Autor(en): | Mathias (TMC) |
Stand: | 22.09.2005 |
Version: | 1.3 |
Notes-Versionen: | 5.x, 6.x, 7.x |
Änderungen: | Version Datum Geändert von Grund 1.3 22.03.2007 Axel Fehlerbereinigung in Code unter Punkt 3.9 |
Inhalt1. Begriffe2. Grundsätzliches3. Praxis 3.1 Antwortdokument erstellen per Button
3.2 Feldinhalte vom Hauptdokument im Antwortdokument anzeigen
3.3 Feldwerte beim Anlegen eines Antwortdokuments vom Hauptdokument übernehmen
3.4 Felder in allen Antwortdokumenten aktualisieren, sobald sich diese im Hauptdokument ändern
3.5 Dokumentlink zum Hauptdokument im Antwortdokument anzeigen lassen
3.6 Einem Antwort-Dokument ein anderes Hauptdokument zuweisen (1)
3.7 Einem Antwort-Dokument ein anderes Hauptdokument zuweisen per Button
3.8 Eine einzige Maske für Haupt- und Antwort-Dokumente
3.9 Löschen von Haupt- und Antwort-Dokumenten
4. Anregungen, Ergänzungen, Verbesserungsvorschläge1. BegriffeHauptdokument auch: Elterndokument, Mutterdokument, Parent document, Main document
Antwortdokument auch: Tochterdokument, Unterdokument, Response document
2. GrundsätzlichesSobald zu ein Hauptdokument per Formelsprache oder Lotus Script ein Antwortdokument erstellt wird, legt Lotus Notes nach dem ersten Speichern ein Feld
$REF mit dem
Datentyp „Response“ an. In dieses Feld wird beim Anlegen die ID des Hauptdokumentes geschrieben.
Hinweis: Das $REF – Feld ist erst nach dem ersten Speichern vorhanden.
Die Maske, die für Antwortdokumente verwendet werden soll, muss als solche ausgewiesen werden, in dem man den Typ auf "Response" stellt.
3. Praxis3.1 Antwortdokument erstellen per ButtonMan kann folgende Formel verwenden, die sowohl für eine Aktionsschaltfläche in einer Ansicht als auch in Masken geeignet ist.
Diese Formel ist geeignet, wenn es nur 1 Hierarchie von Antwortdokumenten geben soll.
@If(Form = "";
@Return(@Prompt( [OK];@DbTitle; "Bitte wählen Sie ein Hauptdokument aus" + @Char(13) + "um ein Antwortdokument zu erstellen."));
@Success
);
@If(@IsResponseDoc;
@Prompt( [OK];@DbTitle; "Bitte wählen Sie ein Hauptdokument aus" + @Char(13) + "um ein Antwortdokument zu erstellen.");
@Command([Compose]; "RESPONSE MASKE")
)
Wenn mehrere Hierarchien möglich sein sollen, kann man folgende Formel verwenden:
@If(Form = "";
@Return(@Prompt( [OK];@DbTitle; "Bitte wählen Sie ein Hauptdokument aus" + @Char(13) + "um ein Antwortdokument zu erstellen."));
@Success
);
@Command([Compose]; "RESPONSE MASKE")
3.2 Feldinhalte vom Hauptdokument im Antwortdokument anzeigenDazu erstellt man im Antwortdokument ein berechnetes Textfeld und setzt in die Feldformel folgende @Formel:
@If(@IsNewDoc;"";@GetDocField($REF;"FELD"))
3.3 Feldwerte beim Anlegen eines Antwortdokuments vom Hauptdokument übernehmenDazu setzt man in den Maskeneigenschaften der Antwortmaske folgenden Schalter:
In den Feldformeln der Antwortmaske, in die Werte vom Hauptdokument übernommen werden sollen, schreibt man den entsprechenden Feldnamen des Hauptdokuments
Im Beispiel ist „Parentdoc_Test“ der Feldname des Hauptdokumentes.
3.4 Felder in allen Antwortdokumenten aktualisieren, sobald sich diese im Hauptdokument ändernWenn Änderungen im Hauptdokument auf alle Antwortdokumente übertragen werden sollen, kann man dies über den Query Save – Event in der Hauptdokument-Maske steuern.
Hilfreich sind hierbei „
Responses property“ und „
StampAll method“ in der „NotesDocumentCollection“.
Beispiel:
Sub Querysave(Source As Notesuidocument, Continue As Variant)
'------------------------------------------------------------------------------------------------------------------
'Zweck: Feldwerte werden beim Speichern in alle Antwort-Dokumente übernommen
'------------------------------------------------------------------------------------------------------------------
Dim session As New NotesSession
Dim db As NotesDatabase
Dim dc As NotesDocumentCollection
Dim doc As NotesDocument
Set db = session.CurrentDatabase
If Source.IsNewDoc Then Exit Sub 'Wenn UIDoc neu ist dann verlasse Script
Set doc = Source.Document 'UIDoc zu Backend-doc
'alle Antwortdocs des Backend-Docs werden in die Collection aufgenommen
Set dc = doc.Responses
'Setze alle Felder der Collection, gespeichert wird automatisch
Call dc.StampAll( "Re_Feld1" , doc.Feld1(0) )
Call dc.StampAll( "Re_Feld2" , doc.Feld2(0) )
Call dc.StampAll( "Re_Feld3" , doc.Feld3(0) )
End Sub
Dieses Script kann man - etwas angepasst - auch in einem Agenten verwenden, der beispielsweise täglich alle Antwortdokumente aktualisiert.
3.5 Dokumentlink zum Hauptdokument im Antwortdokument anzeigen lassenUm ein Dokumentlink-Symbol im Antwortdokument erscheinen zu lassen, welches auf das Hauptdokument verweist, erstellt man ein berechnetes Textfeld. In die Feldformel schreibt man
$REF.
3.6 Einem Antwort-Dokument ein anderes Hauptdokument zuweisen (1)Prinzipiell ist dies z.B. mit folgendem Script möglich:
Dim docParent As NotesDocument
Set docParent = db.getDocumentByUNID("UNID-String")
Call doc.RemoveItem("$Ref")
Call doc.MakeResponse( docParent )
3.7 Einem Antwort-Dokument ein anderes Hauptdokument zuweisen per ButtonAngenommen, man möchte es dem User per Aktionsbutton ermöglichen, dem aktuell geöffneten Antwortdokument ein neues Hauptdokument zuzuordnen, kann man wie folgt vorgehen:
Als erstes erstellt man eine Ansicht, die nur die Hauptdokumente enthält. Beispielsweise trägt man dazu in die View Selection
SELECT FORM = "MyParentForm“ oder etwa
SELECT $REF = "" ein.
Im Beispiel nenne ich die View
($Lookup_AssigningOtherParent).
In der View erstellt man mehrere Spalten, z.B.
Dabei lässt man in der letzten Spalte die DocumentUniqueID anzeigen. Hier im Beispiel soll beim Ändern des Hauptdokumentes auch der Titel übernommen werden, daher steht in der 3. Spalte:
SubjectParent + "~" + @Text(@DocumentUniqueID)
Diese 3. Spalte sollte man verbergen. Das "~" ist ein Trennzeichen (Delimiter), es empfiehlt sich ggf., ein längeres String zu verwenden, z.B. "#'~+*'#".
Nun erstellt man in der Antwortmaske einen neuen Button und fügt folgendes Script ein:
Sub Click(Source As Button)
Const ITEMNAME_TITLE_OF_PARENT$ = "SubjectParent"
Const VIEWNAME_LOOKUP_PARENT$ = "($Lookup_AssigningOtherParent)"
Const DELIMITER_TITLE_UNID$ = "~"
Const COLUMN_NO_LOOKUP$ = "3" 'which column contains the subject + delimiter + UNID ?
Const MSGPICKLIST_TITLE$ = "Document selection"
Const MSGPICKLIST_TEXT$ = "Please select a main document to which you want to assign this response document:"
Const ERRMSG_1001$ = "Current document is not a response."
Const ERRMSG_1002$ = "Current document is not in edit mode."
Const ERRMSG_LINE2$ = "Operation has been canceled."
On Error Goto ErrorHandler
Dim session As New NotesSession
Dim uiws As New NotesUIWorkspace
Dim uidoc As NotesUIDocument
Dim db As NotesDatabase
Dim docCur As NotesDocument
Dim docParent As NotesDocument
Dim vPicklistReturn As Variant
Dim strLeftValue As String
Dim strRightValue As String
Dim i As Integer
Set db = session.CurrentDatabase
Set uidoc = uiws.CurrentDocument
Set docCur = uidoc.Document
'Only continue if the current document is a response & if it is in the edit mode
If Not docCur.IsResponse Then Error 1001, ERRMSG_1001
If Not uidoc.EditMode Then Error 1002, ERRMSG_1002
'Display the main documents and let the user select one
vPicklistReturn =uiws.Pickliststrings(PICKLIST_CUSTOM, False, db.Server, db.FilePath,VIEWNAME_LOOKUP_PARENT,_
MSGPICKLIST_TITLE, MSGPICKLIST_TEXT, COLUMN_NO_LOOKUP)
If Isempty(vPicklistReturn) Then Goto GoOut 'user did not select a document
'Get left and right value
strLeftValue = Strleft(vPicklistReturn(0), DELIMITER_TITLE_UNID)
strRightValue = Strright(vPicklistReturn(0), DELIMITER_TITLE_UNID)
'Set subject of main document to an item of the current response document
Call docCur.ReplaceItemValue(ITEMNAME_TITLE_OF_PARENT, strLeftValue)
'Assign the new main document to the current response doczment
Set docParent = db.getDocumentByUNID(strRightValue)
Call docCur.RemoveItem("$Ref")
Call docCur.MakeResponse( docParent )
'Refresh
Call uidoc.Reload
Call uidoc.Refresh
GoOut:
Exit Sub
ErrorHandler:
Select Case Err
Case 1001 To 1999: 'User defined errors
Msgbox Error$ & Chr(10) & Chr(10) & ERRMSG_LINE2, 64, db.Title
Resume GoOut
Case Else:
ErrorMsg ' Your error sub. See this AtNotes thread for further information: http://www.atnotes.de/index.php?topic=11980.0
Resume GoOut
End Select
End Sub
Als Ergebnis sieht der Anwender folgendes Fenster, wenn er auf den Button klickt:
Nach Auswahl und Bestätigung mit "OK" wird dem Antwortdokument das neu ausgewählte Hauptdokument zugeordnet.
3.8 Eine einzige Maske für Haupt- und Antwort-DokumenteGrundsätzlich wird von Notes vorausgesetzt, dass es separate Masken für Haupt- und Antwort-Dokumente gibt. Dabei ist in der Antwortmaske unter
Type "Response" oder "Response to Response" zu setzen (siehe
-> Kap. 2. Grundsätzliches).
Es gibt aber die Möglichkeit, Haupt- und Antwortdokumente auf Basis einer einzigen Maske zu erstellen. Dies kann von Vorteil sein, z.B. wenn sich die Haupt- und Antwortmaske kaum unterscheiden und man mit Hide/When-Formeln (siehe auch:
AtNotes BP: Verbergen-Wenn (Hide-When) - Formeln) die jeweils zu verbergenden Absätze definiert.
Bedingungen:- Neue Antwort-Dokumente können nicht per Formelsprache erstellt werden, sondern nur per LotusScript, da hierzu die MakeResponse - Methode der NotesDocument-Klasse notwendig ist.
- Zusätzlich ist es bei der Erstellung notwendig, die Versionskontrolle zu aktivieren (Item $VersionOpt setzen), sonst funktioniert die MakeResponse - Methode der NotesDocument-Klasse nicht bei neuen Dokumenten, wenn man diese im Backend erzeugt und dann im Frontend anzeigen lässt (um den Compose - @Command nachzubilden). Details zur Versionskontrolle und $VersionOpt: siehe Designerhilfe.
Beispiel für das Erstellen eines neuen Antwort-Dokumentes per Lotus Script:Das folgende Script ist für einen Button gedacht und kann in Ansichts- und Masken-Buttons eingesetzt werden. Falls das Script mehrfach verwendet wird, sollte man dieses in einem Agenten, einer 'Shared Action' oder in einer ScriptLibrary hinterlegen.
Das neu erstellte Dokument wird dabei nicht gespeichert (NotesUIDocument.IsNewDoc gibt
True zurück), d.h. das Verhalten ist prinzipiell wie beim Compose - @Command.
Sub Click(Source As Button)
'Constants for this procedure
Const FORMNAME_RESPONSE$ = "frmTest"
Const ERR_NODOCSEL_TITLE$ = "Error: No document selected"
Const ERR_NODOCSEL_MSG$ = "You need to select a document to create a response document of it."
On Error Goto ErrorHandler 'Of course we trap errors
'The dim section
Dim uiws As New NotesUIWorkspace
Dim uidocNew As NotesUIDocument
Dim session As New NotesSession
Dim db As NotesDatabase
Dim docSel As NotesDocument
Dim docNew As NotesDocument
'We need the current database
Set db = session.CurrentDatabase
'Get current document as NotesDocument object
If Not uiws.CurrentDocument Is Nothing Then
Set docSel = uiws.CurrentDocument.Document 'Document opened in form
Elseif Not session.DocumentContext Is Nothing Then
Set docSel = session.DocumentContext 'Document selected in view
End If
If docSel Is Nothing Then 'User did not select a document
Msgbox ERR_NODOCSEL_MSG, 48, ERR_NODOCSEL_TITLE
Goto GoOut
End If
'Create new backend response document
Set docNew = db.CreateDocument
Call docNew.ReplaceItemValue("Form", FORMNAME_RESPONSE)
Call docNew.MakeResponse(docSel)
'This is necessary since we use one form for both main and response documents
Call docNew.ReplaceItemValue("$VersionOpt","1")
'Finally, open new document in the frontend
Call uiws.EditDocument(True, docNew)
GoOut:
Exit Sub
ErrorHandler:
ErrorMsg ' Your error sub. See this AtNotes thread for further information: http://www.atnotes.de/index.php?topic=11980.0
Resume GoOut
End Sub
3.9 Löschen von Haupt- und Antwort-DokumentenGrundsätzlich werden beim Löschen von Hauptdokumenten die Antwort-Dokumente nicht mitgelöscht. Damit auch die Antwortdokumente gelöscht werden, kann man folgendes Lotus Script einsetzen. Es werden dabei rekursiv alle Antwortdokumente abgearbeitet und gelöscht.
1. Im PostDocumentDelete - Event des Database-Scriptes folgenden Code einsetzen:
Dim doc As NotesDocument
Dim collection As NotesDocumentCollection
Set collection = Source.Documents
If collection.Count > 0 Then
For i = 1 To collection.Count
Set doc = collection.GetNthDocument(i)
Call DeleteResponseDocs(doc)
Call doc.Remove(True)
Next 'For i = 1 To collection.Count
End If 'If collection.Count = 0 Then
2. Folgende (rekursive) Sub hinzufügen:
Sub DeleteResponseDocs (doc As NotesDocument)
'This is a recursive sub to access all the descendants of a particular document.
Dim collResponses As NotesDocumentCollection
Dim docTemp As NotesDocument
Dim docDummy As NotesDocument
Set collResponses = doc.Responses
Set docDummy= collResponses.GetFirstDocument
While Not (docDummy Is Nothing)
Set docTemp = collResponses.GetNextDocument(docDummy)
Call DeleteResponseDocs(docDummy) 'The recursive call
Call docDummy.Remove(True)
Set docDummy = docTemp
Wend 'While Not (docDummy Is Nothing)
End Sub
4. Anregungen, Ergänzungen, VerbesserungsvorschlägeAnregungen, Ergänzungen und Verbesserungsvorschläge bitte im Best Practices Diskussionsforum posten.
Insbesonders wären weitere Fragestellungen interessant, die immer wieder vorkommen und auch hier beschrieben werden sollten.