Search

What the Quote?

"There are two major products that come out of Berkeley: LSD and UNIX. We don’t believe this to be a coincidence."

Jeremy S. Anderson

"Oh yeah. I forgot about Busta."

Laura Tripcony

"Did you know that when you cook chicken in red wine it turns purple?"

Laura Tripcony

« slides and example database from AD111 | Main| Medusa is coming... »

@GoogleSuggest()

Category xpages

During AD111, I mentioned that SSJS supports custom @Functions, but advised against defining your own. My primary reason for advising against it is the possibility that IBM may, in a future version of Domino, implement their own version of whatever custom function you decided to define. Back when version 6 was released, I saw far too many apps break because developers had defined their own LotusScript Replace() function in previous versions.

On the other hand, XPages are capable of so much by comparison to traditional Notes apps that it's inevitable that we'll occasionally identify functionality we'd like to encapsulate into a function that IBM probably will never make a part of the core product. So here's an example of a handy custom @Function that I doubt will ever be native to the XPages implementation of SSJS:

importPackage(javax.xml.parsers);
var @GoogleSuggest = function(partial:string) {
    var resultKey = "googleSuggest-" + partial;
    if (!(applicationScope.containsKey(resultKey))) {
        var results = [];
        var baseUrl:string = "http://google.com/complete/search?output=toolbar&q=";
        var factory = DocumentBuilderFactory.newInstance();
        var parser = factory.newDocumentBuilder();
        var domResult:DOMDocument = parser.parse(baseUrl + partial);
        var resultNodes:DOMNodeList = domResult.getElementsByTagName("suggestion");
        for (var nodeIndex:int = 0; nodeIndex < resultNodes.getLength(); nodeIndex++) {
            var resultNode:DOMElement = resultNodes.item(nodeIndex);
            results.push(resultNode.getAttribute("data"));
        }
        results.sort();
        applicationScope.put(resultKey, results);
    }
    return applicationScope.get(resultKey);
};

If you add that to a SSJS script library, then add the library as a resource on an XPage, then you can easily set the typeahead for any edit box to be the Google Suggest results for whatever value the user types:

<xp:inputText id="search">
    <xp:typeAhead mode="partial" minChars="3" var="partial"
        valueList="#{javascript:@GoogleSuggest(partial)}">
    </xp:typeAhead>
</xp:inputText>

Comments

Gravatar Image1 - "My primary reason for advising against it is the possibility that IBM may, in a future version of Domino, implement their own version of whatever custom function you decided to define. Back when version 6 was released, I saw far too many apps break because developers had defined their own LotusScript Replace() function in previous versions."

Couldn't you prevent this simply by giving the function a name IBM would never use? For example, instead of "Replace()", call the function "CustomReplace()"?

Gravatar Image2 - @Timothy - absolutely. And following any upgrade, it's always a good idea to refactor any code impacted by changes to the underlying APIs; in the Replace() example, even if the custom implementation used a custom name, the new native implementation was faster than most custom implementations, so any application refactored to use the new native function benefited from a slight performance increase for each call to the function.

In SSJS, defining a custom @Function that may later be natively implemented by IBM carries less danger with it due to the nature of JavaScript (the custom definition would simply override the behavior of the native definition, so any code calling it should not break) but in most cases would be subject to similar performance implications.

Gravatar Image3 -

Realy nice code ;)

But somethings wrong in my implementation.
In the Typeahead respone i get a standard xpages error.
SSJS is the same as in your example.

Could you help me?

Error while executing JavaScript computed expression
Script interpreter error, line=9, col=44: Error calling method 'parse(string)' on java class 'org.apache.xerces.jaxp.DocumentBuilderImpl'
Connection refused: connect

9: var domResult:DOMDocument = parser.parse(baseUrl + partial);

Gravatar Image4 - @Wueste, the end of the error message you're reporting ("Connection refused: connect") indicates that your Domino server is unable to connect via HTTP to the Google Suggest API URL. Your server is most likely behind a firewall that prevents it from accessing the Internet.

Gravatar Image5 - Very cool. Tx Tim.

Gravatar Image6 - Tim, you could also use something like this instead:

var com = com || {};
com.timtripcony = {};
com.timtripcony.GoogleSuggest = function(....) { ... }

and then call it with

com.trimtripcony.GoogleSuggest(...);

Yes I know... what if your domain name changes because of an acquisition or something. Well... there are +'es and -'es to everything Emoticon

Gravatar Image7 - John, that syntax works well too, although it might be a bit confusing to maintenance programmers in the long-term: absent this kind of hierarchical object definition, a call to com.timtripcony.GoogleSuggest() in SSJS would attempt to locate a static GoogleSuggest method in a com.timtripcony Java class within the build path for the application. As a result, developers encountering a call to such a namespaced function within an XPage might assume it's a Java reference and go hunting for it in the package explorer when it's time to make changes to that function instead of realizing its definition is actually in a script library.

Post A Comment

:-D:-o:-p:-x:-(:-):-\:angry::cool::cry::emb::grin::huh::laugh::lips::rolleyes:;-)