dominoGuru.com

Latest Updates

Loading... Please Wait!

Products & Applications

Showtime
My Blackberry Enterprise Server Push Utility for the Lotus Notes Client, allows you to create Jobs for individual Channel, Message, and Browser Content Pushes, as well as allows you to delete Pushed Channel Icons from defined recipient devices.

Time Tracker
The idea is simple. At the start of your day - upon completion of your first task - create an entry highlighting what you did and whether you feel it was an efficient or inefficient use of your time. Based on several requests, you can also select the priority, apply categories, or even align your time against a project.

For Lotus Notes Client v8.0 and above, you can use the Time Tracker Widget to make this process even easier!

Zephyr
My Configuration-based Rich Text Mail Merge and Emailing Utility, Zephyr allows you to create rich, data-driven emails to support automated workflow - all via Microsoft Word Mail Merge-like architecture. Dear <firstname> allows you to personalize each email message not only to the individual recipient, but also to the individual application workflow event!

xCopy
xCopy is a simple configurable xCopy client for the Lotus Notes client. By creating and defining xCopy Profiles, you can batch process your file backup or remote upload jobs. With the addition of the xCopy sidebar widget, you can easily kick-off these jobs, and modify both the xCopy Profiles and xCopy itself.

Community & Resources

Lotus Technical Information & Education Community

The Lotus Technical Information & Education community is comprised of IBM, business partner, and customer subject matter experts who use product wikis, published articles, white papers, community blogs and the latest in social media to build and share high quality technical content.

OpenNTF.org - Open Source Community for Lotus Notes Domino

OpenNTF is devoted to enabling groups of individuals all over the world to collaborate on IBM Lotus Notes/Domino applications and release them as open source.

developerWorks Lotus : Wikis

Share your deployment experiences and best practices in our wikis and help IBM to create scenarios for successful deployments. Contribute to the community by collaborating on shared content and leverage the shared knowledge from that community.

Welcome to dominoGuru.com!

Focused on being the go-to resource for the IBM Lotus Notes Domino developer, dominoGuru.com delivers introductory-level best practices and advanced development deep dives for the IT professional, book and gadget reviews, and technical weblog, and more!

NotesDocument READ and UPDATE with AJAX calls to Domino Agents (or Simple Inline View Editing over the web) - Build, Demo, and Download

09/22/2009 10:30:03 AM by Chris Toohey

Building off of my example from yesterday, I thought that I would show you how we can quickly and easily create READ and UPDATE functions for NotesDocuments via calls to our (modified) HTTP Request Consumer Domino Agents. And, to spice things up, I thought I'd do it all via AJAX.

Build Synopsis

HTTP AJAX NotesDocument Mods Example NotesDatabase

That's the end-goal - a simple NotesData table that will allow us to change the Status of a given NotesDocument.

To get to that goal, I'll take the Agent Design Elements from yesterday - creating one for the READ and another for the UPDATE function. But first I need to ready the Page Design Element that acts as the Default Launch Object for the NotesDatabase, which will act as the display for our NotesData table.

Phase One: index.html Page Design Element

The index.html Page Design Element - just like with yesterday's example - is extremely simple by design: I want to focus your attention to the functional capabilities of having your Web Applications (Domino or non-Domino technologies-based) interacting with the HTTP Request Consumer Agents.

We'll focus on the HTML Form Element and the JavaScript functions, as the rest of the HTML markup is either descriptive/introduction or my Paypal Donation stuff.

The HTML Form Element contains the following markup:

<form action="#" name="moddocs" id="moddocs" method="GET">

<div id="viewbody"> </div>
<script>getdocs(document.getElementById("viewbody"));</script>

</form>

The JavaScript functions - there are two - are:

var http = false;

if(navigator.appName == "Microsoft Internet Explorer") {
http = new ActiveXObject("Microsoft.XMLHTTP");
} else {
http = new XMLHttpRequest();
}

function getdocs(target) {
http.open("GET", "getdocs.agent?open", true);
http.onreadystatechange=function() {
if(http.readyState == 4) {
target.innerHTML = http.responseText;
}
}
http.send(null);
}
function moddoc(val, UNID) {
http.open("GET", "status.agent?open&status=" + val + "&UNID=" + UNID, true);
http.onreadystatechange=function() {
if(http.readyState == 4) {
getdocs(document.getElementById("viewbody"));
}
}
http.send(null);
}

getdocs() simply grabs getdocs.agent Agent Design Element-generated markup and sets the innerHTML of the passed-thru HTML Object (via an AJAX call). moddoc() passes two values to the status.agent Agent Design Element: the new value of the status NotesItem and the target NotesDocument UNID (again, via AJAX). When it's complete, it runs another AJAX call to getdocs() to refresh the NotesData table.

All I need to do from here is make sure that my NotesData table has the markup it needs that wires into the moddoc(). Pretty simple, as via the getdocs() function I have absolute control over what's returned to the Web Browser Client.

Phase Two: HTTP Request Consumer Agents

The getdocs() and moddoc() simply require a modification to their respective Initialize subroutines to both deliver and update our NotesDocuments.

getdocs.agent Agent Design Element - Initialize

status.agent Agent Design Element - Initialize

... and that's it. The getdocs.agent Agent Design Element generates the markup that we need: the onchange event of each SELECT HTML Element passes the newly-selected value and the target NotesDocument Unique ID to the moddoc() JavaScript function, which calls our status.agent Agent Design Element. This processes the request - using the submitted UNID and status parameter values to find the target NotesDocument and update said NotesDocument status NotesItem respectively.

After that, we simply "refresh" the UI via another AJAX call... and we're done.

Online Demo, Example Download, and Closing Remarks

Again, for those of you who prefer an online demo complete with downloadable example, I've got you covered.

The code written in this series is - how should I put this - not ideal. In a "best practices" scenario here, you'd want to return something like JSON, and parse that JSON return locally. This code is about as simplified and straight forward as it gets - I didn't do anything that would subtract from the goal of this article: getting you to understand just what you can do with an HTTP Request Consumer Agent Design Element.

Hopefully, this is a simple enough showcase that you'll start delving into this practice yourself - regardless of your comfort level with LotusScript, JavaScript, HTML Method calls, and AJAX. It's really powerful stuff here, and your web applications will definitely benefit from the overall approach.

Notice I said web applications - which is the second time in this article that I haven't prefixed Domino as normal. I use this approach with Flash-based Banner Ads, simple HTML Forms hosted on IIS and Apache, and countless other scenarios. It's ultimately no different than using Google Web Services or any other SaaS or Cloud service. I take that back actually - using this approach, you can quickly and near-immediately bring Lotus Notes Client-only applications onto the Web and Mobile Browser Clients: simply point the target NotesDatabase to a different NotesDatabase, Domino Server, etc. and you have yourself a very powerful NotesData proxy on your hands...

HTTP Request Consumer Domino Agents - Build, Demo, and Download

09/21/2009 12:01:19 AM by Chris Toohey

I was recently asked by two people how they could get a Domino Agent Design Element to consume an HTTP request. Well, I wasn't asked this exactly...

One Lotus Notes/Domino developer asked me how they could modify a NotesDocument via a web browser client when said NotesDocument is not in edit mode in the UI. He is updating several fields in the NotesDocument - via an Approve button - and ultimately has to redirect the user to a different URL post approval.

The other request was asking for a simple search form in a Domino Web Application... more or less. The original request was to submit the NotesUIDocument (if you will...) via @FileSave;@FileCloseWindow, capture the submitted request, not save a new NotesDocument to the NotesDatabase, run an Agent Design Element via the WebQuerySave Event on the Form Design Element, and do the voodoo that he-do from the Agent Design Element.

Over the past several years, I've come up with a different approach: Submitting an HTTP request to a Domino Agent Design Element... and doing whatever I need to do from there.

Now - before I get into this - some of you may have noticed that I keep referring to each Design Element in it's full name, ie., Agent Design Element. I'm doing this - and will continue to do so - to alleviate confusion. See... I'll be talking about an HTML Form Element interacting with a Domino Form Design Element via the HTML Form Element's Processing Agent, which is targeted at a Domino Agent Design Element. In other words, the Form will interact with a Form via it's Processing Agent, which points us to our Agent. So yeah, it's not like I'm doing this for the word count!

Build Synopsis

For our build example, I'm going to create a simple search facility via an HTML Form Element and a Domino Agent Design Element. To complicate my life make sure we effectively cover all HTTP POST and HTTP GET Method requests, the example NotesDatabase build will feature a unique HTML Form Element each running an HTTP POST, and HTTP GET, and even an AJAX-based interaction with our Domino Agent Design Element.

I'll break this build down into three stages. In the first stage, we'll create a simple HTML Form Element using a Domino Page Design Element that will submit our request to a Domino Agent Design Element. We'll build this Domino Agent Design Element in phase two, and complete our build... well, putting in some Domino-specific hacks to get everything to work via GET. That last part will make sense when this article's finished in that you'll know what I'm talking about - not that you won't see how frustrating it can be!

Phase One: HTML Search Forms

We'll start off by creating a Page Design Element named index.html, setting the Content Type to text/html, setting the NotesDatabase properties to use our index.html as the Default Launch Object (not really needed per se, but it makes everyone's life easier...), and after we've set the HTML Head attributes and the beginning of the Body Element, we can add the following markup:

<h4>HTTP POST via simple HTML Form</h4>
<form id="example_httppost" name="example_httppost" action="search.agent" method="POST">
<label for="example_httppost_query">Query</label><input type="text" id="example_httppost_query" name="query" value="" /><input type="submit" value="Submit Trigger" />
</form>

We'll add 2 additional forms to the index.html Page Design Element - one for HTTP GET via simple HTML Form and another for HTTP GET via AJAX - but as each require a minor tweak that we'll cover in stage three of the build. We'll stick with this one as it gets the overall concept across: we're building a simple HTML Form Element that will submit a request (via POST) against our search.agent Agent Design Element.

Take note of the query HTML Input Element (or Field). This field will contain our search criteria, and will be the sole piece of data consumed when the HTTP POST request is submitted to the search.agent Agent Design Element.

Phase Two: Creating the search.agent Agent Design Element

In this phase, I'll create a simple Domino Agent Design Element - written in LotusScript - that will consume the submitted HTTP requests. I've simplified this Agent Design Element, which consists three (3) Functions and the Initialize:

getvalue

unescape

ReplaceSubstring

Initialize

Pretty basic stuff. Each function really just supports the simple act of taking the Domino Agent's Session - evaluated to a NotesDocument via DocumentContext - decides whether it's a POST or GET Method-submitted HTTP Request, and returns a value accordingly. In this case, it's grabbing the query parameter and using it's correlating submitted value for an FTSearch against a NotesDatabase. For our example build, I'm pointing it to the Domino Server Directory (names.nsf), thus using this more as a NotesData proxy vs. having the FTSearch run against the HTTP Request target NotesDatabase.

I mention that so you can immediately see the extended potential of this approach: your target NotesDatabase doesn't need to be HTTP-accessible in order to return NotesData to a Web Browser or Mobile Device Browser client!

The query thus returns a NotesDocumentCollection, which I then iterate through to build my markup String - which I will Print directly back to the Browser Client.

... and that's pretty much it. There is one additional check... but that's for AJAX vs. POST/GET Method HTTP Requests. Since the UX requires a different Content Type and, well, a different construct of the markup Printed.

Phase Three: AJAX considerations, Domino URL Command hacks, and final tweaks

For the AJAX-based HTTP Request, I add a simple QueryString Parameter and value (AJAX=1). It's usage is fairly evident in the search.agent Initialize LotusScript above - if set, return a Plain Text series of HTML SPAN Elements. Otherwise, it's full HTML Print.

Another gotcha: Domino URL Commands. This was an interesting one. When submitting an HTTP Request via the POST Method, it's simple: QueryString parameters are ignored, and you can point directly to the Domino Agent Design Element name without the need for additional parameters (ie., search.agent). With the GET Method, that's not the case. The entire contents of the submitted HTTP Request are added to the QueryString - both parameter and value. This wouldn't be a bad thing if Domino didn't require a valid Domino URL Command to preceed any of these parameter/value pairs.

For example, if I submit via GET Method to the search.agent Agent Design Element, I'll get this: search.agent?query=blah. And this will fail with a Domino-generated error message telling you - in all it's H2 glory - that there's no such Domino URL Command as query. open is a valid cross-Design Element Domino URL Command, so I decided to go with that... but in order to front-load the parameter, I needed to add it to the HTML Form Element.

<input type="hidden" name="open" value="" />

Silly, but it gets the job done! The result is an ugly but fully functional Domino URL: search.agent?open=&query=blah.

This same consideration applies to the AJAX requests as they use the GET Method to communicate with the search.agent Agent Design Element, but for that we can simply prepend the AJAX=1 to the URL from within the AJAX function.

As for tweaks - this is LotusScript: make it do what you want it to do! Pretty basic functionality that just can't be achieved via the Formula that's supported over the Browser Clients. If you need this to update a given NotesDocument, you can either pass a UNID vs. the query, run a target-NotesDatabase.getDocumentByUNID(UNID)-lookup, and do to that NotesDocument what you will!

Online Demo, Example Download, and Closing Remarks

For those of you who prefer online demos: http://domino1.clearframe.net/httpconsumer.nsf/index.html. Note: I've changed the target NotesDatabase from the Server Domino Directory to the NotesDocument Auto-Save Example Domino Web Application. You have the ability to create/edit NotesDocuments in that online demo as well, so feel free to have at it!

You can also download the demo NotesDatabase by clicking thru to the online demo (see, making you chase it!).

Lastly, I created this article and demo to help Lotus Domino Web Application Developers extend their application capabilites and functionality. In corresponding with one of the developers who mentioned a need for this functionality, he stated that he would compensate me for any help I could provide. I'll tell you what I told him: I'm very thankful for the offer, but the best way to compensate me for something that you find useful on this site is via contribution/donation to the site. All monies donated to this site go directly back into the site. Now, while I'm lucky in that I don't have hosting fees to worry about, I do purchase software - such as the warez I use for podcasting/screencasting, editing, etc. And I'm also picking up additional gear as needed/desired, such as new headsets for said podcasts/screencasts, etc. Now, while I don't think I'll hit the numbers in the coffers to pick up some higher-end hardware (such as the Apple Touch and the entry-level development Mac rig that I've been flirting with picking up)... every little bit extra helps the P.O. go through my wife that much easier.

If you can't donate to the site, I'll take your feedback - which is even more valuable. Like what you're seeing here? Want to see something else? Let me know and I'll see what I can do!

VIDEO: NotesDocument Auto-Save Teaser

08/22/2009 10:22:24 AM by Chris Toohey

While I'm still playing around with the demo of my NotesDocument Auto-Save engine - which I'm developing specifically for an article in the IBM Lotus Domino Designer Wiki - I thought that I would at least show an in-progress teaser demo.

The idea here is simple: The Auto-Save runs - in this example, every 5 seconds - and saves the UI Form's contents to a temp NotesDocument via HTTP POST over AJAX. For the initial submission - which creates a new temp NotesDocument - said NotesDocument UniversalID is returned and put into a field (which I would typically set to hidden). All subsequent auto-saves use that UNID value as the POST target.

When/if you finally submit, you're actually editing the temp NotesDocument and submitting it to the NotesDatabase as a document.

The idea here is that workflow and application logic may be tied to the document, so we keep it a temp NotesDocument until it's submitted. A simple clean-up Agent can be setup to purge any temp NotesDocuments that were not submitted... and you now have your simple-yet-fully-functional NotesDocument Auto-Save engine!

FYI: All NotesDocument reads and writes are done via the Domino CRUD API!

developerWorks Author Contribution Program, Domino Wiki, and my latest article

06/12/2009 03:30:31 PM by Chris Toohey

My latest article and example utility - the Lotus Domino Java AJAX Proxy - will be published hopefully sometime this month as a wiki publication on the Lotus Domino Designer Wiki.

There it should find a much larger readership and hopefully become a more useful solution for those developers beyond the yellow bubble of our Lotus Online Community.

My publishing the article in the wiki instead of directly onto this site is only - I'll admit - partially due to the fact that I think it will get more eyes-on and evolve beyond v1.0 than if I were to publish it here. See, I get something out of publishing to the wiki.

After a quick exchange with Amanda Bauman ( abauman@us.ibm.com ) - where we discussed the article topic, the specific versions of Lotus technology used, etc. - I had pre-registered my to-be-written article for submission to the IBM developerWorks Author Achievement Recognition Program! I am currently an IBM developerWorks Contributing Author, but working my way to the IBM developerWorks Professional Author designation.

So - to recap - I'll publish the Lotus Domino Java AJAX Proxy article on the Lotus Domino Designer Wiki, gain points towards a new developerWorks Author designation, gain readership and further my exposure in the greater global IBM community.... all for the same effort that it would take me to publish it on my own site. Well, on my own site minus the benefit of it being seen outside of the Lotus Online Community, which often has the you're preaching to the choir result.

If you have ideas on articles, run a blog/website and about to write a new article, or just want to contribute to the wikis that little nugget of how-to information that helps get you through the day, contact Amanda Bauman and see if you can't be greedy like me!

Using AJAX, text/plain Content Type, and external resources to create dynamic in-line content!

01/18/2008 11:26:43 AM by Chris Toohey

Was chatting today with a good friend and fellow blogger Mike Smesler, when an interesting requirement came up for an application that he was working on: the need to populate a section of the current page with content from another source - and as dynamically as possible.

Now, an old-school solution to this problem would involve using an embedded iframe and walking said iframe to get the content. In the days of AJAX however, that's no longer a necessity! Here's the code that we'll use:

var xmlhttp=false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
xmlhttp = false;
}
}
@end @*/
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
xmlhttp = new XMLHttpRequest();
}

function getcontent_innerHTML(url, targ) {
targ.innerHTML = '<p align=center><img src="ajax-loader.gif" /></p>';
xmlhttp.open("GET", url);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
targ.innerHTML = xmlhttp.responseText;
}
return true;
}
xmlhttp.send(null);
}

Now, for it's usage:

<div id="container">&nbsp;</div>
<script>
getcontent_innerHTML('some_URL_here', document.getElementById('container'));
</script>

Now, for the Domino-slant on this: you can take a Page or Form (or View, or Agent, etc. etc. etc.) Design Element, set the Content Type to text/plain and generate your markup to be used with this approach. This means that you can run Database queries live and in-line (or -hint hint- use any web technology or client to create a conduit to querying or maintaining Domino applications)!

It's a very simple technique that can help expand the architecture and usage of your applications - even outside of Domino!

One thing that you might want to look at however, the line targ.innerHTML = '<p align=center><img src="ajax-loader.gif" /></p>'; is simply put in there to load a "Loading - please wait" type of icon which will tell your users that something is going on - especially if the response from the server/resource lags for whatever reason.

Updated

Thanks for the catch Tim - I'll approve your comment, which will explain this update, when I get back into the office!