jQuery keypress() handler: managing flow of events
I've got some jQuery code to focus a <select>
dropdown based on user input, as per a previous question. Here it is:
HTML
<select id="poetslist">
<option value="shakespeare" data-initial="WS">William Shakespeare</option>
<option value="milton" data-initial="JM">John Milton</option>
<option value="keats" data-initial="JK">John Keats</option>
<option value="wordsworth" data-initial="WW">William Wordsworth</option>
<option value="larkin" data-initial="PL">Phillip Larkin</option>
</select>
JavaScript
$("#userlist").keypress(function (e) {
initials += String.fromCharCode(e.which).toUpperCase();
//开发者_JAVA百科 when the relevant initials are typed, select that item
$(this).find("option").filter(function () {
return $(this).attr("title").toUpperCase().indexOf(initials) === 0;
}).first().attr("selected", true);
$('#book_results').html(loading_img); // Show 'loading' gif
// Then use get_books function to update some HTML on the page with relevant info
get_books($(this).find("option").filter(function () {
return $(this).attr("title").toUpperCase().indexOf(initials) === 0;
}).first().val(), null, null);
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(function () {
timer = null;
initials = "";
}, 2000); // Max 2 second pause allowed between key presses
return false;
});
It's very promising, but I'm finding that when the user types e.g. 'WW', "William Shakespeare" is selected first, and all the HTML on the page updates for him, and only after a couple of seconds does the dropdown 'catch up' and update for "William Wordsworth".
I'm certain that this is my fault for not handling the flow of events correctly, but could anyone suggest a fix? N.B. I can't guarantee that every item will have two initials.
Thanks for helping out a JavaScript novice!
I'm not sure I understand what you wanted, and I'm pretty sure I didn't understand the code, so I answered anyway, hoping it will help you with your problem...
I wrote a small code that will do the first thing you wanted: Selecting the write element.
<body>
<input type="text" id="userlist" />
<select id="poetslist">
<option value="shakespeare" data-initial="WS">William Shakespeare</option>
<option value="milton" data-initial="JM">John Milton</option>
<option value="keats" data-initial="JMI">John Keats</option>
<option value="wordsworth" data-initial="WW">William Wordsworth</option>
<option value="larkin" data-initial="PL">Phillip Larkin</option>
</select>
<script type="text/javascript">
$("#userlist").keyup(function (e)
{
var initials = $("#userlist").val().toUpperCase();
if (initials.length < 2)
return;
$("#poetslist option").each(function ()
{
if ($(this).attr("data-initial") == initials)
{
SelectOptionEtc($(this));
}
});
});
function SelectOptionEtc(optionElement)
{
$(optionElement).attr("selected", true);
}
</script>
</body>
Now documentation:
First I changed the trigger to "keyup". The reason I don't like "keypress" is that it's not clear if it's before or after the event was fired. and since "keydown" happens before you actually write the letter - it was no good for me.
Second, I used the input text. I could have save the letters every time in a variable but this is wrong for couple of reasons: 1.+= is the worst thing you can do. specially in JS. specially if the initials can be 4-5 letters. if anything, I would use ".push". 2. what about delete? or backspace? you should have consider these and remove the letter the user wishes to remove. too messy for me.
Third, although using "filter" and "find" and all these other jQuery methods is nice, I prefer to keep it as simple and neat as I can.
Fourth, All of your other code should go to a different function. Keeping it all under the same place is... well... not my style.
BTW
As you can see, in order not to do unnecessary actions, I placed a condition saying the minimum length is 2 letters.
Hope it helped, Elad.
My Development Blog
精彩评论