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”:
http://avatar.red-pill.mobi/tim/blog.nsf/d6plinks/TTRY-7DZ4GX
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));
@SetField(targetField; newTypeValue)
I used a different one though. I forget which.
There’s this:
http://searchdomino.techtarget.com/tip/Edit-data-without-writing-an-agent
And I think i used this last crazy one more… I forget.
http://www.antcer.it/lotus-domino/edit-document-fields-6-0-0-by-chad-schelfhout/
I’d forgotten about that. There are some differences, other than being on a tool bar
On the other hand, mine doesn’t handle multi-value fields (like the other links do) or allow deletion of fields. I thought about having a “modify field” choice, which would provide the current value and let you change it or adding logging, so I know the starting/finishing values, who changed it and when. I may also consider making it a version that runs in XPages, so that someone (with the right security) could do it via the browser.
So, several tools to choose from and all worth sharing.