This was an interesting question sent to me by Joel:
I have a text input that it used for a search criteria, and I only want to enable the search button when at least 5 characters have been entered. (The list of possible matches is huge, and I don't want 25,000 results returned to the browser.)Apparently dealing with a browser's autocomplete isn't quite as simple as one would think. I did a quick example to prove this (and I wanted a non-jQuery UI one to test):
Suppose the text input is called "searchBox". With jQuery, I can do this:
$("#searchBox").keyup(function() {
$("#btnGo").button("option", "disabled", $(this).val().length < 5 );
});
(It's a jQuery UI button, which is why the syntax for enabling is different from a normal button).
Most browsers keep a form input history. So If I start to type "apple" and I've typed it before, I can just click and choose it from the list. This does not fire the keyup event. I can bind "change" also, but that only fires when the input loses focus. Any thoughts on how to bind the selection of form history to enable the button?
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("#search").keyup(function() {
$("#searchBtn").attr("disabled", $(this).val().length < 5 );
});
})
</script>
</head>
<body>
<form action="test.html" method="post">
<input type="text" name="search" id="search"> <input type="submit" value="Search" id="searchBtn" disabled="true">
</form>
If you run this (online demo here) and enter a few values, you should be able to see the "manual" approach work, but as soon as you use something from the browser's autocomplete history, it doesn't register. In my initial Google search, the first result I found suggested simply turning it off. That's doable but not exactly a solution. What about using the change handler?
$("#search").change(function() {
$("#searchBtn").attr("disabled", $(this).val().length < 5 );
});
That works - but not immediately. The user has to click elsewhere to register the change. After a bit more searching I found this comment on the jQuery docs for change. The user, Robin, mentioned listening for a new HTML5, input. (This was the first time I'd heard of this. I thought I knew about all the HTML5 Form stuff. Guess I was wrong. Looks to be documented here.) I gave this a try:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("#search").keyup(function() {
$("#searchBtn").attr("disabled", $(this).val().length < 5 );
});
$("#search").live("input",function() {
$("#searchBtn").attr("disabled", $(this).val().length < 5 );
});
})
</script>
</head>
<body>
<form action="test.html" method="post">
<input type="text" name="search" id="search"> <input type="submit" value="Search" id="searchBtn" disabled="true">
</form>
You can demo this one here. Good news! Works in Chrome. Works in Firefox. Works in - oh crap. Not IE. Since apparently IE9 doesn't support anything Form-related in HTML5. sigh At this point, I'm willing to just give up on IE and just use "change" - as I said, it doesn't work immediately, but by this point, IE users are probably used to a substandard experience. Here is the "final" template I used.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("#search").keyup(function() {
$("#searchBtn").attr("disabled", $(this).val().length < 5 );
});
$("#search").change(function() {
$("#searchBtn").attr("disabled", $(this).val().length < 5 );
});
$("#search").live("input",function() {
$("#searchBtn").attr("disabled", $(this).val().length < 5 );
});
})
</script>
</head>
<body>
<form action="test.html" method="post">
<input type="text" name="search" id="search"> <input type="submit" value="Search" id="searchBtn" disabled="true">
</form>
You can try this demo here. So - does anyone have a nicer solution?
Archived Comments
Yes - I'm commenting on my own blog post. ;) One idea that occurred to me - you could use a setInterval to check the field length every second. It shouldn't be too processor heavy I think to do so. It feels kinda hacky, and it would not be "instant", but it would be darn close.
For folks curious I uploaded a version here:
http://www.coldfusionjedi.c...
It uses a interval of 400 ms.
I believe you can add autocomplete="off" to the input text tag.
Errrr right. I said that. ;) But it's not a "solution" though.
Ah, my bad for not reading throughly! ;)
I'd be tempted to turn off autocomplete and provide links above for X number of recent searches.
Here's a suggestion that kind of side-steps the question, but I think it accomplishes the underlying task. How about instead of disabling the submit, wait until submit and then check to see how many characters have been entered? If enough, allow submit to continue, otherwise prevent it. Granted, the experience is slightly different (wouldn't provide a visual indicator that submit is enabled) -- but pretty close.
Maybe if you did a combination of the two approaches you could cover your browser bases.
That's not a bad suggestion Ben.
Thanks for all of the suggestions. Ultimately, I'm going to do an AJAX post ($.post), so they're probably won't end up being a form history anyway. I ran into this once before on a different project and thought I'd bring it up since I didn't find a good solution the first time, either.
I agree with Ben, but if you really want to think of another alternative, you can also fire the function with the onblur event from the input text box. If so, the function should be fired before the user could get the chance to press the submit button.
From a UX viewpoint this wouldn't be ideal without some sort of visible explanation. Quite frustrating seeing buttons and not knowing why you can't click them.
Good point. My demo was pretty minimal but a real form should have had that type of explanation.
A solution for IE is to use the "onpropertychange" event.
$("#search").bind("propertychange change", function() {
$("#searchBtn").attr("disabled", $(this).val().length < 5 );
});
http://msdn.microsoft.com/e...
Michael - kick butt. That _did_ work. I can confirm it. In IE9 at least.
I have an alternative solution that seems to work in all browsers for auto-complete that uses the fact that the auto-complete window is considered outside the DOM in all browsers I have tested.
$(document).mouseenter(function(){
$("#searchBtn").attr("disabled", $(“#search”).val().length < 5 );
The mouse will have to move after clicking before it update for it to register being back in the document but since even the slightest mouse move will cause it to update I dont see this being a issue.
Note: The keyup function works in cases where the user chooses auto-complete option using the enter key instead of the mouse. This is becuase autocomplete updates on keydown but for mouse require a click.