Adding a “working” visual indicator to the XPages TypeAhead

I arrived at this in as much a lesson in learning how the dojo and dijit interface works in the browser. This is a neat little demonstration but I am not sure that it is rock solid in terms of usage. Because it is manipulating the DOM on the front end, it always runs the risk of breaking something in a future release of dojo or XPages. But anyway here we go.

Problem

No user feedback that a type ahead field is looking up data

Background

The normal XPages type ahead functionality looks like this

Normal functionality of an XPages type ahead
Normal functionality of an XPages type ahead

Unfortunately there is no visual feedback to the user, they have no idea if it is a type ahead and they have no idea if anything is happening……This is especially irritating when the network is slow

Breaking down the the HTML

So we are going to add a visual indicator to the field – here’s how we break it down:

The “field” that we see is actually a mixture of divs and fields created by dojo and the Xpages server – breaking it down here with FireBug we can see that the field is made up of 8 (EIGHT!) DIVs and the actual input field. I have highlighted the sections we are interested in.

Breaking down the type ahead field
Breaking down the type ahead field

You may have seen the right hand DIV being used in form validation – a warning icon is displayed at the end of the field – pretty slick modification of the interface really.

You will also see that there is a whole world of style and class pain and suffering going on to make this happen. We really want to stay clear of altering anything more than we have to and that is why we are going to focus in on the right hand DIV in the above picture

Selecting the object to manipulate

The section we are interesting in manipulating is the smaller inside DIV shown above

<div class="dijitReset dijitValidationIcon" style="visibility: hidden;">
<br>
</div>

and this is an element within the <div id=”widget_view:_id1:travelLocator1″ (Highlighted in the picture above)

Using dojo we can “select” this class using the following code

dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d"))

This generates the following code – selecting all elements with the class .dijitValidationIcon, within the widget_view:_id1:travelLocator1 element

dojo.query("#widget_view:_id1:travelLocator1 .dijitValidationIcon")

oh yeah I had to make an update to x$ as well – turns out that dojo can’t query items with colons (:) in it any better than jQuery can. All the code is at the end of this article and I will post another entry showing the update in more detail. Suffice as to say at this point that I have to change widget_view:_id1:travelLocator1 to widget_view\:_id1\:travelLocator1 for the selector to work correctly.

Manipulating the object 

We can now create the following functions to add/remove the visual effect to the field
I added the jQuery equivalent(s) for two reasons, 1) that’s how I figured it out in the first place and 2) it highlights how much easier IMHO selectors are in jQuery).

The passed in parameter idTag will come from the CSJS we are going to add to the events in the designer client. This function selects the DIV we wish to manipulate, changes the background image then finally makes it visible (by default it is hidden)

function addVisual(idTag){

    var newImage="url('/dojo130/dijit/themes/tundra/images/treeExpand_loading.gif')"
    dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d")).style("backgroundImage", newImage)
    dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d")).style("visibility", "visible")

    //jQuery equivalent
    //x$("widget_"+idTag, " .dijitValidationIcon").css("background-image", newImage)
    //x$("widget_"+idTag, " .dijitValidationIcon").css("visibility", "visible")</pre>
}

The equivalent code to remove the image (when we are finished) is as follows (removing the image and hiding the DIV)

function removeVisual(idTag){

    dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d")).style("backgroundImage", "")
    dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d")).style("visibility", "hidden")

    //jQuery equivalent
    //x$("widget_"+idTag, " .dijitValidationIcon").css("background-image", "")
    //x$("widget_"+idTag, " .dijitValidationIcon").css("visibility", "hidden")

}

Adding the events to the XPage

The type ahead is triggered on the onkeypress event of the input field and the typeahead results are removed either on the onblur event clicking away from the field) or the onchange event (clicking one of the results).

Adding the image

In the onkeypress event we add the following to our XPage.

    addVisual("#{id:travelLocator1}");
Adding addVisual to the onblur and onchange events
Adding addVisual to the onblur and onchange events

Removing the image 

In the onblur and onchange events we add the following to our XPage

    removeVisual("#{id:travelLocator1}");
Adding removeVisual to the onblur and onchange events
Adding removeVisual to the onblur and onchange events

Final result

This now changes our type ahead (tested in IE8, Firefox 7 and Chrome 17) to look like this. The visual indicator is added to the type ahead 🙂

Type Ahead with Visual Indicator
Type Ahead with Visual Indicator

No live demo 😦

And this is the only kind of occasion where using WordPress blows –  I do not have anywhere to do a live demo of this. Any volunteers to help me host examples like this would be GREATLY appreciated !!!

The code is listed below  – you will have to change the following to work in your database

  • your lookup view (avoiding 64K issues)
  • the location of your dojo images

Known issues

  • There is no indicator that NO results have been returned (that’s for another day)
The code
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xp_1="http://www.ibm.com/xsp/coreex"
 xmlns:jQuery="http://www.jquery.com/xsp/coreex">

<xp:br></xp:br>
 <xp:table>
 <xp:tr>
 <xp:td style="width: 200px">
 Travel Locator
 </xp:td>
 <xp:td>
 <xp:inputText id="travelLocator1" styleClass="title">
 <xp:typeAhead mode="full" minChars="1" ignoreCase="true"
 htmlFilter="identity" preventFiltering="false">
 <xp:this.valueList>
 <![CDATA[#{javascript:@DbColumn(@DbName(), "vwTravel", 1)}]]>
 </xp:this.valueList>
 </xp:typeAhead>

<xp:eventHandler event="onblue" submit="true"
 refreshMode="norefresh" id="eventHandler2">
 <xp:this.script>
 <xp:executeClientScript>
 <xp:this.script>
 <![CDATA[removeVisual("#{id:travelLocator1}");]]>
 </xp:this.script>
 </xp:executeClientScript>
 </xp:this.script>
 </xp:eventHandler>

<xp:eventHandler event="onchange" submit="true"
 refreshMode="norefresh" id="eventHandler1">
 <xp:this.script>
 <xp:executeClientScript>
 <xp:this.script>
 <![CDATA[removeVisual("#{id:travelLocator1}");]]>
 </xp:this.script>
 </xp:executeClientScript>
 </xp:this.script>
 </xp:eventHandler>

<xp:eventHandler event="onkeypress" submit="false">
 <xp:this.script>
 <![CDATA[addVisual("#{id:travelLocator1}")]]>
 </xp:this.script>
 </xp:eventHandler>
 <xp:eventHandler event="onblur" submit="false">
 <xp:this.script>
 <![CDATA[removeVisual("#{id:travelLocator1}");]]>
 </xp:this.script>
 </xp:eventHandler>
 </xp:inputText>
 </xp:td>
 </xp:tr>
 </xp:table>
 <xp:br></xp:br>
 <xp:scriptBlock id="scriptBlock1">

<xp:this.value><![CDATA[
 function x$(idTag, param, jd){ //Updated 28 Feb 2012

 idTag=idTag.replace(/:/gi, "\\:")+(param ? param : "");
 return( jd=="d" ? "#"+idTag : $("#"+idTag));
 }
function addVisual(idTag){

var newImage="url('/dojo130/dijit/themes/tundra/images/treeExpand_loading.gif')" //Change me for your server
 dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d")).style("backgroundImage", newImage)
 dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d")).style("visibility", "visible")

 //jQuery equivalent
 //x$("widget_"+idTag, " .dijitValidationIcon").css("background-image", newImage)
 //x$("widget_"+idTag, " .dijitValidationIcon").css("visibility", "visible")
}

function removeVisual(idTag){

dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d")).style("backgroundImage", "")
 dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d")).style("visibility", "hidden")

//jQuery equivalent
 //x$("widget_"+idTag, " .dijitValidationIcon").css("background-image", "")
 //x$("widget_"+idTag, " .dijitValidationIcon").css("visibility", "hidden")
}

]]></xp:this.value>
 </xp:scriptBlock>
</xp:view>

Update – 5 March 2012
Like I said at the start of the article I did not know how robust this was and low and behold, the code above works in 8.5.2 but not 8.5.3.

Here are the updated addVisual() and removeVisual() which work in 8.5.3 and 8.5.2

function addVisual(idTag){ //8.5.3 version
var newImage="url('/dojo130/dijit/themes/tundra/images/treeExpand_loading.gif')" //Change me for your server
     var inputField=dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d"))
     inputField.style("backgroundImage", newImage)
     inputField.style("visibility", "visible")
     dojo.query(x$("widget_"+idTag, " .dijitValidationContainer", "d")).style("display", "block")
     inputField.attr("value","")

}

function removeVisual(idTag){
     var inputField=dojo.query(x$("widget_"+idTag, " .dijitValidationIcon", "d"))
     inputField.style("backgroundImage", "")
     inputField.style("visibility", "hidden")
     dojo.query(x$("widget_"+idTag, " .dijitValidationContainer", "d")).style("display", "none")

}

Update 22 March 2012

Through the help of Sven Hasselbach I have been able to add a fail icon – here is the article

6 thoughts on “Adding a “working” visual indicator to the XPages TypeAhead

  1. Is it me or does it look like the image gets cut off by the size (height) of the text field? Makes for a strange visual if that’s the case, maybe a smaller animated gif?

    • Yes the image is cut off by 1pixel at the top and bottom. The effect is demonstrated well though.

      I think I would rather go with something which is already on the server than provide my own in this situation.

    • Hi Pieter – thanks for the comment

      So I had to update the code from 8.5.2 to 8.5.3 and now it fails in 9 – this is because every time a new version of dojo is released they change the way that the dojo widgets work. It is really unfeasible to keep updating the code with every new release of dojo.

      It was a good case study at the time but not really any more.

      If you want a very cool type ahead capability I suggest you look at the jQuery token autocomplete which is way better even than my modifications to the out of the box domino model.
      https://xomino.com/2012/05/01/jquery-in-xpages-8-tokeninput-autocomplete/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s