UPDATE
With the help and suggestions taken from the @Ziv Weissman and @Fribu I re-wrote the whole autocomplete function.
If anybody needs it he/she can download from here.
Thanks StackOverFlow community.
I am creating a jquery autocomplete function. The function that I created is working fine with single text box. But as soon as I am implementing it on another text box in same page it is behaving unexpectedly. It opens and closes the autocomplete list.
here is my code for autofill.js:
function setUl(result) {
var $ul = $('<ul>');
if (result !== undefined) {
$.each(result, function (k, v) {
$ul.append('<li data-value="' + v.value + '">' + v.label + '</li>');
});
}
return $ul;
}
$.fn.autofill = function (options) {
if (options == undefined) {
options = {};
}
var $currentInput = $(this);
var autoCompleteData = $currentInput.data('autofill');
var listId='autofill-' + (new Date().getTime()).toString(16);
$currentInput.on('keyup focus', function (e) {
var query = $(this).val();
var result = $.grep(autoCompleteData, function (v) {
return v.label.search(new RegExp(query, 'i')) !== -1;
});
$ul = setUl(result, $currentInput);
$ul.attr('id', listId);
$ul.addClass('autofill-show');
$ul.attr('data-target',$currentInput.attr('id'));
var position = $currentInput.position();
$ul.css({
width: $currentInput.width() + parseInt($currentInput.css('padding-left'), 10) + parseInt($currentInput.css('padding-right'), 10),
position: 'absolute',
top: position.top + $currentInput.outerHeight(),
left: position.left
});
if ($ul.find('li').length >= 6) {
$ul.css({
height: '130px',
'overflow-y': 'scroll'
});
}
if (result !== undefined) {
if ($(e.target).attr('id') !== $currentInput.attr('id') && $($(e.target).parent()[0]).attr('id') !== listId) {
destroy($ul);
}
$currentInput.after($ul);
}
$currentInput.trigger('onChange', [query, result]);
});
$(document).on('click', '.autofill-show li', function (e) {
if($ul!==undefined && $($(this).parent()[0]).attr('id')==$ul.attr('id')){
$ul.trigger('onSelect', [$(this).text(), $(this).data('value')]);
}
e.stopImmediatePropagation();
});
$(document).on('onSelect', '#'+listId,function (e, label, value) {
$currentInput.val(label);
if ($.isFunction(options.onSelect)) {
options.onSelect(label, value);
}
if ($(e.target).attr('id') !== $currentInput.attr('id') && $($(e.target).parent()[0]).attr('id') !== listId) {
destroy($ul);
}
e.stopImmediatePropagation();
});
$(document).on('onChange', '#'+$currentInput.attr('id'), function (e, query, result) {
if($ul!==undefined && $($(this).parent()[0]).attr('id')==$ul.attr('id')) {
result = $.grep(autoCompleteData, function (v) {
return v.label.search(new RegExp('\^' + query + '\$', "gi")) !== -1;
});
if ($.isFunction(options.onChange)) {
options.onChange(query, result[0]);
}
}
e.stopImmediatePropagation();
});
$(document).on('click', function (e) {
console.log($(e.target));
if ($(e.target).attr('id') !== $currentInput.attr('id') && $($(e.target).parent()[0]).attr('id') !== listId) {
destroy($ul);
}
e.stopImmediatePropagation();
});
};
function destroy($ul) {
$ul.remove();
}
Here is my css:
.autofill-show{
list-style: outside none none;
padding: 0;
border: 1px solid #ccc;
margin:0;
z-index: 9999999;
}
.autofill-show li{
border: 1px solid #ccc;
text-align: center;
background: #fff;
}
.autofill-show li:hover{
background: #9bcea3;
cursor: pointer;
}
And this is how I am calling my function:
$('#autofill').autofill();
$('#autofill_2').autofill();
Here is the fiddle link. https://jsfiddle.net/saineshmamgain/cs6g13q9/2/
In the process of searching a specific value, the jQuery UI autocomplete selection feature provides the user with some string suggestions for the input area which effectively saves time. The autocomplete select action is triggered when the user selects one of the options from the pre-populated list.
Syntax: $("TagId"). autocomplete({ source : itemList // List of Words. })
Option - appendTo This option is used append an element to the menu. By default its value is null. When the value is null, the parents of the input field will be checked for a class of ui-front. If an element with the ui-front class is found, the menu will be appended to that element.
As I mentioned, and others helped, this is a problem with your events and selectors.
One solution can be adding unique ID to the UL created, not "datetime based". Each time you will destory a specific ID, and recreate it. The events will be triggers via HTML (added onclick=...) and dealth with current/parent level with jQUERY.
I've updated this fiddle
It might have things that are leftovers from your fiddle which I don't have time to perfect... I'll leave it to you.
The solution looks something like this:
function setUl(result) {
var $ul = $('<ul>');
if (result !== undefined) {
$.each(result, function (k, v) {
$ul.append('<li data-value="' + v.value + '" onclick="clickHandle(this)">' + v.label + '</li>');
});
}
return $ul;
}
function clickHandle(ele){
var label = $(ele).text();
var value = $(ele).data('value');
var inputId = $(ele).parent("ul").attr("data-target");
$('#'+inputId).val(label);
if ($.isFunction(options.onSelect)) {
options.onSelect(label, value);
}
}
$.fn.autofill = function (options) {
if (options == undefined) {
options = {};
}
var $currentInput = $(this);
console.log($($currentInput).attr('id'));
var autoCompleteData = $currentInput.data('autofill');
var listId='autofill_' + $currentInput.attr('id');
$currentInput.on('keyup focus', function (e) {
var query = $(this).val();
var result = $.grep(autoCompleteData, function (v) {
return v.label.search(new RegExp(query, 'i')) !== -1;
});
if($('#'+listId)){
$('#'+listId).remove();
}
$ul = setUl(result, $currentInput);
$ul.attr('id',listId);
$ul.addClass('autofill-show');
$ul.attr('data-target',$currentInput.attr('id'));
var position = $currentInput.position();
$ul.css({
width: $currentInput.width() + parseInt($currentInput.css('padding-left'), 10) + parseInt($currentInput.css('padding-right'), 10),
position: 'absolute',
top: position.top + $currentInput.outerHeight(),
left: position.left
});
if ($ul.find('li').length >= 6) {
$ul.css({
height: '130px',
'overflow-y': 'scroll'
});
}
if (result !== undefined) {
destroy($ul);
$currentInput.after($ul);
}
$currentInput.trigger('onChange', [query, result]);
});
//end key up
$('#'+listId).on('onSelect',function (e, label, value) {
$currentInput.val(label);
if ($.isFunction(options.onSelect)) {
options.onSelect(label, value);
}
destroy($ul);
e.stopImmediatePropagation();
});
$(document).on('onChange', '#'+$currentInput.attr('id'), function (e, query, result) {
if($ul!==undefined && $($(this).parent()[0]).attr('id')==$ul.attr('id')) {
result = $.grep(autoCompleteData, function (v) {
return v.label.search(new RegExp('\^' + query + '\$', "gi")) !== -1;
});
if ($.isFunction(options.onChange)) {
options.onChange(query, result[0]);
}
}
e.stopImmediatePropagation();
});
$currentInput.on('blur', function (e) {
window.setTimeout(function(){
destroy($ul);
}, 100);
});
};
function destroy($ul) {
$ul.remove();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With