My approach to DbLookup and DbColumn in Javascript
Sometimes NotesFormula is still the best way to go. We've all seen it abused in applications that use page after page of Formula when a few lines of LotusScript would have done the trick. But occasionally I still find that Formula can elegantly achieve the desired result. Such seems to be the case with today's example.
I was out playing with my new buddy JSON, and noticed that I was creating more design elements than I liked just to allow me to perform new queries (a new page embedding a different view, for example). "Well, this is just silly," I thought. "There's gotta be a way to make a single design element flexible enough to serve all my lookup needs." So I created a single page that computed which view to embed based on a query string value. But that seemed only slightly less silly, because all of the views still needed a very specific format in order for the returned data to be valid JSON... which essentially rendered each view useless for any other purpose. So I scrapped all of the duplicate views I'd created and retained only a single page (with - and this is crucial - the content type set to text/plain), which I then trimmed down to contain only a computed text element with the following value:
strQueryView := @UrlQueryString("view");
strQueryKey := @UrlQueryString("key");
strQueryColumns := @Explode(@UrlQueryString("columns");",");
@For(
n := 1; n <= @Elements(strQueryColumns); n := n+1;
intColumnId := @TextToNumber(strQueryColumns[n]);
strThisResult := @Implode(
@Text(
@If(strQueryKey = "";
@DbColumn("Notes":"NoCache";"";strQueryView;intColumnId);
@DbLookup("Notes":"NoCache";"";strQueryView;strQueryKey;intColumnId;[FailSilent])
)
);
"\",\""
);
strResultList := (strResultList) : ("{columnValues: [\"" + strThisResult + "\"]}")
);
"({columns: [" + @Implode(@Trim(strResultList);",") + "]})"
This allows me to query any existing view in the database via an AJAX request. For example:
new Ajax.Request('viewqueryjson?openpage&view=profiles&key=' + strMyName + '&columns=2', {
onComplete: function (getObject) {
var queryResult = eval(getObject.responseText);
Chat.profileID = queryResult.columns[0].columnValues[0];
}
});
Here's what makes this flexible enough to suit me:
- It can function either as a DbLookup or a DbColumn... for the latter, just leave out the key in the request URL
- It can return multiple columns from a single request... less trips to the server, just set "columns=" to a multi-value (i.e. "1,2" or even "2,1")
- The result format is generic... no need to treat one view differently from another, or to customize views to format the data to be Javascript friendly (although it's possible that certain characters may piss it off, such as apostrophes, quotes, and backslashes)
It's true, using an agent to retrieve this data would work just as well (or better), but I guess I'm still on my little "no agents" kick, and this approach gets me what I want when I don't want to risk having a frequently-triggered agent causing performance anxiety. Uh.......... I mean slowing down the server. Yeah, that's better.
In a similar vein, if you haven't already seen Vince's portalizer, go check it out. It's wicked slick. Chris, as an option for displaying Blogsphere sideblocks, this is probably pretty close to what you're looking for, although it seems to be geared mainly toward displaying multiple views on a single page; perhaps the approach I've outlined above would be useful for sideblocks that aren't intended to be linkable - at least, not in the traditional view-based sense (i.e. the BlogRoll block, which is specifically designed to contain links, but not to the documents that define the block content).








Comments
Posted by Roman Kopac At 04:16:44 On 08/23/2006 | - Website - |
Posted by Roman Kopac At 15:47:30 On 08/22/2006 | - Website - |
Sean---
Posted by Sean Burgess At 08:01:31 On 08/22/2006 | - Website - |
if (isIE) {
// compensate for poor implementation of a given standard
} else {
// do what every other browser supports
}
If we set a request header in the AJAX call, this clears up the problem:
new Ajax.Request(requestUrl, {
requestHeaders: ["If-Modified-Since","Thu, 1 Jan 1981 00:00:00 GMT"],
onComplete: function.....
Since I was 3 at the time, the file obviously must have been modified since then, so it forces I.E. to do what I told it to, even if it cached the result the last time. Not the most desirable approach - and it should only be used in cases where caching is inappropriate - but it produces the desired effect. As I've rambled on about previously, AJAX is effective - not just "pretty" - when it actually reduces the amount of data that must be sent between server and client. When used in that context, forcibly telling the browser to disregard the cache doesn't feel quite as sleazy as it might otherwise.
@Roman - you've brought up a good point as well. Whether using this approach to pull multiple columns or just one, each lookup has its limit (however, the limit applies separately to each, so as long as each is under 64K, numerous lookups can be returned simultaneously, even if the aggregate total exceeds 64). Bear in mind, this isn't intended to be an alternative option for full-blown navigation or reporting, just a flexible way to perform columnar lookups (such as retrieving new values for a drop-down field when a dependent field's value has changed) without a full page refresh. I agree, adding Start and Count into the mix might yield some interesting results, but for the use cases that motivated me to try this, most of the returned data would be minimal.
Posted by Tim Tripcony At 00:52:29 On 08/23/2006 | - Website - |