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>