Semantic UI Search form is not fetching object data

Viewed 114

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?

2 Answers

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);
});

You could simplify the code a bit using plain javascript:

var content = [];

$.getJSON("/getCountries", function (data) {
  parseData(data);
});

function parseData(data) {
  for (var item of data) {
    content.push({ title: item.country });
  }
}

$(".ui.search").search({
  source: content,
});

I used this for the data assuming it's an array of objects:

const data = [
  { country: "Albania", code: "AL" },
  { country: "Algeria", code: "DZ" },
  { country: "Andorra", code: "AD" },
  { country: "Angola", code: "AO" },
];
Related