Quick Tip: A View-Filtering Search Box
Tue Sep 16 21:31:16 EDT 2014
One of the problems that crops up in some situations in XPages is the one described here: executing Ajax queries in too rapid a succession can cause the browser to cap them out until a full refresh. Depending on how you're encountering the problem, there may be a built-in solution: XSP controls that execute Ajax requests often have a throttling or latency parameter, and the same applies for "manual" JS widgets like Select2 (called "quietMillis" there).
Another such situation is the topic of this code snippet: a "filter view" control that allows the user to type and executes partial refreshes for each keypress or clearing of the field. To solve this, I found a block of code I wrote years ago, but should do the trick nicely. It uses setTimeout
and clearTimeout
to do this sort of delayed search and throttling. As I recall, it worked pretty well, though you'd want to increase the 500ms latency if the request usually takes longer, I suppose (or improve your page speed).
The code is from a Custom Control with styleClass
, style
, and refreshId
properties and stores its value in viewScope.searchQuery
.
<?xml version="1.0" encoding="UTF-8"?> <xp:view xmlns:xp="http://www.ibm.com/xsp/core"> <xp:div styleClass="lotusSearch #{compositeData.styleClass}" style="#{compositeData.style}" id="searchBox"> <xp:inputText id="searchQuery" styleClass="lotusText" value="#{viewScope.searchQuery}" type="search"> <xp:this.attrs><xp:attr name="placeholder" value="Search"/></xp:this.attrs> <xp:this.onkeypress><![CDATA[ if(event.keyCode == 13) { if(window.__searchTimeout) { clearTimeout(window.__searchTimeout) } XSP.partialRefreshPost("#{javascript:getComponent(compositeData.refreshId).getClientId(facesContext)}", {}) return false } ]]></xp:this.onkeypress> <xp:eventHandler event="search" submit="false"> <xp:this.script><![CDATA[ // search is fired when the "X" in WebKit is clicked to clear the box if(window.__searchTimeout) { clearTimeout(window.__searchTimeout) } window.__searchTimeout = setTimeout(function() { XSP.partialRefreshPost("#{javascript:getComponent(compositeData.refreshId).getClientId(facesContext)}", { execMode: "partial", execId: "#{id:searchBox}" }) }, 500) ]]></xp:this.script> </xp:eventHandler> <xp:this.onkeyup><![CDATA[ // Keypress doesn't fire for deletion if(event.keyCode != 13) { // Let's try some trickery to auto-search a bit after input if(window.__searchTimeout) { clearTimeout(window.__searchTimeout) } window.__searchTimeout = setTimeout(function() { XSP.partialRefreshPost("#{javascript:getComponent(compositeData.refreshId).getClientId(facesContext)}", { execMode: "partial", execId: "#{id:searchBox}" }) }, 500) } ]]></xp:this.onkeyup> </xp:inputText> </xp:div> </xp:view>