Twitter Bootstrap typeahead: get context / calling element with `this`

12,734

Solution 1

You are inside another function so you need to save a reference to the element in the outer closure, this can then be passed into the event handler of the inner closure. You can do that using an $.each() call to loop through the selector saving a reference to the element (this) each time - e.g.

$('#client-search, #endClient-search, #other-search').each(function() {
    var $this = $(this);
    $this.typeahead({
        ...

        ,updater: function (item) {
            var target = $this.attr('id').split('-')[0] + '-id';
            $('#'+target).val(mapped[item]);
            return item;
        }
        ...
     });

Solution 2

The accepted answer is a good one, but just wanted to share an alternative that doesn't actually require the outer closure. I'm using bootstrap v2.3.1 and the input is available to you from this.$element.

Eg:

$(':input[data-typeahead-url]').typeahead({
    source: function (query, process) {
        $.get(this.$element.attr('data-typeahead-url'), { query: query }, function (data) {
            labels = [];
            mapped = {};
            $.each(data, function(i,item) {
                mapped[item.label] = item.value;
                labels.push(item.label);
            });
            process(labels);
        });
    }
    ,updater: function (item) {
        $('#'+this.$element.attr('data-typeahead-target')).val(mapped[item]);
        return item;
    }
    ,items: 10
    ,minLength: 2
});
Share:
12,734
Peter Di Cecco
Author by

Peter Di Cecco

Among other things, I am a... Software and web developer Musician Karaoke enthusiast Camping aficionado Developer of table top games A general, over-all geek Some programming languages and tools I've used: JavaScript, Node.js, Vue.js, NestJS, Knex.js, jQuery, HTML5, CSS, Twitter Bootstrap, jQuery UI SQL, PostgeSQL, Microsoft SQL Server, Python, Bash, git Java, J2EE, Java EE, Hibernate, Struts, Tomcat, Play! Framework

Updated on June 05, 2022

Comments

  • Peter Di Cecco
    Peter Di Cecco almost 2 years

    I am using the Typeahead component of Twitter Bootstrap 2.1.1, and jQuery 1.8.1

    I am trying to access the text box element from within typeahead's updater function. Here is my current code, which works great:

    $('#client-search').typeahead({
        source: function (query, process) {
            $.get(url, { query: query }, function (data) {
                labels = [];
                mapped = {};
                $.each(data, function(i,item) {
                    mapped[item.label] = item.value;
                    labels.push(item.label);
                });
                process(labels);
            });
        }
        ,updater: function (item) {
            $('#client-id').val(mapped[item]);
            return item;
        }
        ,items: 10
        ,minLength: 2
    });
    

    I have many typeahead search boxes on the same page. Each search box has an id #xxx-search and a corresponding hidden input with id #xxx-id. I'd like to re-use the same code for everything by doing something like this:

    $('#client-search, #endClient-search, #other-search').typeahead({
    
        ...
    
        ,updater: function (item) {
            var target = $(this).attr('id').split('-')[0] + '-id';
            $('#'+target).val(mapped[item]);
            return item;
        }
    
        ...
    

    I thought that this would refer to the text box element in use, but apparently not, because I get an undefined error in firebug:

    $(this).attr("id") is undefined
    

    When I use this instead of $(this), I get:

    this.attr is not a function
    

    Can anyone help make this work?


    UPDATE: THE ANSWER, AND MORE!

    Thanks to benedict_w's answer below, not only does this work perfectly now, but I have also made this much better in terms of re-usability.

    Here is what my <input>s look like:

    <input type="text" autocomplete="off"
        id="client-search"
        data-typeahead-url="/path/to/json"
        data-typeahead-target="client-id">
    <input type="hidden" id="client-id" name="client-id">
    

    Notice how the search box references the hidden id. Here's the new js:

    $(':input[data-typeahead-url]').each(function(){
        var $this = $(this);
        $this.typeahead({
            source: function (query, process) {
                $.get($this.attr('data-typeahead-url'), { query: query }, function (data) {
                    labels = [];
                    mapped = {};
                    $.each(data, function(i,item) {
                        mapped[item.label] = item.value;
                        labels.push(item.label);
                    });
                    process(labels);
                });
            }
            ,updater: function (item) {
                $('#'+$this.attr('data-typeahead-target')).val(mapped[item]);
                return item;
            }
            ,items: 10
            ,minLength: 2
        });
    });
    
  • benedict_w
    benedict_w over 11 years
    You will find some more discussion about JavaScript Closures here: stackoverflow.com/questions/111102/…
  • nizam.sp
    nizam.sp almost 11 years
    I was struggling with this problem for 2 hours. You saved my day!