IBM®
Skip to main content
    Country/region select      Terms of use
 
 
   
     Home      Products      Services & solutions      Support & downloads      My account     

developerWorks  >  Lotus  >  Forums & community  >  Best Practice Makes Perfect

Best Practice Makes Perfect

A collaboration with Domino developers about how to do it and how to get it right in Domino

A recent question in the Notes 6 & 7 forum on dW, got me thinking that I should document the process for attaching a file to a document that's being edited, in cases where the file is produced by LotusScript code.

The challenge is that LotusScript doesn't provide a way to attach a file to a document that's in edit mode (if it existed, it would be a method of the NotesUIDocument class).

There are two ways that you can create a file attachment automatically:

  • NotesRichTextItem.EmbedObject: the problem is that since rich text doesn't update on screen when you update it in the back end, using this method requires that you also engage in some gymnastics to cause the new attachment to appear on screen, as described in the Update rich text tip. This is certainly one way to get the job done, but there are drawbacks to this method also, including that it causes Queryclose, Queryopen, Postopen form events to update and loses the values of any global variables you may be holding in LotusScript.
  • In macro language, @Command([EditInsertFileAttachment]; filename) works, but macro language often isn't powerful enough to come up with the filename automatically; you might have to search on disk for the file, or maybe the file doesn't exist yet and you have to create it , then attach it. For instance, it might be a report in a spreadsheet that you create through OLE automation, then want to attach to the document where you specified the report parameters.
My preferred solution uses the macro @Command in combination with LotusScript. To make this work, you need three pieces of code:
  • The LotusScript agent, which produces the file and records its location in an environment variable, a secret field of the document, a profile field, or anywhere else that macro language can get the information.
  • A macro language agent, which looks for the filepath and, if one has been supplied, uses it to create the attachment.
  • A two-line formula to call the two agents.
So for instance, the LotusScript agent would be:

   Dim wksp As New NotesUIWorkspace
   Dim uidoc As NotesUIDocument
   Set uidoc = wksp.CurrentDocument
Dim strFilepath$
' at this point, create your file and store the path in strFilepath (or exit early to abort creating the attachment).
   uidoc.Document.ReplaceItemValue "PathToAttach", strFilepath
End Sub

Of course I have left out the complicated part, creating the file, because there are so many different ways you might do this.The formula agent is:


@If(PathToAttach != "";
   @Do(
      @Command([EditBottom]); { or EditGotoField, or whatever you need to do to position the insertion point if it's not already where you wanted it.};
      @Command([EditInsertFileAttachment]; PathToAttach; "1");
      FIELD PathToAttach := @Unavailable
   );
   ""
)

And the code to call them (which might be in an action button) is:

@Command([ToolsRunMacro]; "(ImportFile)")


I've experimented around with this a little, and I've found that you really have to do it just this way. There are a couple of things you might think to try that don't work, so I'll save you time and list them.
  • Having the first agent call the second agent directly, fails with the message, "Notes error: @Function is not valid in this context". The agent called by "Run" method is not supposed to interact with the user, and all @Commands are presumed to have UI interaction so they are prohibited when the agent is called with Run.
  • Having the first agent use NotesUIDocument methods to position the insertion point, makes the EditInsertFileAttachment command fail without an error message. Apparently, if you touch the rich text in any way with NotesUIDocument, it's left in an "pending" state until all code stops running, at which point the pending updates to rich text content and cursor are displayed. Putting up a dialog to the user will also finish up the rich text changes and let the attach operation proceed, but of course opening a dialog is what we usually wanted to avoid by doing all this! Just let the macro code position the cursor.
  • Don't forget to erase the filepath from wherever it's stored after the attachment is created, so that if the first agent fails (and fails to erase the value), the second agent doesn't attempt to attach a file anyway. Also, of course, there's usually no need to store this filepath in the document, so save space and increase performance by removing it.
  • You might think to check PathToAttach in the agent-calling macro and just don't call the second agent if there's no file to attach. The problem is that this formula has cached the field values that were current at the time the agent started running -- it doesn't see the change that the first agent makes to the PathToAttach field. This might work if you used an environment variable, but I tend to think a form field is neater, less code, etcetera, even though it does mean that you sometimes call the second agent unnecessarily.
  • The PathToAttach field shouldn't appear on the form. This works without doing that, and why make your form more complex unnecessarily? With the field not on the form, the second agent can delete it (@Unavailable) without it coming back when you save (available, but value is "")

Andre Guirard | 9 November 2007 03:04:03 PM ET | Plymouth, MN, USA | Comments (13)


 Comments

1) 2-Line Action Button?
Julian Robichaux | 11/10/2007 7:44:38 AM

Just to clarify, the code for the action button is really two lines, right? Something like:

@Command([ToolsRunMacro]; "(LotusScriptImportFile)");

@Command([ToolsRunMacro]; "(FormulaImportFile)")

Or can there be a single "(ImportFile)" agent that calls them both?

2) re: 2-Line Action Button?
Andre Guirard | 11/11/2007 8:55:20 PM

I intended that the action button would have the two lines in it as you suggest.

There [i]could[/i] be a macro agent that contains the two lines instead, so that your action button could be just one line to call this third agent. I assume that would work, though I didn't try it.

However, I think the benefit of the extra modularity isn't worth the disadvantage of greater complexity of code -- one more layer of agent calls. Especially since I think it would be unusual that multiple forms could use the same LotusScript agent to generate or locate their file, so you would probably need a different third agent for each import in your application.

3) Some Solution
Timothy Briley | 11/12/2007 2:42:33 PM

At the end of the day, this is still a hack. Isn't an update to either the formula language and/or LotusScript to handle this overdue?

4) Could be better...
Andre Guirard | 11/13/2007 8:44:54 AM

I agree this would be nice to have built-in and probably not hard to do. I have requested it as a feature; it's not up to me to decide. As always, there are competing priorities for our developers' time.

5) Attaching a file in the front-end from LotusScript
Jaime Bisgrove | 3/24/2008 10:49:50 AM

Andre -

I must be missing something. I am trying to attach a file in the UI to the document (like the web's fileupload control), not a rich-text field. Is this possible? My problem stems from my need to have the Notes Client and the web behave in the same manner. On the web, the file upload control attaches a file to the document (somehow) and in the Notes Client I am only able to attach a file to a rich-text item. Is there a method I am missing here?

Cheers.

6) Attaching a file in the front-end from LotusScript
Andre Guirard | 3/24/2008 4:41:18 PM

No, but if you have a rich-text field on your form, the file upload control should attach the file to that field when submitted in the web browser client.

7) Attaching a file in the front-end from LotusScript
Jaime Bisgrove | 3/25/2008 10:25:50 AM

Andre,

I currently do not, only a FileUpload control in the web browser client. Perhaps that is the answer.

Cheers

8) Falls just a bit short...
Sasa Brkic | 11/12/2009 1:30:16 PM

Andre,

This is really useful and I have used it already.

I just wish that @Command [EditInsertFileAttachment] could handle hidden fields.

Why would I want this? Well, I tend to hide fields containing files and then use an action to launch the file. I find this visually more appealing and I think it is a good idea to hide from end users a specialized field (that needs to be editable).

I guess one could temporarily show the field (use PathToAttach in Hide When formula?), but that would further complicate things and require RefreshHideFormulas.

9) Doesn’t this apply to 8.5.1 or ....
Thomas C Lyngesen | 3/31/2010 9:51:17 AM

When using your example on a new document, I get the error "file has not been saved yet" - I am trying to attach a file to the current uidoc body field ( a 8.5.1 Calendar Entry document(meeting))

10) correction ...
Thomas C Lyngesen | 3/31/2010 10:02:51 AM

... it is of course "document has not been saved yet" I am getting as the error message.....

11) and what about the other way? - removing an attachment in the front end?
Patrick Kwinten | 4/27/2010 2:29:56 PM

how to remove an attachment in the front-end using LS ?

12) Doesn’t this apply to 8.5.1 or ....
Tom Manning | 11/9/2010 10:40:41 PM

I'm sure you have figured this out by now, but...

In the basics tab of the agent properties, Target should be none.

13) Without agents you can use javascript + lotusscript + formula language
Shanmuga Subramanian Vellagal Arunachalam | 2/26/2014 5:07:25 AM

Hi,

Thanks a lot Andre Guirard! You opened a new idea for me!!!

You need 3 buttons namely "Attach Files" (Visible to user), "GetFileNames" (Hidden to user) and "AttachFiles" (Hidden to user). In "Attach Files" button set that as Client -> JavaScript and enter "GetFileNames.click()" in "GetFileNames" should be Client -> LotusScript with the following code to add multiple files:

Sub Click(Source As Button)

Dim ws As New NotesUIWorkspace

Dim filenames As Variant

Dim doc As NotesDocument

Dim fileNamesHolder As String

filenames = ws.OpenFileDialog(True, "Select files to be attached")

If Not(Isempty(filenames)) Then

Set doc = ws.CurrentDocument.Document

Forall filename In filenames

fileNamesHolder = fileNamesHolder + "|" + filename

End Forall

doc.ReplaceItemValue "fileNamesHolder", fileNamesHolder

End If

End Sub

and for "AttachFiles" button it should be Client -> Formula with the following code:

@If(@IsAvailable(fileNamesHolder); ""; @Return(""));

fileNamesArray := @Explode(fileNamesHolder; "|");

NoOfFiles := @Elements(fileNamesArray) + 1;

@Command([EditGotoField];"Attachments");

@For(i := 0; i < NoOfFiles; i := i + 1; @Command([EditInsertFileAttachment]; fileNamesArray; "1"; "1"));

FIELD fileNamesHolder := @Unavailable;

 Add a Comment
Subject:
   
Name:
Comment:  (No HTML - Links will be converted if prefixed http://)
 
Remember Me?     Cancel

Search this blog 

Disclaimer 

    About IBM Privacy Contact