Search code examples
javascriptjquerysemantic-ui

Semantic UI Search form is not fetching object data


I'm pulling a list of countries from an endpoint. I think that I am constructing the object correctly but I am not getting any results in the search form, however with inline declaration of content[] it works fine.

Empty searchbox

The API JSON response looks like this:

{country: "Albania", code: "AL"}
{country: "Algeria", code: "DZ"}
{country: "Andorra", code: "AD"}
{country: "Angola", code: "AO"}
var content = [];
$.getJSON('/getCountries', function(data){
    $.each(data, function(key, value){
        $.each(value, function(key, value){
            if (key == 'country') {
                content.push({ title: value})
            }
        })
    })
})

$('.ui.search')
  .search({
      source: content
  })

Any ideas?


Solution

  • Looks to me like an async issue.

    $(".ui.search").search() is getting called before $.getJSON() has returned with data.


    Let's break down what's happening:

    /*
    $.getJSON() is shorthand for
    
    $.ajax({
      dataType: "json",
      url: url,
      data: data,
      success: success
    })
    
    which is asynchronous.
    
    See https://api.jquery.com/jQuery.getJSON/
    */
    
    // start the ajax call
    $.getJSON(
    
      // URL from which we're fetching JSON data
      "/getCountries", 
    
      // the "success" callback function to be executed after a successful request
      function (data) {
        parseData(data);
      }
    );
    
    // begins executing immediately after .getJSON()
    // without waiting for data to return
    $('.ui.search').search({
      // content is still empty at this point, since data hasn't come back yet
      source: content
    })
    


    Solution

    We need to call .search() after the async .getJSON() call returns with data.

    Since we're already making use of the callback function that executes after we get our JSON data back, let's do all of our data stuff inside that callback.

    Here I've made two smaller functions: one to parse the data into the form that we want content to have, and one to call .search() to init the search form with that content.

    We can now call those two functions from inside our callback, where we know we've gotten the data.

    // set up empty array
    var content = [];
    
    // when this is called, use the value of the content array
    function populateSearch() {
      $(".ui.search").search({
        source: content
      });
    }
    
    // when this is called, push data into the content array
    function parseData(data) {
      for (var item of data) {
        content.push({ title: item.country });
      }
    }
    
    $.getJSON("/getCountries", function (data) {
      // first parse data into the content array
      parseData(data);
    
      // then call the function that sets up search
      populateSearch();
    });
    


    Modernized to ES6-level Javascript

    You could write it more concisely like so:

    function populateSearch(data) {
      // use .map() to transform our data array to a new array in one step
      const content = data.map(item => (
        { title: item.country }
      ));
    
      // init the search form with our new content array
      $(".ui.search").search({
        source: content
      });
    }
    
    $.getJSON("/getCountries", function (data) {
      populateSearch(data);
    });