Thursday, January 20, 2011

Configurable Embedded Views (Single Category Views in External Notes Databases)

Have you ever had Notes application A that had related data in Notes application B where you wanted to show the application B data when you opened a document in application A? I have, and I found there are lots of ways to combine data like this. If it were all in one database, it would be pretty trivial to create an embedded view and show the single category that relates to the open document. It gets complicated when you want to leave the data in its source database rather than copying it to where you want it, and feels almost impossible if you then introduce multiple environments (eg. development, QA and production).

Composite Applications, introduced in Notes 8, were one way to accomplish this, but they never really caught on, due in part to their own deployment issues. XPages is the latest silver bullet that can be used to slay this beast. But what if you don’t have Notes 8.5.1 and aren’t going to move to it in the near future? Or you don’t have the time to focus on learning XPages right now?

There is a way to make these related applications work in a configurable way in the Notes 6 and 7 client. This is not original thinking. See Nathan Freeman’s blog (ntf.gbs.com) for the Sesame Street and Area 51 demos for the earlier documentation. I just thought it was worth bringing up again.

The entire solution is based on three features of Domino Designer and Notes that haven’t gotten a lot of attention: computable frameset contents, embedded editors and forms that open in framesets. Nathan’s Sesame Street demo showed how you could embed a fully functional frameset on a form. That was great, unless you only wanted a single category of a view. That problem was solved in the Area 51 demo.

For this demo, I have an application catalog. Not *the* application catalog that each Domino server has, but one that adds on to that catalog to add a description, an application owner and technical support staff. Rather than copying everything from the system catalog, we’ll reference the catalog from within our application. I’ll refer to the application catalog as the “source” database and the system catalog as the “target” database. The source database documents will contain the replica ID of the application database that will be our lookup key for the target database.


    Target Database
    1. Create a form in the system catalog with an embedded view on it, with the view being one categorized by replica ID. You can create a view specific to your needs or use one that is already in the system catalog.

    2. Set the form so that it does not appear on the Create menu.

    3. On the embedded view, the Show Single Category property should be set to @Word(@Environment(“Catalog_Ref”);”~” ;4). The environment variable will be set by the source application and will be explained in the next section.

    4. Save the form with the name OneReplica.

    This must be created in the target database so that you can choose the “Current Database” option as the source of the embedded view. Because there is not a way to programmatically select the source of an embedded view, this ensures the proper view will always open, whether you are looking at your Dev, QA or Production system catalog.

    Source Database
    This database should already have a form in it for the application items that you want in addition to what is in the system catalog. To make this work, you need a field on the form for the replica ID of the application, and the value should be in the formula format (12345678:87654321), unless you created a new view in the target database that reformats the replica ID. You should also have a view that lists the application documents.

    There are two elements that need to be added in the source database and one change to the application form you already have. The new elements are a frameset that will display the form from the target database, and a wrapper form that is set to display in a frame of the new frameset. On the application form, you need to add an embedded editor that will display the wrapper form.

    1. Create a frameset with three frames: two side-by-side on top and one full width on the bottom. Set the top frames to a relative height of 1 and 50% width. The borders should be set to not be 3D and 2 pixels in width.

    2. Name the top left frame NotesView and set its target to NotesDocView. Set the Content Type to Named Element and click the ‘@’ icon to enter formulas to determine the element. The kind of element should have the formula @Word(@Environment(“Catalog_Ref”);”~” ;2), the database should be the formula @Word(@Environment(“Catalog_Ref”);”~” ;1) and the element name should be the formula @Word(@Environment(“Catalog_Ref”);”~” ;3). The kind and name of the element could actually be constants, but it is a better practice to compute them in case they need to change later or you want to use this frameset for more than one purpose.


      3. Name the top right frame NotesDocView.

      4. Name the bottom frame InvisibleMan. The height of InvisibleMan should be 0 pixels, Scrolling should be Off and Allow Resizing should be No. We don’t want to see this frame; it is used only as the target for the form we want to open in a frameset.

      5. Save the frameset as CatalogView.

      6. Create a form. It should be set so that it does not appear on the Create menu. On the Launch properties, set it to open in the CatalogView frameset in the InvisibleMan frame. The only purpose of this form is to open in a frameset so the frameset can appear to be embedded on another form. This form could also set the environment variable, but we are not doing so in this example.


      7. Save the form with the name Wrapper.

      8. In the application documentation form (assumed to have been created previously), add an embedded editor that opens the Wrapper form. In the PostOpen of this form, you need code to set the Catalog_Ref environment variable. The variable should be in the format server!!filepath~Form~OneReplica~replicaID. The server could be computed based on the location of the source application and the filepath is probably constant across the environments, so you could probably enter it directly (remember to escape any ‘\’ in the path). The element type and name will be constant and the replica ID is the name of the field containing the replica ID. More likely, the server and filepath for the catalog would be read from a configuration document. Just keep in mind that the location of the target database (that is, both the server and file path) should not be hard coded, because that defeats the purpose of this solution: to make it possible to migrate from your dev to production environment without making programming changes as the moves are completed.

      9. Save the updated form.

      Once everything is saved, go to your source database and open or create a document using the application documentation form. If all goes well, you should see an embedded view that contains the documents from the system catalog for the replica ID of the database you are looking at, and a box to the right that should display the document you click in the view. See, a real embedded frameset!


      If you want to prove that it is configurable via the environment variable, set the environment variable to @Implode(@MailDbName;"!!")+"~Folder~($Inbox)" and see that it opens your mail box.

      Once you wrap your head around how this works, the possibilities become nearly endless. Multi-database applications can become far more informative.

      Update: Here is a link to a complete "Source" database that also includes the form that needs to be copied into the "Target" database. Hope that helps flesh out the example a little more.


      Technorati:

      18 comments:

      Kevin Pettitt said...

      Nice one Don! I was familiar with Nathan's earlier work so I'm very happy to see it put to such clever use. Funnily enough I actually have written a few apps that *do* copy over all the catalog data so this example is particularly relevant.

      Thanks for taking the time to do the write up!

      John said...

      is it possible and if so, difficult, to configure it so that when you click on the document an associated view appears on the right, say a history of activities associated with the selected document?

      Nathan T. Freeman said...

      Wow! Excellent and thorough write-up Don. My head is spinning remembering how to do that stuff! :-)

      Thanks for the nod, and I'm glad to see the whole pattern is working for you.

      Don McNally said...

      @Kevin - Thanks a lot! I was hoping that the demo might prove useful in the real world.

      @Nathan - That'll be the day, that anything *I* write makes *your* head spin. ;) I'm looking forward to you spinning my head next week.

      @John - Off the top of my head, I'd say it would be possible. One way would be to have the form used by the documents in the view include an embedded view to show the history documents. The other would be to set a form formula in the view that points to a form that includes an embedded view for the history documents. I suppose you could also try a regular view and have it exceute a @SetViewInfo, but I haven't had great luck with that @command. Hope that helps.

      Vee Eee Technologies said...
      This comment has been removed by a blog administrator.
      Anonymous said...

      Hi, I followed your tip to simulate a composite application. It's very usefull for me. Thanks a lot!
      But I need to show some child docs from a dataBaseB in an ambedded view restrict to the docunid of the parent doc (parent is created from a databaseA). I use the notes.ini file to store the docunid of the parent doc. It's ok for the notes client but it doesn't work in web! Do you think there's a way to pass the value of the parent unid to the embedded view.
      Thanks a lot for your help!
      Regards

      Don McNally said...

      Thanks for the comment and I'm glad you found it useful.

      I am not a web developer so I can't tell you exactly how to do what you want to do. But I found this (https://groups.google.com/forum/?fromgroups#!topic/comp.groupware.lotus-notes.programmer/F7S0AdZ_t4s) that seems to have a possible solution (see Dennis Yugo's comment). Sorry I can't give you more than that.

      Anonymous said...

      Hi, thanks for your reply! I'm not a web designer too (your are not alone!!) It seems that he had the same issue, but he didn't give the workaround in the topic.
      I will search again!
      regards

      Dietmar said...

      Has one ever tried to download the sample database? When I do, I get "This database has local access protection (encrypted) and you are not authorized to access it."

      Don McNally said...

      Hi, Dietmar. Thanks for checking out my post. I uploaded the sample database about 3 weeks ago and I guess no one has tried to download it since then. I often forget about the encryption on my local replicas. I put a new version up just now that should have no encryption on it. Please let me know if the new version works for you.

      Dietmar said...

      Revisited today ... Thanks for updating the sample database, Don. Works well now.

      Anonymous said...

      Please note that if you struggle to get this code to work, just check your quotes.
      If you copy and paste the sample code from the website, then it posts the wrong quotes in designer. Just replace them with normal quotes.

      Anonymous said...

      Hi Don
      I was looking for similar solution and your post has helped a log.

      Thank you for detailed explanation.

      Regards
      Krishna

      Anonymous said...

      I keep getting error "you cannot add a directory to your workspace". I get this on the Wrapper form (and then the wrapper frameset and application form). I added the environment variable to the wrapper form instead of the application form, so pretty sure that the @setEnvironment phrase is the problem.

      Unknown said...
      This comment has been removed by the author.
      Marco S. said...

      Hello.
      I'm using this trick for months but Today I realized a big limitation and I don't know how solve it.
      You can't use it when you open two similar documents containing the emdedded editor.
      What happens if you have the embedded editor on a form (for example a Person form with embedded docs showing activities) and you want to open two document containing the embedded editor (in my example two person documents A and B)?
      In this situation, when you go in edit mode of the Person A you will lose his activities (in the embedded) and you'll see the activities of the Person B.
      In fact when you open the Person B document the environment variable will be overwritten!! (if you stay only in read mode no problem because the variable and the embedded documents are not re-calculated, but if you go in edit-mode you'll be unpleasantly surprised!).
      Anyone has ideas about it? Thanks

      Ramon said...

      @Marco S.: Thats the problem i've too. In Read-Mode all opened Docs shows the right Content/Kategories, but if you go with one Doc in edit Mode and Save the Doc, then the next Doc you go in edit mode get the wrong value.

      Have you managed the Problem, if i find a Solution i will post it here.

      Best Regards
      Ramon

      Achim said...

      great solution!

      > "you cannot add a directory to your workspace"
      don't copy/paste - the " are no normal " - you need to replace them, then it works

      Problem with more than one open document in edit mode:

      refresh the environment in queryrefresh