The createViewNavFromCategory method in the NotesView class has the following bug:

if the user has no rights to read all documents in the category you specified,
this method does NOT return an empty view navigator but a navigator FOR ALL SUBSEQUENT CATEGORIES IN THE VIEW.


You have a categorized view by company names.
Some documents in this view has a reader field, and you are not authorized to see the documents in the category "ITWU".
The view will look like this:



Now, you write the following Java code:

Database db = DominoUtils.getCurrentDatabase();
View view = db.getView("myview");
ViewNavigator nav = view.createViewNavFromCategory( "ITWU" );

You probably suppose to get an empty view navigator but that's where you are wrong;
the view navigator is for all entries in the categories Microsoft and SAP

This phenomenon does not happen in the getAllEntriesByKey method.


Check the first entry in the view navigator again if you have the correct category.
Attention: if the column is a multi-value field, you have to check it too.

ViewEntry entry = nav.getFirst();
if( entry != null )
    if( !"ITWU".equals( entry.getColumnValues().get(0).toString() ) )
        System.out.println("not found");


Eigentlich sollte es ein Feiertag sein, aber Teamstudio, TLCC und IBM hatten etwas anderes geplant. Es war mal wieder Zeit für das monatliche Webinar. Dieses Mal mit dem schönen Titel: App.Next - The Future of Domino Application Development.

Und es hat sich gelohnt. Schaut mal ab 15:27 was für Pläne es für die NSF gibt. Das Auslagern der View Indexes wäre nun wirklich eine sehr feine Sache. Im Q&A am Ende der Präsentation wird dazu sogar noch erklärt, dass die View Indexes auf einen eigenen Controller Channel könnten. Meine Performance Träume werden vielleicht irgendwann noch wahr. Aber weitere Vorteile liegen auf der Hand: innerhalb der NSF wird Platz frei (erinnert an DAOS), man kann viel mehr Views erstellen, ohne sich Gedanken um die arme NSF machen zu müssen und unnötige View Indexes müssen nicht mehr gesichert werden.

Das weitere Webinar verlief wie erwartet. Es wurden viele Features für XPages vorgestellt. Dabei sollte man sicherlich die Dokumenten-Verschlüsselung innerhalb von XPages hervorheben. Aber natürlich sind Responsive Designs und Relational Data Support und vieles mehr auch nicht langweilig.

Wer gerne etwas weiter in die Zukunft denkt, sollte ab 51:07 Domino on Bluemix schauen. Praktisch wird es ab 1:04:10 mit einer Demonstration von XPages auf Bluemix. Auf jeden Fall Dank an die Präsentatoren des Webinars am Feiertag: Pete Janzen, Martin Donnelly und Brian Gleeson ;)


Problem Description

In this article I will show you how to elegantly link documents in a Notes database with the use of event handlers. At first glance linking documents together seems to be a very trivial task. It is something we all implemented hundreds of times already, either using built-in Notes response hierarchies or through building document trees of our own design. Doing that programmatically while using backend classes is as trivial as it sounds, but letting the user do it interactively is something else entirely. Because then there are certain additional requirements that should be implemented to guarantee a consistent and hassle-free user experience.

So let us take a look at those requirements for the two standard use cases:

1. The user links an already existing document to the currently open document (through a dialog field or a view selection). The title of the linked document should be displayed in a field and the document can be opened through a hotspot.


  • If the user doesn’t save the currently open document the link should be voided i.e. the field should be empty and the hotspot action should not execute.
  • The operation should not access backend classes to avoid replication and safe conflicts.

2. The user creates a new document from an already open document. The new document should be linked to the already opened one and its title should be displayed in a field (and can, after the initial save, opened through a hotspot).


  • If the user doesn’t safe the new document AND the current document the link should be voided i.e. the field should be empty and the hotspot action should not execute, even if the new document has been saved.
  • The operation should not access backend classes to avoid replication and safe conflicts.
  • Every change the user performs on the new document should immediately be reflected in the old document.



During the following demonstration I will call the document that provides the link the parent and the link target the child. I also will not make use of the Parent-Response-Hierarchy but will implement my own hierarchy using document IDs I generate myself programmatically. I am sure you know why that is . Of course you can use a Parent-Response Hierarchy instead and, if you are feeling lucky, you can even use Universal IDs to define the link.


Case 1: Linking to an existing document

The first case is more or less trivial. The child already exists and will not be opened during the linking operation hence we actually can (have to actually) access it using backend classes, specifically an instance of NotesDocument or built-in functions e.g. a dialog list field.
We create a dialog list field on the parent form and populate the choices with a column of a lookup view. The column formula should be something like the following:

doc_title + “|” + doc_id

Now make sure “Allow keyword synonyms” is checked in the field properties and you are done.

If you have to actually use backend classes, for example in conjunction with the NotesUIWorkspace Functions PicklistCollelction or PicklistStrings you can use the NotesUIDocument Function FieldSetText to set the value. And yes you can set computed and even hidden fields that way, too. I normally use a dialog list field even if the field is computed and set with FieldSetText. That way I can set the doc_id and after a NotesUIDocument.Refresh the displayed value is automatically translated to the title. For this to work you of course have to check the option “Refresh choices on document refresh” in the field properties.

The hotspot action performs a lookup in the same view (the first sorted column has obviously to be doc_id) and opens the document.


Case 2: Linking a new document

This case requires a little more work. So let us split the requirements into two steps to make it clearer.

For the purpose of code clarity and management we create persistent backend classes which serve as a wrapper for NotesUIDocument instances. We accomplish that through creating an instance of our wrapper in the PostOpen event and saving the reference in a variable declared in the Globals section of the form. For more details read my previous articles on the subject:

Event Handling mit LotusScript Teil I - Persistente Event-Handler


Step 1: Creating the child

In the backend class for the parent we first declare a private member variable:

Private childUIDoc As NotesUIDocument


And the following sub:

Public Sub actionCreateChild()

   Dim ws As New NotesUIWorkspace()
   Dim db As NotesDatabase
   Dim childDoc As NotesDocument

   Set db = ws.CurrentDatabase.Database
   Set childDoc = db.CreateDocument()

   Call childDoc.ReplaceItemValue( "Form", "childDoc" )
   Call childDoc.ComputeWithForm( False, False )

   Set me.childUIDoc = ws.EditDocument( True, childDoc )

End Sub


That sub will be called by the action which we use to create the child document. In effect our persistent instance of the parent wrapper class now has a handle on the NotesUIDocument instance of the just created child.

Step 2: Handling Child Events in the Parent-Wrapper

Next we want to notify the parent if and when the child gets saved or closed. For that purpose we bind the corresponding events, which are fired by the child NotesUIDocument instance, to event handlers we define in our parent wrapper.

Public Sub actionCreateChild()
    Dim ws As New NotesUIWorkspace()
    Dim db As NotesDatabase
    Dim childDoc As NotesDocument
    Set db = ws.CurrentDatabase.Database
    Set childDoc = db.CreateDocument()
    Call childDoc.ReplaceItemValue( "Form", "childDoc" )
    Call childDoc.ComputeWithForm( False, False )
    Set me.childUIDoc = ws.EditDocument( True, childDoc )

    On Event PostSave From me.childUIDoc Call OnPostSave_Child
    On Event QueryClose From me.childUIDoc Call OnQueryClose_Child

End Sub


All the PostSave event handler has to do is to set the doc_id and refresh the NotesUIDocument instance of the parent document. This way the current title of the document is always displayed.

Public Sub OnPostSave_Child( Source As NotesUIDocument )
    Call me.mUIDoc.FieldSetText( "child_id", _
                                  Source.FieldGetText( "doc_id" ) )
    Call me.mUIDoc.Refresh()
End Sub


In the QueryClose event handler we first check if the child has been saved. Since we created the document using backend classes we need to check the property IsNewNote on the backend document rather than the property IsNewDoc which is provided by the NotesUIDocument instance (and hence will always be false). If the child has been saved we do nothing, everything already has been taken care of by the PostSave event handler. If it has not been saved we reset the link field to the empty string, thus removing the link.

Public Sub OnQueryClose_Child( Source As NotesUIDocument, _
                               Continue As Variant )
    If childUIDoc.Document.IsNewNote Then
          Call me.mUIDoc.FieldSetText( "child_id", "" )
          Call me.mUIDoc.Refresh()
    End If
End Sub


And that is it. If the child doesn’t get saved the link will be empty. If the parent doesn’t get saved the link won’t change at all. If it was empty before the child was created it will obviously stay that way regardless whether or not the child has been saved.


Step 3: Opening the link

To keep the behavior consistent we also have to obtain the child NotesUIDocument instance when the user follows the link. For that we create a new sub for the sole purpose of opening the document.

Public Sub actionOpenChild()

    Dim ws As New NotesUIWorkspace()
    Dim db As NotesDatabase
    Dim view As NotesView
    Dim childDoc As NotesDocument
    Dim childID As String
    childID = me.mUIDoc.Document.GetItemValue( "child_id" )(0)
    If Not childID = ""  Then
          Set db = ws.CurrentDatabase.Database()
          Set    view = db.GetView( "lkpChildDoc" )
          Set childDoc = view.GetDocumentByKey( childID, True )
          If Not childDoc Is Nothing Then
                Set me.childUIDoc = ws.EditDocument( True, childDoc )
          End If
    End If
End Sub


So in theory we are done but what if the child gets opened end edited outside of the parent context? Well if we use the dialog list approach we are still done because when the child gets edited the view entry will change and the link title will be updated the next time you open the parent (into edit mode). But what if you want the parent to reflect changes in the child immediately?
There probably is a reason why you made one document the child and the other the parent and not the other way around. You built your hierarchy to reflect some piece of business logic or maybe even real logic .

In consequence it is highly likely that the user is already editing the parent when he opens the child. Hence updating the parent programmatically through the child without having the parent context invites all kinds of trouble. So don’t! Rather write an agent that runs once a night and performs a ComputeWithForm on all parent documents.



Normally, updating RichTextFields in an opened IBM Notes document requires saving, closing and then reopening the document. If you use the RichTextField to attach a file to the document even after doing all this closing and reopening, it is not guaranteed that the attachment is inserted where you want it to be. Another problem that is implicated with this is the necessity to save documents you do not want to save, yet.

Fortunately, there is an undocumented method in LotusScript that enables us to update RichTextFields on unsaved UIDocuments without the need for saving and reopening them.

It's called

NotesUIDocument.ImportItem( tmpDoc As NotesDocument, RichTextItem As NotesRichTextItem)

and it is part of in the NotesUIDocument class.


Explanation standard method:

The standard method to embed files or document links etc. into RichTextFields is the use of



Example Code:

    Dim ws As New NotesUIWorkspace
    Dim db As NotesDatabase
    Dim doc As NotesDocument
    Dim rtitem As NotesRichTextItem
    Set doc = ws.CurrentDocument.Document
    Set rtitem = New NotesRichTextItem(doc, "RichTextField")
    Call rtitem.EmbedObject( EMBED_ATTACHMENT, "", "C:\Desktop\Document.docx")


Fig. 1: Notes form with buttons for the standard method and our workaround for attaching files in the RichTextField


After using the standard method the problems stated above become obvious. When the document is saved and reopened the file is attached at the end of the document, but not in the RichTextField where it should be.

Fig. 2: Result of the standard method EmbedObject of LotusScript


Explanation workaround:

Now we will use the ImportItem method.


Example Code:

    Dim sess As New NotesSession
    Dim ws As New NotesUIWorkspace
    Dim db As NotesDatabase
    Dim tmpdoc As NotesDocument
    Dim rtItem As NotesRichTextItem
    Dim uiDoc As NotesUIDocument
    'uiDoc contains the RichTextField we want to import our file into             
    Set uiDoc = ws.CurrentDocument
    'Create a support NotesDocument (tmpDoc)       
    Set db = sess.currentDatabase
    Set tmpdoc = db.CreateDocument
    'Create a RichTextItem on the support document to embed the desired file into
    Set rtItem = New NotesRichTextItem(tmpdoc, "RichTextField")
    'embed the desired file into the created RichTextItem
    Call rtItem.EmbedObject( EMBED_ATTACHMENT, "", "C:\Desktop\Document.docx")
    Call rtItem.update
    '!!Using computeWithForm ensures that the attachment is completely embed into the RichTextField before
    'we try to import it into our uiDoc. It works even though we have no form specified!!

    Call tmpdoc.ComputeWithForm(False, False)
    'Put Cursor into the RichTextField --> precondition for the file's import
    Call uiDoc.GoToField("RichTextField")
    'finally import the desired file into the RichTextField on the uiDoc.
    Call uiDoc.ImportItem(tmpDoc, "RichTextField")


Fig. 3: Result of the workaroung method ImportItem


As you can see, right after using the workaround button, the file is attached into the RichTextField of our opened document as desired. No saving and reopening needed!

!Please keep in mind that this workaround method is undocumented an could be removed from LotusScript by IBM!
I hope this workaround helped you as much as it helped me!
If you have any questions or suggestions do not hesitate to contact us.