With our transition to XPages, I’ve been finding more and more often that I don’t have a form interface in the Notes client to just change one field value on the back end. Too often, on the front end, in XPages, there’s a value I simply haven’t exposed for editing or don’t even display. I often don’t add the fields to the back end Notes form because it really doesn’t add much value. So, when I want to change one field, or change one field on multiple documents, I do it with an agent. Heck, over the years, we all have. We just usually did it in a very static manner – writing a quick @formula to change the value of a specific field. That requires changing the design to create the agent and then delete the agent – or leaving a mess behind that slowly grows your agent list with more and more single-use agents.
So, I wrote an agent that allowed me to replace a text field by naming the field and the value. Then, I found I wanted one for numbers as well. So, for a few weeks, I had two agents. Then, I realized the folly and wrote an agent that detects the field being updated (or asking you if the field doesn’t exist). I only did it for text, numbers and dates, so I imagine it could be extended. It’s enough for me. Since I had occasion to share it this week with another developer, I thought I’d also post it here to share via the blogosphere.
While there’s nothing brilliant about it, it sure is useful.
%REM Agent Change Field Value Created Jun 19, 2015 by David Navarre/DAI Description: This Agent allows the user to name a field and change the value It checks the field type on the first document selected and handles strings, numbers and dates differently %END REM Option Public Option Declare Use "Utilities" Dim ws As NotesUIWorkspace Dim newDate As NotesDateTime Dim newvalue As Variant Dim fieldname As Variant Dim change As String Sub Initialize Dim session As New NotesSession ' thisdb declared in Utilities ' Dim ndc As NotesDocumentCollection Dim itemdoc As NotesDocument Dim itemToChange As NotesItem Dim numericValue As Double Dim itemType As Long Dim selectedType (2) As String Dim choice As Variant Dim reason As String On Error GoTo errorhandler Set ws = New NotesUIWorkspace Set thisdb = session.CurrentDatabase selectedType (0) = "Date" selectedType (1) = "Text" selectedType (2) = "Numbers" Call StartAgentLogging (session ) fieldname = ws.Prompt ( PROMPT_OKCANCELEDIT, "Field Name", "Enter the name of the field to change" ) If IsEmpty ( fieldname ) Then Exit Sub End If newvalue = ws.Prompt ( PROMPT_OKCANCELEDIT, fieldname, "Enter the new value for " & fieldname ) If IsEmpty ( newvalue ) Then Exit Sub End If ' get the collection before issuing the confirmation, so we can determine field type ' ' from the first document selected, assuming it is the same on the rest ' Set ndc = thisdb.UnprocessedDocuments Set itemdoc = ndc.GetFirstDocument Call agentLog.LogAction ( "Items: " & ndc.Count ) If ( itemdoc.Hasitem(fieldname) ) Then Set itemToChange = itemdoc.Getfirstitem(fieldname) itemType = itemToChange.Type Else choice = ws.Prompt(PROMPT_OKCANCELLIST, "Select field type", "Field " & fieldname & " does not exist on the first document. Select field type to create", "Text", selectedType ) If IsEmpty ( choice ) Then MessageBox "Action cancelled" Exit Sub End If Select Case choice Case "Date" itemType = 1024 Case "Text" itemType = 1280 Case "Number" itemType = 768 End Select End If If Confirm ( itemType ) Then While Not itemdoc Is Nothing Select Case itemType Case 1024 ' DATETIMES ' Call itemdoc.ReplaceItemValue ( fieldname, newDate ) Case 1280 ' TEXT ' Call itemdoc.ReplaceItemValue ( fieldname, newValue ) Case 768 ' NUMBERS ' ' if the value supplied is an integer, save it that way ' If ( CInt ( CDbl ( newValue ) ) = CInt ( newValue ) ) Then Call itemdoc.ReplaceItemValue ( fieldname, CInt ( newValue ) ) else Call itemdoc.ReplaceItemValue ( fieldname, CDbl ( newValue ) ) End If End Select Call agentLog.LogAction ( change ) Call itemdoc.Save ( True, False ) Set itemdoc = ndc.GetNextDocument ( itemdoc ) Wend MessageBox change & Chr$(10) & "Successful on " & ndc.Count & " documents" End If exiting: Call agentLog.LogAction ( "-------" ) Call agentLog.LogAction ( "-------" ) Exit Sub errorhandler:' report all errors in a messagebox ' reason = "Error #" & CStr (Err) & " (" & Error & ") on line " & CStr (Erl) MessageBox reason, 16, "Error" Call agentLog.LogAction ( reason ) Resume exiting End Sub %REM Function ConfirmValue Description: This function displays a confirmation dialog based on the field type %END REM Function Confirm ( itemType As Long ) As Boolean Select Case itemType Case 1024 ' DATETIMES ' Set newDate = New NotesDateTime ( newValue ) change = "Change date in " & fieldname & " to " & newDate.Dateonly Case 1280 ' TEXT ' change = "Change text in " & fieldname & " to " & newValue Case 768 ' NUMBERS ' change = "Change number in " & fieldname & " to " & newValue Case 1 ' RICHTEXT ' Confirm = False MessageBox "Cannot change rich text using this agent" Exit Function Case Else Confirm = False MessageBox "Cannot change " & fieldname & " using this agent" & Chr$(10) & "Field type: " & itemType Exit Function End Select Confirm = ws.Prompt ( PROMPT_YESNO, "Confirmation", change & "?" ) End Function
Oh, and the relevant snippet of the Utilities script library….
%REM Library Utilities Created Mar 29, 2012 by David Navarre/DAI Description: Some database utilities %END REM Option Public Option Declare Dim thisdb As NotesDatabase Dim agentLog As NotesLog Sub Initialize End Sub Sub StartAgentLogging ( session As NotesSession ) ' this module starts agent logging ' ' 29 Mar 12, David Navarre ' Dim title As String Dim agent As NotesAgent Set agentLog = session.CreateLog ("Agent log") Set agent = session.Currentagent Call agentLog.OpenAgentLog Call agentLog.LogAction ( "Log Open" ) End Sub
If I’m understanding you correctly there’s been a bunch of solutions to this. You’re doing the agent thing which is cool. But there’s been a couple formula based solutions which are more handy because you can put them in an icon on a tool bar and not need to add an agent to each database.
Tim Tripcony had what he called a “Magic Button”:
targetField := @Prompt([OkCancelEditCombo]; “Select Field”; “Select a field to override:”; “”; @DocFields );
updateTypes := “Text”:”Number”:”Time”:”Delete Field”;
updateType := @Prompt([OkCancelList]; “Select Type”; “Choose a type or action:”; “Text”; updateTypes );
@If(updateType = “Delete Field”; @Return(@SetField(targetField;@DeleteField)); “” );
newValue := @Prompt([OkCancelEdit];”New Value”;”Enter the new value:”; @Text(@GetField(targetField )));
newTypeValue := @Select(@TextToNumber(@Replace(updateType; @Subset(updateTypes;3);”1″:”2″:”3″ )); newValue; @TextToNumber(newValue); @TextToTime(newValue));
I used a different one though. I forget which.
And I think i used this last crazy one more… I forget.