Part 1 - The Revolution will not be televised...
...but it will be blogged.
The first part of what we're looking at today is remote event binding in Notes apps.
The concept is simple enough. Let's say I have a very typical Notes apps with a button to create a new document. Typically, the form of the new document has events for PostOpen, QueryRecalc, QueryModeChange and so forth defined in the form's design.
An advanced technique is to attach code to these events using a library instead. Typically, this is done through a custom class, with On Event calls, set up when the document is first created.
When I decided I wanted to do some research on this topic, I chatted with my friend Colin Macdonald of the Clan Macdonald. I'd mentioned to him that I thought there must be SOME way to build Lotuscript this way, because you could remotely get the UIDoc handle when you do a workspace.composeDocument. So while I put some time in on the treadmill, Colin got to work with some experiments...
He found that he could do the following:
Dim uiDoc as NotesUiDocument
Set uiDoc = notesWorkspace.composeDocument(server, path, form, 0, 0, true)
On Event QueryRecalc From uiDoc call myRecalcCode
Where myRecalcCode was a routine defined IN THE VIEW. The form of the new document had no knowledge of that routine, yet it was remotely triggered when the document was refreshed. When it was, it had the SOURCE of the document, but the global inclusions of the view. Additionally, the CONTINUE variant moved across as well, so the view could actually return a value to the event that triggered the function call.
This, of course, has an interesting implication. It means if you can get a handle on a particular UI context in a Notes client, you can attach code to the events of that context, from your current context. When the code executes, you get the lotuscript context of where you originally defined the routine.
Here's what it looks like in The Revolution...
And here's the detail showing just how simple the code is in the view...
I've uncovered one limitation: the remote UI object must have SOMETHING defined in that event, otherwise it's never triggered in that context. It doesn't matter what's in there -- it can be a placeholder, as long as there's some kind of evaluated code. So I was able in to open my personal address book and then bind code in The Revolution to the address book's NotesUIDatabase.QueryDocumentDelete event.
That means we can't totally encapsulate just ANY Notes app with a set of remote events. The other app's design has to acknowledge those events already in some way.
However, it might be possible to mix language contexts. I didn't really try that. So you might be able to have a form where the QueryRecalc is @Formula or Javascript, while a view binds some Lotuscript to that same event and triggers it. I haven't tried this yet -- though I imagine some curious reader here will give it a crack before too long.




Comments
Posted by Charles Robinson At 11:35:22 AM On 07/22/2007 | - Website - |
What could you do with it? I'm working on some example for that.
Posted by Nathan T. Freeman At 11:45:36 AM On 07/22/2007 | - Website - |
I would also like to be able to get references to objects that are global to the database. So these would be instantiated once when the database is opened and would be available for other UI elements. For example, error handling code could be instantiated once and then just invoked from almost anywhere. Not sure if agents running on the client could get a hold of that code.
Also the ability to bind code to events on remote ui elements is nice in terms of handling deletions as these now can be localized to the view that is to handle that deletion. Code becomes simpler as it only needs to deal with one case. No longer do we need to write a big case statement to differentiate the behaviour for different documents.
Now if I only knew why this actually works. I mean why does the dynamically loaded code behave the way it does. It may very well be intended behaviour, but I still find it puzzling. You seem to think that code that is Execute'd as part of one event shares the same memory space (stack) even though it may be part of different subs. Seems it must be so, until there is a different explanation.
Posted by Slawek Rogulski At 12:01:05 AM On 07/23/2007 | - Website - |
But even just remote binding is pretty cool. Class implementations can get much more localized in their encapsulation techniques. For instance, rather than having a document's PostSave event try to track down whatever view a document was in, you could have the view where the create/edit action was launched attach itself to the PostSave directly, and monitor for its own refresh cycle.
Parent/child field syncing also gets a breath of fresh air.
Posted by Nathan T. Freeman At 08:16:33 AM On 07/23/2007 | - Website - |
This way I can set up the shared code, pass a reference to the uiview and take it from there all on the form. At least in theory, as I have not gone back to refactor my code, yet.
Posted by Slawek Rogulski At 11:47:44 AM On 07/23/2007 | - Website - |
Posted by Stephan H. Wissel At 08:55:45 PM On 07/24/2007 | - Website - |
It's not limited to a single NSF. You can have SESSION-wide objects to pass around.
Posted by Nathan T. Freeman At 09:34:38 PM On 07/24/2007 | - Website - |
But hang on! Session wide as in you load the objects you want to be accessible in throughout the session in the desktop6.ndk database and then grab them from there in all subsequently loaded NSFs? Or maybe bookmarks.nsf? Does that make sense?
Posted by Slawek Rogulski At 10:52:43 PM On 07/24/2007 | - Website - |
There are limitations. You have to bind an event from the bookmark.nsf to something in another application, right? So if the user does File - Database - Open, you don't have any trigger context on the bookmarks. Nothing gets kicked off from that point.
But if you're using Bookmarks as a portal, then remotely binding the event becomes possible.
The trick is: it's not just a matter of having a place to STORE the objects. You could load 'em up into the NotesUIDatabase globals for Bookmarks pretty easily. It's making sure you can subsequently remotely bind as well.
If you look at The Revolution, you'll see that we essentially push the object reference from a starting context to a new context. I'm working now on a technique to pull it instead. I don't think it's going to be terribly difficult, but there's a quirk about execution order of bound events that MIGHT get in the way.
Posted by Nathan T. Freeman At 06:49:11 AM On 07/25/2007 | - Website - |
---* Bill
Posted by Wild Bill At 06:42:02 PM On 07/29/2007 | - Website - |
Posted by Alain H Romedenne At 04:41:48 PM On 08/08/2007 | - Website - |
Posted by guido At 11:23:51 AM On 08/13/2007 | - Website - |