List View / Enable Record Search
Open the sample app and create a few tenant records. Then play with the
search box in the tenant list view and see how "search-as-you-type" works.
In the previous section, we have created a sub-loader landlordlist in the slv0
loader. Now we are ready to add search function to the landlord list view.
First let's add an input field:
//...
if ($mode=='embed'){
?>
<div class="section">
<div style="padding:10px 0;">
<input id="landlordkey" onkeyup="lookuplandlord(this);">
</div>
<div id="landlordlist">
...
Note that the input field is added
before the landlordlist container. That way,
when the content of the list is updated, the input box doesn't lose focus.
The onkeyup event handler in the input field sends a request to the server,
along with the value of the input field, each time a key is pressed. The
response of the server is loaded in the
landlordlist container.
In
landlords.js, add the following function:
lookuplandlord=function(d){
var key=encodeHTML(d.value);
ajxpgn('landlordlist', document.appsettings.codepage +
'?cmd=slv0&key='+key);
}
Again, we're using the slv0 message to trigger the listlandlords server handler.
Edit the listlandlords function to the following:
<?php
function listlandlords(){
global $db;
$key=GETSTR('key');
$query="select * from landlords.*, persons.* ";
$query.=" from landlords, persons where ";
$query.=" landlords.personid=persons.personid ";
if (trim($key)!='') $query.=" and persons.fname like '%$key%'";
$query.=" order by persons.fname ";
In the interest of simplicity, the search only matches first names. You can
later write more sophisticated queries. For now, we just need to set up the
wiring.
If you test the search box in the list view, you'll see it's almost working. But
don't get too excited.
Use a non-limiting search term, such as the letter "a", so that there are more
pages. Click on the Next page link. See how the search term is no longer
honored? We'll need to fix the paging links so that the search term is
forwarded.
<a
onclick="ajxpgn('lv0',document.appsettings.codepage +
'?cmd=slv0&page=<?echo $page+1;?>
&key=' + encodeHTML(gid('landlordkey').value)
+'&mode=embed');">
Next »
</a>
There!
In practice, the following lines are used to allow a sound-based search:
...
$soundex=0;
if (strpos($key,'?')) {
$soundex=1;
$key=str_replace('?','',$key);
}
...
if (trim($key)!=''){
$query.=" where (person.fname like '$key%' ";
if ($soundex) $query.=" or person.fname sounds like '$key%' ";
$query.=") ";
}
Now when the user enters the search term Sara with a question mark, the
question mark is first removed from the search key, but any result that
sounds like Sarah is pulled from the database.
We are almost done with a fully functional list view. There's one more
enhancement, which we'll see again when building auto-complete lookup in
future chapters.
Enable Firebug and watch the requests being sent to the server in the Console
tab while typing letters in the search box. You notice that every key stroke
sends a request. This is exactly how we designed the lookup, but it's
wasteful. If we need to look up a landlord "Dane", it would be wasteful to
generate results that match "D", "Da" and "Dan".
The
ajxpgn function has built-in optimization so that when multiple requests
are sent to populate the same content loader, all previous in-flight requests
are aborted. This makes sure that the browser doesn't wait on searchs for
"D", "Da" or "Dan" when the response for "Dane" is ready. This doesn't
help elminating useless queries, however. The server still does work for
nothing.
Imagine you're planning a family trip with a roomful of opinionated yet
indecisive relatives. Some wants to go to the islands while some suggests a
ski trip; the Tuesday flight is in contest with the Thursday alternative. Being
an efficient person, or simply someone who hates the overhead of traveling
logistics, you are not going to book and then rebook anything unless there's a
consensus. If a final decision hasn't been objected by yet another final
decision in 30 minutes, you'll likely to pick up the phone or hit that Purchase
button.
Following the same concept, we use a keystroke delay to throttle the
requests:
lookuplandlord=function(d){
var key=encodeHTML(d.value);
if (d.timer) clearTimeout(d.timer);
d.timer=setTimeout(function(){
ajxpgn('landlordlist', document.appsettings.codepage +
'?cmd=slv0&key='+key);
},500);
}
When the user enters "D", a request is scheduled to be sent out in half of a
second. The handle of this scheduled event is stored in the
d.timer flag. The
name of the flag is arbitrary. If another key is pressed before the request is
sent, the scheduled event will be detected and aborted. Now the user has
another 500 millisecond window to type another character without sending a
request.
You can finetune the delay to strike a balance between responsiveness and
computing time.