0

Just trying to get some practice working with public APIs in Javascript. All I want to do is, when you submit the query, have the list of items I get back be sorted alphabetically by the h4 value (food name). I tried calling .sort() on the response item before calling .map(). Tried directly sorting the div elements after the fact using jquery, but in both cases, I just get a blank page back. I'm very new to javascript and writing this all in Notepad++, so there's probably a much better way to be doing all this, but I'm not aware of it.

Html code:

<!DOCTYPE html>
<html>
<form action="search">
 <label>Search</label>
  <input type="text">
  <input type="submit">
  <input type="reset">
</form>

<div class="result">
 <h3>Result</h3>
</div>
</html>

Css code:

.result{
 display:flex;
 flex-wrap:wrap;
}
.item{
  min-width:200px;
  margin:20px auto;
}

JavaScript code:

 var apiKey = "4b314d3e9171fbe99c6cdf16127ba93e";
 var apiId = "4c143c55";
 var queryItem;
 var url = 'https://trackapi.nutritionix.com/v2/search/instant?query=';

 var form = document.querySelector('form');
 var input = document.querySelector('input[type="text"]');
 var result = document.querySelector('.result');

 function search(e){
  e.preventDefault();
  queryItem = input.value;
  makeRequest(queryItem);
  input.value= "";
 }

 function reset(){
  var node = document.querySelector('.result');
  while (node.firstChild) {
  node.removeChild(node.firstChild);
 }
 }

 function createFood(name, qty, unit, photo){
 var item = document.createElement('div');
 var foodName = document.createElement('h4');
 var serving = document.createElement('p');
 var img = document.createElement('img');

 item.classList.add('item');
 foodName.innerHTML = name;
 serving.innerHTML = qty+' '+unit;
 img.src = photo;

 result.appendChild(item);
 item.appendChild(img);
 item.appendChild(foodName);
 item.appendChild(serving)

 }

 function makeRequest(queryItem) {
 reset();
 xhr = new XMLHttpRequest();

 xhr.onload = function() {
 var response = JSON.parse(this.responseText);

 response.common.map(function(food){
  createFood(food.food_name,
             food.serving_qty,
             food.serving_unit,
             food.photo.thumb
            )
  })
};

xhr.open(
 "GET",
 url+queryItem,
 true
);
xhr.setRequestHeader('x-app-id',apiId);
xhr.setRequestHeader('x-app-key',apiKey);
xhr.send();
}

form.addEventListener('submit', search)
form.addEventListener('reset', reset)
Llazar
  • 3,167
  • 3
  • 17
  • 24
sam
  • 151
  • 1
  • 3
  • 15
  • The api isn't returning any food items or anything for me. – zfrisch Sep 27 '18 at 17:55
  • @zfrisch You just copied/pasted this into a new file and ran it? I just did so and re-loaded to be sure, and I if I enter a food name and hit "submit" I do get a list of foods back. But they are not sorted. – sam Sep 27 '18 at 17:58
  • 1
    `common.sort((a, b) => a.food_name > b.food_name).map` –  Sep 27 '18 at 17:59
  • be better if you showed what the response was... – epascarello Sep 27 '18 at 18:00
  • Most likely a dupe of https://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value-in-javascript – epascarello Sep 27 '18 at 18:01
  • @epascarello, yeah, sorry, I'm not too good with web development questions, wasn't sure where to upload my code so you could actually view the page yourself. – sam Sep 27 '18 at 18:03
  • @Chris G, thank you, that worked! – sam Sep 27 '18 at 18:03
  • lodash _.orderBy is your friend,.. –  Sep 27 '18 at 18:09
  • @sam In case you're interested, here's a jQuery version: https://jsfiddle.net/khrismuc/adkpmf1v/ –  Sep 27 '18 at 18:18

1 Answers1

0

You can use a generic function to sort by the attribute of your choice.

function sortByAttrAlphabeticallyASC(arr, attr) {
    return arr.sort((a, b) =>
      a[attr].toLocaleLowerCase().localeCompare(b[attr].toLocaleLowerCase())
    );
}

Where arr is the array of Objects you want to sort and attr is the name of the attribute that will be compared.

As you can see here Array has a method that you can pass a callback with the comparation.

And String has a method to compare Strings as seen here witch can be passed inside Array::sort for comparation purposes.

In your case you would do:

sortByAttrAlphabeticallyASC(response.common, 'name').forEach(food => createFood(food.food_name,
    food.serving_qty,
    food.serving_unit,
    food.photo.thumb
))
ygorazevedo
  • 487
  • 1
  • 4
  • 14
  • 1
    A better generic function would probably be one that produces comparators, so you can do something like `arr.sort(compare("food_name"))`. It would be then be trivial to reverse sort with a single wrapper function applicable to any single comparator - `reverse => f => function() { return -1 * f.apply(this, arguments)}` – VLAZ Sep 27 '18 at 18:19