What if they had a Revolution...
...and nobody came?
Did Tim and I leapfrog our audience with the latest spoon-bending efforts? My emails go unanswered, the one pointer to this stuff come from my colleague (who made a significant advance with this technique yesterday) and people look at the demo database and say "I don't get it."
Folks, this is sharing Lotuscript object references between tabs. Shared objects between NSF, between frames, between embedded elements, and in the case of ActiveX controls, between applications!
And I can barely get a "I might find this interesting if you weren't so puffed up about it" in the comments. Bah.
So, if you have a question on how this works, download my or Tim's example. If you have an idea on where this technique could be used, post it in a reply here. I'll start...
1) A global instantiation of audit trail/logging instances for an entire NSF context. Imagine establishing an OpenLog session in the NotesUIDatabase PostOpen event, and keeping it until the application is closed. How much faster would it be to write log documents? How much more might you log? Since you could actually keep the same DOCUMENT open the whole time, why not do the equivalent of a DEBUG_OUTFILE and record every move the user makes in your application?
2) Cross-frame COM objects. Tim and I showed a technique for full-page web browser linkages in frames the other day. But that creates an entirely new Browser object for each document selection. With The Revolution, you could render a browser object in a frame and update it dynamically, say, based on document selection in a view in another frame. Imagine having a list of Taco Bells in your view, and as you select each one, they're adding to a Google Map in the browser frame. Sound impossible? It's easy, if the view has the COM object in the other frame available, you're literally using browser.document.addAddress(notesUIView.documents.getItemValue("Address")(0))
3) Need to get the selected document collection from an embedded view? We've shown how to do it before, but it was necessary to match the view in a hidden frame. That has the downside of prohibiting the use of "switch to view" column headers. Now you don't have to worry about it. The new view can simply reach into the parent container, inject it's UI reference, and then your containing document just says myCache.contexts("embeddedViewName").refUIView.documents That's all there is to it.
4) Want something simpler? Okay, you can stop trying to force a view refresh from the wrong context. Ever have a form where you write a PostSave that includes...
NotesUIWorkspace.currentView.refresh?
Yeah, you can stop that now. When you create the document from the view, grab a handle and do "On Event PostSave from NewDoc..." and tell the blasted view to refresh itself. Now you can put that code where it belongs.
Starting to get a feel for it yet?
I'll tell you what, if you still don't get it, don't worry about it. Just ask in the comments for the most outrageous thing you can think of from the Notes client. What's something you consider totally impossible? Interactive dashboard-style graphs? Mash-ups? Name it. Let's see if The Revolution changes as much as Tim and I think it does.



Comments
Using a single MQ Series, or LS:DO, session at view level, rather than an instantiation per Document Script.
Previously, if response times were a critical requirement (WAN?), then the solution would have required a bit of C to hold open the pipe. Usually this just forced a UI decision which was often not optimal if not bad.
Posted by Colin Macdonald At 08:26:18 AM On 07/26/2007 | - Website - |
Posted by Rob McDonagh At 09:35:59 AM On 07/26/2007 | - Website - |
I also get the nagging feeling that this could be used in 'Interface Matters' Chris's embedded editor example, where he closes and opens the document when one of the embedded docs is deleted using the embedded editor. Also, I think we could use this to line up the New Doc, Update Doc, and Delete doc options, instead of having the New Doc in the view action, and the others inside the embedded editor...that was something a client asked the last time I implemented this, and I couldn't think of a way to do it then.
Posted by Ranjit At 09:41:11 AM On 07/26/2007 | - Website - |
Posted by Charles Robinson At 09:50:33 AM On 07/26/2007 | - Website - |
this IS way cool though. congrats. your gigantic brains are all set to take over the known universe.
Posted by jonvon At 10:20:23 AM On 07/26/2007 | - Website - |
I haven't dug into the fine details of this, but I had a scenario present on a recent project where I could have used this functionality. I have an embedded view with an action to create a new document which passes values from the parent document into the new document. Problem is, if the user accidentally clicks the 'New' action and then closes the subsequent new document, they are presented with a Save New Document dialog. I thought this would be a bit confusing to the user if they hadn't done anything to the new document and simply wanted to close it. I looked into setting the IsNewDoc property to false, but couldn't get a handle to it. I'll be studying The Revolution in more detail to see if it can set my IsNewDoc to false. Thanks!
Posted by Mike Miller At 10:31:53 AM On 07/26/2007 | - Website - |
My two-row action bar logic might benefit as well.
Hmmmm.....
Of course, We shouldn't forget about your other recent innovation relating to embedded framesets. All very kewl.
Posted by Kevin Pettitt At 10:39:00 AM On 07/26/2007 | - Website - |
BTW - Thanks for totally nuking the "get selected document from embedded view" solution I've writing up for posting on Mr. Blatnik's site
Posted by Keil Wilson At 10:49:28 AM On 07/26/2007 | - Website - |
Keep 'em coming.
One thought I had -- could we drive view type-ahead in an embedded view from a form field? Say by establishing a NotesTimer in the view that monitors the field in the container UIDocument?
For that matter, do we even need remote binding for this? Maybe not... a timer is a timer, right? We can always get NotesUIWorkspace.currentDocument.fieldGetText so maybe there's nothing NEW available there.
But we COULD trigger some stuff in cross-frame contexts with, say, an onChange event in a field. That might open some new doors.
Posted by Nathan T. Freeman At 10:59:37 AM On 07/26/2007 | - Website - |
Posted by john head At 11:19:37 AM On 07/26/2007 | - Website - |
Posted by Mike Lazar At 12:10:26 PM On 07/26/2007 | - Website - |
Here's a simple example for you, Nathan:
A recursive budget database.. i.e. you start with an overall budget, say for "Smart Family Budget" with a total amount and an amount allocated/spent. Then have a response document under that for "John Smart's Budget", then have response document under that for, say, "John's Beer Budget".
All forms open directly to edit mode.
You should be able to open the Smart Family Budget, then open John's Budget either from the view or from an embedded view within Smart Family Budget, then the Beer document from the view.
With Tim's idea of using a cached list of variants, you could open all three documents, in any order, change the Beer budget and then see your change immediately reflected in the the TotalAllocated fields other two NotesUIDocuments. If they're open in the UI, they'll update through the UI instead of the back end.
We could even include the % allocated in the window title of each budget document so that when the Beer budget is changed, we can see the other two tab titles update immediately. If they're open in edit mode, call the appropriate NotesUIDocument.Save. If they're not open, they won't be in the cached list, so we can update it via the back end as we always have. If the parent docs are open in read mode... the best I can think of is to switch to edit mode, save, then switch back. (I first thought of updating and saving via the back end then calling...
set uidoc2 = ws.EditDocument(False)
call uidoc.Close
... but that would change the tab order.)
Posted by John Smart At 03:55:53 PM On 07/26/2007 | - Website - |
From what I see in day to day land, hardly anybody's requesting or building sophisticated Notes client apps these days. Those apps have moved over to the web side now.
I see people being asked to maintain legacy monstrosities, or newby companies looking for quick doc library type things, and nobody requesting something truly sophisticated, unless it's on the web.
I hope I'm wrong. If I'm right, I hope it's a temporary blip that Notes 8 will alleviate. However, with Notes 8, maybe this technique is less relevant with multiple windows and property brokers, I dunno, haven't looked closely enough at it yet.
At any rate, I applaud the achievement and look forward to digging into it when opportunity allows. Many thanks!
Posted by Lance Spellman At 05:53:22 PM On 07/26/2007 | - Website - |
... yes, "borker" was an honest typo, but it made me giggle so I left it in.
... Gah! Now I got that Swedish Chef song in my head!
Posted by John Smart At 06:07:38 PM On 07/26/2007 | - Website - |
Especially interested in seeing something like your 3rd point. I've had a play but cant seem to get the embedded view to work for me ...
Excellent work though!
Posted by Sean Power At 03:51:01 AM On 07/27/2007 | - Website - |
Although dynamic loading of the script library works great and allowed us to prevent circular references and also enabled on demand loading of the script libraries, we encountered weird type mismatch error at our end when we tried to pass the built-in constant 'NOTHING' as an argument to a function in a script library that is being loaded dynamically. I had posted this problem in the Notes forum, but could not get an answer to the problem. Additionally, we cannot use typed objects, but variants only. I was first introduced to dynamic loading of script libraries a few years ago while reading a red book. Had an entire chapter dedicated to the same. Although not exactly similar to your idea, at our end, I have used the concept extensively in a multilingual application that we use. Amongst other things, we have used the concept in an agent in the application suite that loads language specific script libraries while generating emails for the end users. The object reference variable of the script libraries are "cached" in a list and depending on the language being processed, the script library is either loaded from the list or dynamically instantiated. I look forward to more articles that further this revolution.
Posted by Joydeep Gupta At 10:12:02 AM On 07/27/2007 | - Website - |
My first reaction on reading your post was - wow this could be **really** powerful, but I just don't have time to play with it right now. It's a concept that takes some time to sink in.
But the more I think about it, the more I think I should work it out before my next project starts. Just thinking about the ability to have to two documents open in the UI and be able to update either notesUIDocument object - this is truly revolutionary. For example: if you build your application correctly, I'm starting to think you could do things like
- get a list of all open documents. Think of what that could do for you.
- possibly bring a document which is open but does not have focus to the front? Not sure but this would be super.
- way better co-ordingation between embedded objects
and so on.
I think like any true revolution, this will build momentum and gather pace before taking over. Then we will wonder how we ever did things any other way. Yes - composite apps should improve things also, but many of my clients are still on 6.5 and 8 is years away.
Bring on the revolution !
Posted by Michelle O'Rorke At 10:25:03 PM On 07/27/2007 | - Website - |
So i took your database and that one Tim did and tried to play around a little bit.
I build another view into Tims database and changed between those two views. Every time i changed the objects got lost. So i see a brilliant idea, but without practical impact. Perhaps i am missing something and it would work even when changing between views?
Posted by Thomas Schulte At 07:45:41 AM On 07/30/2007 | - Website - |
I have the db but I'm so buried on other stuff right now, it's gonna have to wait. Based on the first read and your 'needful' update, I think this could be one of those techniques that changes how I do what I do. Between you and Chris, I am in a constant state of 'wait, I could do it this way, or that way, or wait, another way....' My productivity has fallen through the floor!
Speaking generally, the problem I have is trying to really really wrap my head around how to use some of the new stuff. I've been stuck in 'form, doc, view' for soooooo long, it took a while to see the value of embedded views so when you toss more stuff on the pile it's gonna take a while for me to 'get it'.
And thanks! Awesome stuff.
Posted by Doug Finner At 12:31:20 PM On 07/30/2007 | - Website - |
@11 - too late, I already played with it. Of course, I'd BEEN playing with it, but Nate pcreated a better gestalt than I had done. Anyway, until our teams stops its current bread and butter
of migrating the planet to Exchange, who the heck cares about Programming Power Pops Proving Prowess? Give me a good 5-to-8 migration with some change control to make the old apps better on the new platform, then we can rock.Nate, I don't think you'll be able to go global to the Database Script level. The scheme depends on being able to refernce a "real" variable from the $EXECUTE$ module (whose accidental persistence we're relying on). Code can only access variables outside its own module if the variable is a global, public variable. For example, in your contextView, you have a global variable myCache. Since you have Option Public turned on, this is a global public variable accessible to any modules co-loaded with the view's own module, including the $EXECUTE$ module in the viewQueryRecalc routine. The same holds true for the similar myCache variable in the form. When the form's event gets consumed both internally to the form and by the externally latched routine in the view, the $EXECUTE$ module loaded by both confuses LotusScript, and it incorrectly uses shares public globals between the two $EXECUTE$ modules. This is the key to the magic.
Now, move on over to NotesUiDatabase. Stick the myCache variable in the (Declarations). Everything's looking pretty much the same. Except it won't work. because there's no Option Public in NotesUiDatabase. You can't put on in there, and you can't even override the default by delclaring Public myCache directly... because for some reason, all code in the Database Script is ocnsidered procedure-level. Hmm, I wonder if you imported it all.... or if you Use'd a special module just for the database script. Might be a way around it. Let me know if that works for you, or if you need me to play with that. I've only tried this kind of stuff with things called from agents, or the occasional one-form-calling-another (I think that was where I managed to RBOD it).
Posted by Dovid At 01:09:34 AM On 07/31/2007 | - Website - |
And yes, I have it working from a NotesUIDatabase space.
Posted by Nathan T. Freeman At 10:54:23 AM On 07/31/2007 | - Website - |
Now, Nathan, how about a hat trick. We have had (are still living) two of your flashes of insight. How about one of these "unsolvable" problems:
1. showing in memory only (not saved) documents in a view and by extension same for notes document collections
2. dynamically changing a frameset to include additional frames.
Maybe there is more such challenges that we could list and attempt to solve.
Posted by Slawek Rogulski At 11:39:49 PM On 07/31/2007 | - Website - |
Basically, what I would like to do is define e.g. a register user function in the NAB - perhaps in the database script library - and be able to do something like this:
set session blah
set db = session.getDatabase (name of your nab file)
call db.registerUser(pass some sort of structure here containing the data)
Any thoughts, or am I stuck?
Posted by Andy Burnett At 10:08:14 AM On 08/08/2007 | - Website - |