jQuery UI Autocomplete behaviour. How to search free text on enter? - javascript

first question (and hopefully, but doubtfully my only one)
I'm using the jQuery UI Autocomplete. Here is sample code to replicate my issue.
var suggestions = ["C", "Clojure", "JavaScript", "Perl", "PHP"];
$("#autocomplete").autocomplete({
source: suggestions
});
When a user types 'J' they will be presented with 'Clojure' and 'JavaScript' as suggestions.
I have omitted Java from this list, if the user wants to search for Java, they type 'Java', press the enter key but the form does not submit. If you add a space the 'JavaScript' suggestion disappears and the form can be submitted by pressing the enter key.
I am creating a free search, I want users to be able to search by pressing enter even if there are suggestions available.
$("#autocomplete").keypress(function(event) {
alert(event.keyCode);
if (event.keyCode=='13') $this.closest('form').submit();
});
I tried the above thinking I could manually detect a submit keypress and submit the form, but the alert shows all keys are detected EXCEPT submit which seems to be suppressed by the autocomplete.
Any help is greatly appreciated! Thanks.

UPDATE
I had to make a few changes, but this code works fine on my side after doing that. First, e.keycode should be e.keyCode. I didn't think the case mattered, but it does. Also, make sure you are not quoting the 13 when you check for the keyCode to be the enter button. It will not work correctly if you do so. Here's the new code:
var suggestions = ["C", "Clojure", "JavaScript", "Perl", "PHP"];
$("#autocomplete").autocomplete({
source: suggestions
}).keypress(function(e) {
if (e.keyCode === 13) {
$(this).closest('form').trigger('submit');
}
});
The keypress function should look like below, and also, you can chain the autocomplete and keypress functions to make it easier on you. Below code should work.
var suggestions = ["C", "Clojure", "JavaScript", "Perl", "PHP"];
$("#autocomplete").autocomplete({
source: suggestions
}).keypress(function(e) {
if (e.keycode === 13) {
$(this).closest('form').trigger('submit');
}
});

I had a similar problem, the jquery-ui autocomplete widget fires the select event when the user selects a suggestion from the list, whether the selected suggestion was clicked or the enter key was pressed. But it did nothing if the user typed text and pressed the enter key without selecting an item from the list. When that happens, I need to do a search.
It was easy to add a keypress event handler, but it fired whether a selection had been made or not. So I added a variable, didSelect, to maintain the selection state.
Here's the complete solution:
$(function() {
var didSelect = false;
$( "#search" ).autocomplete({
source: "/my_remote_search",
minLength: 2,
search: function (event, ui) {
didSelect = false;
return true;
},
select: function( event, ui ) {
if (ui.item) {
didSelect = true;
my_select_function(ui.item);
}
}
}).keypress(function(e) {
if (e.keyCode == 13) {
if ( ! didSelect ) {
my_search_function( $("#search").val() );
}
}
});
});

Using the UI Autocomplete plugin version 1.8.5:
Look for this bit of code
"case d.ENTER:case d.NUMPAD_ENTER:a.menu.element.is(":visible")&&c.preventDefault();"
and remove or comment it out.
Essentially what was said above but from the current version of the plugin.
cheers
Pete

This is what I did
<div class="ui-widget">
<form action="javascript:alert('hey run some javascript code')">
<input id="search" />
</form>
</div>

Autocomplete supresses submit but this worked as a workaround for me:
jQuery.fn.go_url = function(id) {
var url="gl10.pl?ar=2010&listi=ts&niv=stovnsnr&rl=1290693052914&stovnsnr=replaceme";
var ok;
if (ok=id.match(/^\d{6}$/)) {
url=url.replace(/replaceme/g,id);
location=url;
}
}
jQuery(function() {
jQuery( "#stovnar" ).autocomplete({
source: "autocomplete.pl?pname=stovnsnr",
minLength: 3,
select: function( event, ui ) { if (ui.item) { jQuery.fn.go_url(ui.item.id); } }
});
}).keypress(function(e) {
if (e.keyCode === 13) {
v=jQuery("#stovnar").val();
jQuery.fn.go_url(v)
}
});

I had the same problem, and was thinking of using validation to accomplish this, but in the end my solution looks a whole lot easier than other solutions on this page:
Make an input field to type the text in, named #input and a hidden input named #hiddeninput. Your search-backend will have to use the value for #hiddeninput.
Inside your autocomplete, set the value of #hiddeninput to request.term: (I set this inside $.ajax({ success: }) )
$("input#hiddeninput").val(request.term);
Set the autocomplete with the select:-method to fill the hidden input with the suggestion that is chosen:
select: function( event, ui ) {
$("input#input").val(ui.item.label),
$("input#hiddeninput").val(ui.item.nr),
//Auto-submit upon selection
$(this).closest("form").submit();
}
Now your search will be performed on what the user has typed until he selects something from the suggestions-list.

<script>
$(function() {
$('#student').autocomplete({
source: '../ajx/student_list.php',
minLength: 3,
response: function( event, ui ) {
$('#student_id').val(ui.content[0].id);
},
select: function( event, ui ) {
$('#student_id').val(ui.item.id);
$(this).closest('form').trigger('submit');
}
}).keypress(function(e) {
if (e.keyCode === 13) {
$(this).closest('form').trigger('submit');
}
});
});
</script>
<div>
<form action='../app/student_view.php'>
<input name='student_id' id='student_id' type='hidden' value=''>
<label for='student'>Student: </label>
<input id='student' />
</form>
</div>
Here I used autocomplete to search for a student. If the user pressed ENTER, the form would submit, even if nothing was selected from the list. The 'response' event would update the value of a hidden input field with the first item in the list. They could also click or select from the list.

Related

jQuery keyup should should trigger enter key

I have a simple problem (hopefully), but I am unable to find a clear solution.
I have a datatable, which has a text input field. The user enters text into the text field, and hits the enter key. This automatically filters from the text entered.
I was hoping to use the onkeyup event to trigger so when a user enters a value in the text field, the datatable automatically updates, rather than the user having to press enter.
<input type="text" name="input" class="filter" id="input" onkeyup="functionName(this)" value="">
<script>
function functionName(e) {
alert(e.value);
}
</script>
This code works, so when I enter a value, it pops an alert up displaying the entered value.
Is it possible i can change the alert, to do a submit, or replicate what the "enter" key does.
From trying to find a solution, it is more difficult because it is not a form, as it uses ajax so the .submit methods will not work.
I was also hoping a solution like this could work
<script>
var e = jQuery.Event("keyup");
e.which = 13; // Enter
$("#input").trigger(e);
</script>
I know there are many similar topics, and I have looked, but none of them seem to be the right solution for me.
Thanks for the help.
//
Edit
//
Based on the keyup issue, how can I refocus cursor after filtering. Is this done at the same time as filtering?
$obj.find('input.filter').on('keyup',function(e){
e.preventDefault();
ajax($obj);
});
You're using jQuery, so there's no real need to use onclick="", Secondly try to avoid to use reserved names for IDs & Classes (e.g. #input). Lastly, you can mimic the form submission by using $.post() on each .keyup event like below:
<input type="text" name="input" class="filter" id="searchinput" value="" />
<script>
$(document).ready(function() {
$(document).on('keyup', '.filter', function( event ) {
$.post( 'yourapi.php', { input: $(this).val() }, function( data ) {
//Refocus the <input />
$('#searchinput').focus();
});
});
});
</script>
As you can code in jquery too. Then you can go with this code......
$(document).ready(function(){
$(".filter").keyup(function(){
var text_input_text = $(this).val();
//here is your ajax post request
$.post('url for post', {filter_text: text_input_text}, function(response){
console.log(response);
});
});
});
Here we have covered the keyup event and ajax post.
Hope this will help you.
$(document).ready(function(){
$("input").keyup(function(event)
{
var keycode = (event.keyCode ? event.keyCode : event.which);
if(keycode != '13')
{
var e = jQuery.Event("keyup");
e.which = 13; // Enter
$("input").trigger(e);
}
else {alert("Enter triggered");
}
});
});
DEMO JSFiddle

Modify jQuery autocomplete not to submit eagerly on Enter

Our users complain that when they press the enter key after pasting or typing values in a jQuery autocomplete widget the form is submitted.
It's extremely annoying them when they copy-paste a value that exists in the autocomplete options the autocomplete widget opens to show that single value, they press Enter to accept that value but then the form is submitted before they finished filling all the fields because (by default and we don't want to change it) the widget won't select the first option in the menu.
<form>Type C and press Enter:
<input id="autocomplete" />
<input type="submit" value="submit" />
</form>
$('form').submit(function () {
alert('You submitted the form');
return false;
});
$('#autocomplete').autocomplete({
source: ["c#", "c", "c++", "java", "php", "coldfusion"]
});
DEMO of the problem
How can we change that clicking Enter will only close the autocomplete suggestions?
It seems like jQuery UI didn't left a backdoor to customize the widget out of the box, so what you can do is override the autocomplete function to register a callback for the onkeypress event, capture the Enter and stop the propagation so it won't submit the form if the widget is open=visible.
Here how it goes:
function cancelAutocompleteSumbission(e) {
// Make sure this is a nodeElement and the button pressed was Enter-Return
if (!this.nodeType || e.which != 13)
return;
// If the widget is visible we simply want to close the widget.
if ($(this).autocomplete('widget').is(':visible')) {
$(this).autocomplete('close');
return false;
}
}
// Making a private scope to avoid naming collision.
$.fn.autocomplete = (function () {
// Cache the old autocomplete function.
var oldAutocomplete = $.fn.autocomplete;
// This will be the new autocomplete function.
return function () {
// If the first argument isn't "destroy" which
// should restore the input to it's initial state.
if (!/^destroy$/i.test(arguments[0]))
// Attach event to the input which will prevent Enter submission as
// explained above.
this.keypress(cancelAutocompleteSumbission);
// We need to restore the input to it's initial state,
// detach the keypress callback.
else
this.off('keypress', cancelAutocompleteSumbission);
// Call the cached function with the give "this" scope and paramteres.
return oldAutocomplete.apply(this, arguments);
};
})();
Live DEMO
Notes:
To change all the autocomplete widgets you need to use jQuery's prototype, $.fn is an alias to $.prototype.
Also you need to change $.fn.autocomplete before you use it it or the changes you made won't apply to those widget.
this inside the autocomplete function is actually a jQuery object so you don't need to wrap it with $(this)
You might say, Hey you keep register the very same callback for the keypress event. Well, that's exactly what I'm doing and why I wrote the callback as a named function. If you pass the same callback to addEventListener it will register it only once. MDN, Specifications
Adding code to a javascript function programmatically
I might have a simpler solution by using jQuery autocomplete's autocompleteclose and autocompleteopen events.
See the code below:
var flag = 0; //global variable
$("#autocomplete").on({
autocompleteclose: function (event, ui) {
flag = 1;
//set flag back to 0 with a short delay so the next keypress can submit form
setTimeout(function () {
flag = 0;
}, 100);
},
//if the autocomplete widget is open, don't submit form on keypress
autocompleteopen: function (event, ui) {
flag = 1;
}
});
$('body').keypress(function(e) {
if (e.keyCode == '13') {
if (flag != 0) {
e.preventDefault();
} else {
//submit form
}
}
});​
var flag = 0; //global variable
$("#autocomplete").on({
autocompleteclose: function (event, ui) {
flag = 1;
//set flag back to 0 with a short delay so the next keypress can submit form
setTimeout(function () {
flag = 0;
}, 100);
},
//if the autocomplete widget is open, don't submit form on keypress
autocompleteopen: function (event, ui) {
flag = 1;
}
});
$('body').keypress(function (e) {
if (e.keyCode == '13') {
if (flag != 0) {
e.preventDefault();
} else {
//submit form
}
}
});
$('form').submit(function () {
alert('You submitted the form');
return false;
});
$('#autocomplete').autocomplete({
source: ["c#", "c", "c++", "java", "php", "coldfusion", "javascript", "asp", "ruby"]
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script src="//code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<link rel="stylesheet" type="text/css" href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
<form>Type C and press Enter:
<input id="autocomplete" />
<input type="submit" value="submit" />
</form>
I was somehow against overriding the jqueryui implementation and did the following:
in the close event of the autocomplete i set a flag "doNotSubmit" when enter was pressed
in your case then i'd bound a submit event listener to the form which checks the doNotSubmit flag and acts accordingly.
The basic idea behind it, is that jqueryui's close event is triggered before keyup or submit events and gives you the keycode. So you can in another place (keyup, submit, etc.) consume that one unwanted enter or other keypress.
This question is similar to this one. While the solutions on that page are straight forward, they depend on the ID's of elements on the page. I use autocomplete on lots of pages so I prefer gdoron's approach (on this page). Thanks to him for doing the heavy lifting.
However, I think there is a bug in his code. If you go to an autocomplete field that already has content and type a return, it will submit the form. Here is a fix (the change is the second "if block in cancelAutocompleteSumbission):
function cancelAutocompleteSumbission(e) {
// Make sure this is a nodeElement and the button pressed was Enter-Return
if (!this.nodeType || e.which != 13)
return;
if (!$(this).autocomplete('widget').is(':visible') && e.which === 13){
return false;
}
// If the widget is visible we simply want to close the widget.
if ($(this).autocomplete('widget').is(':visible')) {
$(this).autocomplete('close');
return false;
}
}
// Making a private scope to avoid naming collision.
$.fn.autocomplete = (function () {
// Cache the old autocomplete function.
var oldAutocomplete = $.fn.autocomplete;
// This will be the new autocomplete function.
return function () {
// If the first argument isn't "destroy" which
// should restore the input to it's initial state.
if (!/^destroy$/i.test(arguments[0]))
// Attach event to the input which will prevent Enter submission as
// explained above.
this.keypress(cancelAutocompleteSumbission);
// We need to restore the input to it's initial state,
// detach the keypress callback.
else
this.off('keypress', cancelAutocompleteSumbission);
// Call the cached function with the give "this" scope and paramteres.
return oldAutocomplete.apply(this, arguments);
};
})();
Live Demo

jQuery UI autocomplete suddenly stopped working

I have simple jQuery UI autocomplete, which was working and now it's not. The code is as follows:
<html>
<head>
<script type="text/javascript" src="js/jquery-1.8.0.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.8.23.custom.min.js"></script>
<script type="text/javascript">
$(function() {
$( "#city" ).autocomplete({
source: function( request, response ) {
var cities = new Array();
cities.push({"label" : "Chicago", "value" : 1});
cities.push({"label" : "Houston", "value" : 2});
response(cities);
},
focus: function(event, ui) {
//console.log(ui.item.label);
$(this).text(ui.item.label);
//console.log($(this).text());
event.preventDefault();
//console.log($(this).text());
},
select: function(event, ui) {
//console.log($(this).text());
event.preventDefault();
//console.log($(this).text());
}
});
});
</script>
</head>
<body>
<input id="city" />
</body>
</html>
I am using the focus handler to show the label in the textbox instead of the value (which is what the autocomplete does by default). What is happening now is that the textbox is showing neither label nor value, it is showing the value that I have typed (say 'Chi')
This was working but now it's not. I thought it was because I had included some other javascript and there was a function name clash. But I moved it to a separate HTML as you can see above and it's still not working.
BTW if I uncomment those console log statements and from the dropdown I select Chicago, then all of them print Chicago.
This seems like some silly mistake somewhere but has me stumped. Any suggestions?
EDIT 1: BTW, if I remove the focus and select handlers then the autocomplete works with its default functionality.
EDIT 2: Would be great if someone can test this on their own computer
There are a couple of changes from default functionality which you appear to be attempting here.
You would like the "completed" variable to be previewed in the main input when it is selected
You would like the label, not the value, to be shown when a selection has been made.
The reasons that neither of these are currently working are related and simple: <input> fields only have a value associated with them, not a separate "label" and "value". When you select an "autocomplete" option from the list, it is the "value", which gets filled in.
For point 1, the part which is being updated by the focus: event, just replace .text(...) with .val(...), as that is the attribute of the <input> field which you actually want to update:
focus: function(event, ui) {
$(this).val(ui.item.label);
event.preventDefault();
},
For point 2, as you actually want the field to be filled in by the label, not the value, you could just fill in the same text for both (the default if a flat array is given):
source: function( request, response ) {
var cities = new Array();
cities.push("Chicago");
cities.push("Houston");
response(cities);
},
Remember that autocomplete is always optional. All you need to fill in for the value: is something which you back-end can fully disambiguate. That could be an id, but it usually makes sense to use something which the user might have typed in on their own. Of course, if you're doing that, it may also make sense to use ui.item.value instead of ui.item.label in the focus: event, as well.
With the source made sane as above, you can drop the select: event entirely.
I think the problem lies in the assignment of the autocomplete source. This works for me:
$(function() {
var cities = [
{"label": "Chicago", "value": 1},
{"label": "Houston", "value": 2}
];
$( "#city" ).autocomplete({
source: cities, // assign the source directly
focus: function(event, ui) {
//console.log(ui.item.label);
$(this).text(ui.item.label);
//console.log($(this).text());
event.preventDefault();
//console.log($(this).text());
},
select: function(event, ui) {
//console.log($(this).text());
event.preventDefault();
//console.log($(this).text());
}
});
});​
here's a fiddle

jQuery UI Autocomplete

I am using jQuery UI's autocomplete plugin and everything is well and good except for that fact that when a user clicks the value they want the function I have assigned to the "select:" method fires before the value of the field is changed. So if I type "Foo" in the input field, then click the autocomplete match for "Foo Bar" the function detects the value as what was typed (in this case "Foo") as opposed to the value which was selected from the autocomplete list. Once the function fires (in this case I just have an alert box popup with this.value) the value of the input field is set to the value selected via the autocomplete list. This problem does not occur if the user selects the option with the keyboard (arrow keys->tab), only when the mouse is used.
$(function()
{
var aEmps =
[
<?php
echo $sEmps;
?>
];
$("#slast").bind( "keydown", function( event ) {
if ( event.keyCode === $.ui.keyCode.TAB &&
$( this ).data( "autocomplete" ).menu.active )
{ event.preventDefault(); }
})
.autocomplete({
source: aEmps,
select: function(event, ui)
{
var aName = $(this).val();
alert(aName);
}
})
});
Since most users will be interacting with this using their mouse I have to find a way to get the value set before firing the "select:" function. I believe I can accomodate for this by adding a condition to the statement prior to the auto complete but I need some help finding the right syntax.
Looking at the documentation, it looks like the select event is fired as the selection is being updated, not after the selection is updated. Try using the change event instead of select, and see if that solves your problem.
After trying a number of approaches I found that by simply binding the callback function to the close event works very well. I added some error handling to catch values that aren't selected from the list and I am off and running!
Here is the updated code:
$(function()
{
var aEmps =
[
<?php
echo $sEmps;
?>
];
$("#slast").bind( "keydown", function( event ) {
if ( event.keyCode === $.ui.keyCode.TAB &&
$( this ).data( "autocomplete" ).menu.active )
{ event.preventDefault();}
})
.autocomplete({
source: aEmps,
close: function(event, ui)
{
alert(this.value);
}
})
});

Customised jQuery autocomplete

I have a customised jQuery autocomplete control that is declared something like this.
$('#SystemCode_Autocomplete').autocomplete({
source: [{"label":"Access","value":0},{"label":"Documentum","value":0}], //move values
minLength: 1,
change: function(event, ui) {// some function},
select: function(event, ui) {// some function}
});
The change and select events are custom.
The problem is if I type something into the textbox then click the submit button (i.e. no tab out, or lost of focus), or if I press the key to submit after typing into the text box, the change event isn't fired and it has to be before I submit.
I was hoping to do it without putting javascript behind the submit button, and to ideally do it from within the autocomplete control itself. I tried adding the change to the blur event.
${'foo').blur(function() { $('bar').trigger('autocompletechange');
// or
${'foo').blur(function() { $('bar').change();
But none of them have worked, anyone have any ideas?
You can try something like this:
$('#SystemCode_Autocomplete').autocomplete({
source: [{"label":"Access","value":0},{"label":"Documentum","value":0}], //move values
minLength: 1,
change: function(event, ui) {/* some function */},
select: function(event, ui) {/* some function */}
}).each(function(){
var self = $(this).closest("form").submit(function(e){
self.trigger("change");
// you may not need anything like this...but whatever
if(!functionToCheckIfFormIsValid()){
e.preventDefault();
}
});
});
focus function autocomplete
Before focus is moved to an item (not selecting), ui.item refers to the focused item. The default action of focus is to replace the text field's value with the value of the focused item, though only if the focus event was triggered by a keyboard interaction. Canceling this event prevents the value from being updated, but does not prevent the menu item from being focused.
Solve the problem:
$('#SystemCode_Autocomplete').autocomplete({
source: [{"label":"Access","value":0},{"label":"Documentum","value":0}], //move values
minLength: 1,
focus: function( event, ui ) {
return false;
},
select: function(event, ui) {
alert('Select Event:'+ui.item.value);
}
});
So your problem is that you have to make sure that action a occurs before action b and you're having trouble reconciling that between two event handlers? That actually sounds like a pretty common UI problem, not something that's limited to jQuery.
How would you solve it in any other circumstance? What if I suggested you to use the jQuery data object to attach to the element and then do some sort of semaphore checking in each method, like setting a flag in the one method, and in the other method checking to see if the flag is set?
That's how I would do it, were it me.
DEMO: http://ask.altervista.org/demo/jquery-autocomplete-help/
$(function() {
var json = [{"label":"Access","value":0},{"label":"Documentum","value":0}];
$('#SystemCode_Autocomplete').autocomplete({
source: function( request, responce ) {
responce( $.map( json, function( item ) {
return { id: item.value, label: item.label, value: item.label }
}));
$.each( json, function( i, item ) {
if ( request.term.toLowerCase() == item.label.toLowerCase() ) {
// do something here, ex.: AJAX call or form submit...
$('#submit_button').click();
}
});
},
minLength: 1,
change: function(event, ui) { /*alert(ui.item.label + ' ' + ui.item.id)*/ },
select: function(event, ui) {}
});
});
Ok I completely for to update this to what we actually did to get it to work.
Basically we editted the autocomplete .js file to get it to do want we wanted.
Specifically we added our own options to the autocomplete then we editted the _response method to something like this
_response: function (content) {
if (content.length) {
content = this._normalize(content);
this._suggest(content);
this._trigger("open");
this.options.isInError = false;
this.element.removeClass("input-validation-error");
} else {
this.close();
if (this.element.val() == '') {
this.options.hiddenField.val('');
} else {
this.options.hiddenField.val('-1');
}
if (this.options.mustBeInList) {
this.options.isInError = true;
this.element.addClass('input-validation-error');
}
}
this.element.removeClass("ui-autocomplete-loading");
},
That way we know if the User is entering "rubbish" as they type and the controll goes red and into an "error"mode. To stop them from posting back we do this
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
// when menu is open or has focus
if (self.options.isInError == true) {
return false;
}
if (self.menu.element.is(":visible")) {
event.preventDefault();
}
//passthrough - ENTER and TAB both select the current element
case keyCode.TAB:
if (!self.menu.active) {
return;
}
self.menu.select(event);
break;

Categories

Resources