This week’s Uncle Pete’s corner will be covering Gmail Style Email Entry Field
We will be creating a Gmail Style Email Entry Field, which means we will be creating a type ahead style combo box and a few other features as well.
For those that have been living under a rock and haven’t seen the Gmail interface. Here’s a brief description and feature list:
It start’s out blank of course.
As you type, a list appears (emulating a combo box) with addresses that match your entry.
Notice as you continue to type, the list filters further. There are also a few subtle features on display here.
- This list only displays the top 6 matches
- It uses “begins with” matches first. Notice in the screen shot with just “a” all begin with “a”
- If it doesn’t get six then it uses, “contains” matches. Notice in the second screen shot with “al”, firstname.lastname@example.org and Mike Alexander are now on the list.
- If it still doesn’t get six then it repeats the steps 2 and 3 using the email address field instead of the name field.
When you select an entry it adds the entry to the “To” field similar to a button, which allows you to remove the entry by clicking on it.
That’s a tall order and a far cry from the old pcReminder interface so let’s get started.
First some foundation stuff, I am using classes for this project, there for my address book is already loaded into an array. I am certain this function would be far to slow if trying to do direct file access, so how ever you accomplish it the first step is to get the address book into a structured array. Once that is done it preforms very well, I have 485 entries in my test address book and there is absolutely no describable speed issues. This is accomplished by doing all the comparisons via an array so it is all in memory, and also by limiting the number of matches shown (10 in my case). It stands to reason that the larger your dataset, the more matches there will be and as soon as you get your 10 matches the routine ends.
We will get to the screen design later, but for now now that the screen consist of
- An entry field for the input
- A Looper to display the matches
- A cell to emulate a combo box around the matches
- A Looper to display the selected Address, including a “delete” button
- A cell to contain the Looper of selected Addresses. There are a few import settings on these last two that we will cover, when we discuss the screen design later.
Here is a screen shot at design time.
And here is the screen at run time with some selections already made.
So now lets look at the function that does all the heavy lifting of finding the matches.
First notice that the function is AJAX enabled (the icon is green). We will be calling this function from the browser code of the entry field, and since there is quite a bit of this code that would not be allowed in browser code we are going to use AJAX to execute it on the server.
The function accepts one parameter, which is the text that has been typed into the entry control.
LoopAddressSearch is a list of matches and we start out by clearing it on Line 3
Next we declare a few variables: FoundCount so we can keep track of the number of matches found, NumberofEntriesToDisplay so we can adjust from the limit from 10 to whatever without changing any other code, X will be used to keep track of which of the 4 loops the code is currently executing, and ComprassionField is used to hold the field (name or email) we are comparing so the code can be a little more generic.
At line 9 we start a WHILE loop that will continue until we get our 10 matches, or we forceably BREAK out of it.
At line 10 we increment X, so we know that the first two loops are for Name matchings and the second two loops are for Email matching.
Line 11 is a FOR loop that loops through all of the entries in the array. Again there are a lot of ways for you to structure the array and get your data into it, and I won’t be covering that in this article
Line 13 is a feature that apparently Goggle didn’t think of, so now my code is better than theirs <G>. Once an address as been selected, in no longer makes sense to show it in the matching list anymore, you don’t want to add the same person twice. So the code is looking in the array that contains all of the selected addresses for this reminder and if it finds a match it CONTINUEs the loop, meaning it jumps back to the top and starts with the next entry in the array.
Line 16-20 moves the correct field into the ComparisonField variable based on the value of X. Again 1 and 2 is Name, 3 and 4 is Email.
Line 21 again uses X to determine which loop we are in. However this time if it is loop 1 or 3, then we perform the “Begins with” code, otherwise we perform the contains code.
Line 22 uses a special operator to test if the ComparisonField starts with the value from the entry field, while ignoring case.
If there is a match Line 23 adds the match to the looper and Line 24 increments the FoundCount.
Line 27 uses Contains to see the value of the entry field is anywhere in the ComparisonField, ignoring case. Lines 28 and 29 add matches to the array and increment the FoundCount.
Line 32 BREAKs out of the FOR loop if we have reached our 10 matches, and since the outer loop is a WHILE loop it will also end.
Line 36 checks to see if we have completed all four loops and forceably BREAKs out of the WHILE loop if we have.
And Finally at line 41 we return the FoundCount value to the caller.
It takes way longer to explain it than it does to execute it!!!
We are going to call the function from the “Key up” browser event of the entry field.
We are using “Key up” because we want this to be “on the fly”. “Exit with modification” only fires when you leave the field, and “Key Press” fires before the entry field has been updated with what was typed.
Line 1 uses AJAXExecute to call the procedure we just wrote passing in the value of the entry field. AJAX function can only return string values, so just to be safe we use the Val function to insure we do a numeric instead of character comparison. If our function found any matches it returns the count, and the cell that emulates the combo box is made visible, and we refresh the Looper by pressing a hidden button.
We have to use a hidden button because LooperDisplay is a server function and can’t be executed by Browser code. You may be thinking to yourself, why not just refresh the Looper inside the Search function. That does not behave as expected. When your code is executed via AJAXExecute, changes to screen controls are not displayed. You must refresh them outside of the AJAX Execute code.
If no matches were found the the cell is hidden.
btnRefreshAddressBookLooper is a hidden button, that only has one line of code in it to refresh the Looper. Notice this is AJAX enabled. This is different than AJAXExecute and the Looper will be refreshed. If this button were not AJAX enabled the entire page would reload.
Let’s look at cellAddressBookEntries next. That is the cell that contains the matches Looper and emulates a combo box.
There are two key settings for this cell. First it is marked as not visible when the page first opens and it is marked as “can be overlaid”. The overlaid setting is required so the position of the cell can be adjusted, and it can be displayed over the top of other controls without the browser moving the controls around.
There are also a couple of lines of code in the “onload” browser event for this cell. The last two lines move the cell so it is positioned under the entry control, again this emulates a combo box. The cell could be position there at design time, but that would be a PITA when working on the screen, so I position it off the screen and then move it at run time.
The loopAddressSearch looper contains one control, a link control. Both browser and server code is executed when this link is clicked
First the browser code clears the entry field, and hides the cell, emulating a close of the combo box.
The server code adds the selected entry to entry to the array of selected addresses and then refreshes the loopArrAddresses which is the looper containing the selected addresses. Again this code is AJAX enabled so we don’t get a screen refresh.
The Looper itself has two attributes, the name which is what is displayed for the link, and the addressbookID which is the pointer to the address book entry. The Looper is filled by programming, and we already saw the code that does that in the search function.
That brings us to the most complicated part of the page design, and will show off some really impressive WebDev features. And that is the looper with variable number of columns and variable column widths. We will cover that in Part 2 next week.
Be sure to go over to wxLive.us and watch the Uncle Pete’s corner webinar that is the companion to this article.
Uncle Pete’s Corner is weekly webinar on all things WX every Friday 7:15 AM CST (5:15 PST), to watch the recorded version of this webinar, many other WX related webinars or to watch future ones live go to wxLive.us