Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom autocomplete function in jquery

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/

like image 564
Sainesh Mamgain Avatar asked Jul 19 '16 06:07

Sainesh Mamgain


People also ask

How does autocomplete work in jQuery?

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.

How can create autocomplete search box in jQuery?

Syntax: $("TagId"). autocomplete({ source : itemList // List of Words. })

What is the default value of appendTo option of autocomplete () method?

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.


1 Answers

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();
}
like image 199
Ziv Weissman Avatar answered Sep 29 '22 11:09

Ziv Weissman