Paladini
Paladini

Reputation: 4572

jQuery almost winning me - UI Autocomplete " data undefined"

jQuery is almost winning me. I already saw lots and lots in StackOverflow answers and I can't find a solution to my problem.

I'm using jQuery UI Autocomplete in my project, and I need render a default message if no results is returned. I'm using "_renderItem", as you can see bellow.

var autocompleteDir = $("#search");

autocompleteDir.autocomplete({
    source: function (request, response) {
        populate(request.term, response);

        result = $.ui.autocomplete.filter(result, request.term)

        var item = {};
        item.type = 'loading';
        item.label = "Loading..";
        item.value = "";

        result.unshift(item)

        response(result.slice(0, 10));
    }
});

autocompleteDir.data("ui-autocomplete")._renderItem = function (ul, item) {
    if (item.type === "loading") {
        return $('<li></li>')
            .data("ui-autocomplete-item", item)
            .append("<div style='text-align: center;'>" + item.label + "</div>")
            .appendTo(ul);
    }
};

And here's what I'm getting on the console:

Uncaught TypeError: Cannot read property 'type' of null
Uncaught TypeError: Cannot call method 'data' of undefined 

I'm using jQuery 1.10.2 and jQuery UI 1.10.3. Someone have a good idea?

Edit 1:

If I use this before "source":

response: function(event, ui){ 
                    if (ui.item.type === "loading"){
                        ui.content.push({label:"Loading",value:"Loading"})
                    }

                } 

I have the following error:

Cannot read property 'type' of undefined 

If you help me solve this problem, can I use "response" to format and style my "loading" and my "none" result?

Edit 2

var populate = function(term, response) {
        $.getJSON(
            '<%= my_rails_path %>.json',
            {search: term},
            function(json) {
                  var result = [];
                  $.each(json, function(key, value) {
                    var item = {};
                    item.type = '';
                    item.label = value.name;
                    item.value = value.name;
                    result.push(item);
                  })

                  if (result.length == 0) {
                    var item = {};
                    item.type = "noResult";
                    item.label = "Create '" + term + "'"; 
                    item.value = term;
                    result.push(item)
                  }

                  response(result);
            }
        );  
};

Edit 3

Now the problem is solved, but the label is literally showed, but I want that be rendered. See the code, you'll understand:

 response: function(event, ui){ 
          for(var i in ui.content){
            if (ui.content[i].type==="loading"){
                  ui.content[i] = {
                         label:"<div style='text-align: center;'>Loading</div>",
                        value:""
                                   }
            }
          }
 }

Instead render "Loading" in the middle of the ui, all the string is showed to user (Loading).

Upvotes: 2

Views: 2132

Answers (1)

Rick Hanlon II
Rick Hanlon II

Reputation: 21737

You don't need to use _renderItem because jQuery provides an event that fires after the search returns and before the results are displayed, which you can modify to return a default value if the search return was empty. See the response event. You can do this instead:

autocompleteDir.autocomplete({

    source: function (request, response) {
        populate(request.term, response);

        result = $.ui.autocomplete.filter(result, request.term)

        var item = {};
        item.type = 'loading';
        item.label = "Loading..";
        item.value = "";

        result.unshift(item)

        response(result.slice(0, 10));
    },

    response: function(event, ui){
        if(ui.content.length === 0){
            ui.content.push({label:"default",value:"value"}); /* modify to your liking */
        } 
    }
});

Changing to this technique should solve both issues.

Edit:

In your third edit, if you want to change the value of a div somewhere else on the page, you need to do this in the response function yourself, not by returning the value in the function.

response: function(event, ui){
    if(ui.content.length === 0){
        $('#id-of-div-to-change').text("Loading");
    } 
}

Upvotes: 1

Related Questions