Processing multiple documents from a view

Jake Howlett, 28 January 2003

Category: Views; Keywords: View checkbox GET POST process Agent

As Domino has matured over the years, the number of features only available to the Notes Client developer has decreased. For example, one feature of the Lotus Notes client is the ability to select documents in a view and perform an operation on all those selected. This ability doesn't translate well to the web browser and it wasn't until Lotus released Domino R5.0.5 that they introduced the feature that allowed the selection of documents in a view.

The Problem:

The problem with Lotus's solution is that it only really solved the problems that they deemed worthy. Mainly the ability to move documents between folders in the Mail template. What we really want is the ability to select the documents and do what we like with them. That is what I aim to cover in this article.

A Solution:

The solution most often suggested to this problem involves creating a long URL that consists of a set or document Unique IDs. Pass this list to an agent and it can decode the list and process each document in turn.

There are problems with this solution. For a start there are the limits in the allowed length of a URL using the GET method. This limit varies from browser to browser and between servers but, if we assume it to be 1,024 characters, the number of documents we can process at any one time would have to somehow be limited to about 30!

Another possibly more serious problem is that the browser will cache the URL. All GET requests from a browser are stored in the browser's history. Hence a user could inadvertently re-submit their request for the same URL and cause any code to run again, re-processing the same set of documents, at any time in the future. This can easily be done by either pressing the refresh button or by cycling through the history using the Back and Forward buttons.

The Solution:

In order to remove the chance of either of the above two scenarios it is advisable that we use the POST method instead. In fact you could argue that we should be using this method in the first place anyway. In the words of the W3C:

In particular, the convention has been established that the GET method SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". This allows user agents to represent other methods, such as POST, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested.

So how do we go about doing the same thing with but using the POST method? Well, we take a method I described on this site some time ago and mould it to this scenario. The basics being that we trick Domino in to letting us submit forms and data we generated ourselves. Let's see how.

As an example I will use a database that I made available online after a reader asked me for help. In this database there is a view of documents that are in one of two states. Published or Un-published. What is needed is a nice and easy way to publish/unpublish more than one at a time without having to edit and save each one. To do this we create a set of checkboxes (one for each document) and two buttons, as in the screenshot below:

View Processor

From this view an administrator can easily select any number of documents and, using one of the two buttons, quickly change their status.

Implementing the solution:

Before going any further it's probably a good idea to download the example database so that you can follow my directions without me having to go in to too much detail. I will assume you have done.

The first thing we need to do is create a view that allows us to select documents. To do this we need the view to be treated as HTML, like below:

View Properties

Notice that the property "Allow selection of documents" is not selected. We are about to do this part ourselves. In the first column of the view (called "All" in the example DB) we use the following formula:

"<input type=\"checkbox\" name=\"processdocs\" value=\"" + @Text(@DocumentUniqueID) + "\" />"

The result is a set of fields sent to the browser that all have the same name. We can send them back the Domino server and it will treat it as though they were all simply one multi-value field containing the list of IDs for the selected documents.

Obviously these fields need to be on a form. In the example database it's the form called "$$ViewTemplate for All". Take a look at this form and notice that we have included some HTML that ends the default Domino form and starts a new one called "processor". This is where the checkbox fields reside. When the user clicks either of the two buttons it is this form that is submitted and not anything that Domino created. Notice also that the action parameter of this new form. It point to a URL that will create a document using the form called "Processor".

If you have a look at the Processor form you will notice I added a field called SaveOptions with a value of "0" so that no document is actually created. Notice also that there is nothing much to this form other than the two fields to hold the data passed in to it and that it has a WebQuerySave agent setting. When the user submits the form's view, the server "creates" a document with the Processor form and this agent gets triggered. It's in this agent that we do the processing work. The code is extremely simple and the guts of it are shown below:

Dim process As NotesDocument
Dim item As NotesItem
Dim value As String

Set db = session.CurrentDatabase
Set view = db.GetView("all")
Set context = session.DocumentContext
Set item = context.GetFirstItem("processdocs")
value = context.status(0)

Forall v In item.values
Set process = db.GetDocumentByUNID( v )
process.Status = value
Call process.Save( True, True)
End Forall

Call view.Refresh

So the field that was submitted called "processdocs" holds the list of IDs for each document that we want to work on. The field called "status" holds the new value for status of all these documents. Hopefully how this code works is fairly self-explanatory and so I won't go in to any more detail than to say that it loops through each document, sets the new field value and saves it. The final step is to refresh the view so that when the $$Return field redirects the browser back to the view all the changes are obvious.

Taking it further:

What I've shown as an example here is only a basic application of this method. It could be used for other far more varied and advanced techniques.

For example, it would be easy to add a free-text field to the view's template. This way you could change the value of any field on any number of documents. All in the click of one button!

In Summary:

This might not be useful to everyone but I can guarantee you come across a situation where this technique, or a an application of it, couldn't make somebody's life an awful lot easier.