Search code examples
jqueryjquery-autocompletejquery-widgets

Why is my jQuery widget returning 'object is not a function'?


I'm trying to create a 2 column autocomplete. I theory this code should be correct, but I keep getting the error Uncaught TypeError: object is not a function and I don't know why.

Can anyone see why I'm getting this error? Here is my fiddle - to reproduce the error, type at least two characters into the text field starting with mo.

PS. There is a bug in jsFiddle. If you click Update after saving the first time, you will get an 403 forbidden. Hopefully they'll fix this asap.

UPDATE
So I've done some debugging. Switching from jquery.min.js to jquery.js shows that jQuery actually fails on the each:

TypeError: obj is undefined
length = obj.length,

So by doing this:

var stores = items.stores;
console.log(stores.toSource());

you will get a TypeError: stores is undefined

But if you do this:

$.each( items, function( index, item ) {
  console.log(item.toSource());
});

it will output

// Stores
({0:{id:"4058", name:"Moods"...}, 1:{id:"4059", name:"Moody"...}, label:(void 0), value:(void 0)})  

// Brands
({0:{id:"4673", name:"Moods"...}, 1:{id:"4674", name:"MOOKS"...}, label:(void 0), value:(void 0)})

UPDATE 2
It seems that response(data); removes named parameters in the JSON object.
If you do this:

success: function (data) {
    console.log(data.stores.toSource()); // <-- This works
    response(data); // But after this, it no longer works
}

Now you can dot his:

console.log(data[0].toSource());

code:

var data = 
  {"stores":[
      {"id":"4058","name":"Mo-shu","city":"Oslo","fk_countryID":"NO"},
      {"id":"4059","name":"Mood","city":"Oslo","fk_countryID":"NO"}
  ],
  "brands":[
      {"id":"4673","name":"Moods"},
      {"id":"4674","name":"MOOKS"}
  ]
}    


$.widget( "custom.searchAutocomplete", $.ui.autocomplete, {
    _renderMenu: function( ul, items ) {
        var self = this;
        ul.addClass('searchAutocomplete');
        ul.append('<li class="stores left"></li>');
        ul.append('<li class="brands left"><li>');

        $.each( items.stores, function( index, item ) {
            self._renderItem( ul.find('.stores' ), item, 'store' );
        });

        $.each( items.brands, function( index, item ) {
            self._renderItem( ul.find('.brands' ), item,'brand' );
        });

    },
    _renderItem: function( li, item, type) {
        var listItem = $('<div />');

        listItem.data('ui-autocomplete-item', item );

        if(type == 'store') {
            listItem.append( "<a>"+ item.name + "<br /><span class='address'>Street name here</span></a>" );
        } else {
            listItem.append('<a>' + item.name + '</a>');
        }

        listItem.appendTo( li ); 
        return listItem;
    }
});

$('#search-box').searchAutocomplete({
  minLength: 2,
  source: data,
  select: function(e, ui){
     $(this).val(ui.item.name);
     return false;
 }
});

Solution

  • The "source" parameter only accepts 3 types of input - refer to http://api.jqueryui.com/autocomplete/#option-source to see that the format you give it is not appropriate. I've done a little research and this works:

    $('#search-box').searchAutocomplete({
      minLength: 2,
      source: function(request,response)
        {
            response(data);
        }
    });
    

    Everything else is about debugging your extending methods.

    I've updated your fiddle - http://jsfiddle.net/PMfb8/2/