0

The code below is supposed to create a list of categories and sub-categories in vanilla js. I am using 2 for-loops. The code works fine for the first level, but not when adding the second level. Can anyone tell me why it only returns the first category? I am a newbie.

function insertAfter(referenceNode, newNode) {
  referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
    if (this.readyState == 4 && this.status == 200) {
      var response = JSON.parse(xhttp.responseText);
      var allBirds = response.birds;

      for (var i = 0; i < allBirds.length; i++) {
        var el = document.createElement('li');
        el.innerHTML = allBirds[i].family;
        var ul = document.getElementById('overview');
        insertAfter(ul, el);

        var members = allBirds[i].members;
        for (var j = 0; j < members.length; j++) {
          var elj = document.createElement('h5');
          var ulj = document.getElementById('innerView');
          insertAfter(elj, ulj);
        }
      }
    }
  };

xhttp.open('GET', 'JSON/birds.json', true);
xhttp.send();

This is the desired outcome: category sub-category sub-category category sub-category . .

JP Douma
  • 133
  • 1
  • 8

3 Answers3

0

If you try parse a array/object use a recursive function to seal with every "layer" on its own. Call the function with the top Node. The function have to loop over all child elements and decide if it is a leaf (a node this no child elements) or a node (containing child elements).

If it is a Leaf, you could generate some output. If it is a Node you go deeper in to the rabbit hole :)

The for-loop you use is a classic one. A counter increments every loop and you get the value from the array. I use a other for-loop. I don't need to know the array keys. I just ask the array "Hey! give me all your keys". And then i use this keys for(var key in node)

To check the type of a child I use typeof witch will return the type of the variable as a string (e.g. typeof("Hello World") will return "string"). So you can decide what to do with the variable/child.

The next thing is the ===. This is a other operator then ==. Short story: === check for identity and == for equality. Lets say you have tow friends named Alex. The have the same name (==) but where different (!==) persons. Long story: Which equals operator (== vs ===) should be used in JavaScript comparisons?

Then I add a counter (deep) to know the level of recursion (but i don't use it) It is up to you to create your output depending on the level. You could add some dots before the text to show the depth or something else. I would properly use this var text = '...........'.substr(0,deep) + node[key].family

A recursive function like this:

function listChildren(node, deep){
    for (var key in node) {
      if(typeof(node[key])  === 'array' || typeof(node[key]) === 'object'){
        var el = document.createElement('li');
        el.innerHTML(key);
        var ul = document.getElementById('overview');
        insertAfter(el, ul);
        listChildren(node[key], ++deep);
      }else{
        var el = document.createElement('li');
        el.innerHTML(node[key].family);
        var ul = document.getElementById('overview');
        insertAfter(el, ul);
    }
}

This is only a hint. you have to modify it for your needs!

Marcus
  • 1,910
  • 2
  • 16
  • 27
  • Thanks Marcus. I will work my way through this and see if I will be able to grasp it. Started coding 3 weeks ago, so still a little slow :-). – JP Douma Oct 12 '17 at 06:23
  • Your welcome. If you are new to coding let me explain a little bit more, wait just a moment ... – Marcus Oct 12 '17 at 06:24
  • so, any questions :) ? – Marcus Oct 12 '17 at 06:40
  • Hey Marcus, your answer is closer to what I came up with than PHPglue’s. I think I understand both and will try to play around with both solutions. This is a tremendous help moving my knowledge forward. I will let you know tomorrow if I got it to work. Thank you very much for taking the time to explain it to me! – JP Douma Oct 12 '17 at 08:04
  • Hi Marcus, studying your example further I came across the for-of loop as well. The difference with the for-of loop seems to be that the values in the iterable using for-in can only be strings. I have found this explanation as well: ‘for-of is for iterating over arrays and for-in is for iterating over the keys of objects’. What is your motivation to use one over the other? You have set me on a new path of learning the intricacies of ecma 6. :) – JP Douma Oct 12 '17 at 12:10
  • When I use the `for-in` version, I don't have care about the keys. If there are any "holes" in there (e.g. `var a= { 1:'Hello', 3:'WORLD', 'a':'xYz'}`) But you have to be aware of some special "keys" like the key `length` witch is part of every object. So I only use `for-of` when I need a counter (e.g print position inside the array like in this `var a = 'HELLO WORLD FOR REAL !!!'.split(' ')`) – Marcus Oct 12 '17 at 12:25
0

Just focusing on this part, you should create it all dynamically:

function birdLister(xhrResponse, appendTo){
  var allBirds = xhrResponse.birds, all = document.createElement('ul');
  for(var i=0,b,ti,ui,u,m,l=allBirds.length; i<l; i++) {
    b = allBirds[i]; ti = document.createElement('li'); ti.innerHTML = b.family;
    ui = document.createElement('il'); u = document.createElement('ul'); m = b.members;
    for(var n=0,li,c=m.length; n<c; n++){
      li = document.createElement('li'); li.innerHTML = m[n]; u.appendChild(li);
    }
    ui.appendChild(u); all.appendChild(ti); all.appendChild(ui);
  }
  appendTo.appendChild(all);
}

Now inside your XHR:

var xhttp = new XMLHttpRequest();
xhttp.open('GET', 'JSON/birds.json');
xhttp.onreadystatechange = function(){
  if(this.readyState === 4 && this.status === 200){
    var response = JSON.parse(this.responseText);
    birdLister(response, document.getElementById('output'));
  }
}
xhttp.send();
StackSlave
  • 10,613
  • 2
  • 18
  • 35
  • 1
    Alright. After having chewed on it for a bit, I think I do get it. Tonight, I am going to play around with this code a bit and will get back to you tomorrow whether I really understood or not. Just a few words of background. I have worked my way through online videos and the Mozilla basics. Now I have defined an ambitious project involving quite a few technologies. This forces me to work on real world examples and tackle all sorts of issues. I do not have a background in computer science to fall back on. Your answer will help me leap forward quite a bit. Thank you! – JP Douma Oct 12 '17 at 07:32
  • PHPglue, I got it to work, kind of intuitively. Still working through all the steps to fully understand it. This is the direction for my final solution I am looking for (I need to read data from a Trello board, turn it into a quote, and send it off to a customer). Thank you for helping out. – JP Douma Oct 13 '17 at 10:52
  • For other users looking at this. I was trying to rewrite a p5.js tutorial in vanilla js. This is the tutorial: https://youtu.be/118sDpLOClw by Daniel Shiffman, The Coding Train. – JP Douma Oct 13 '17 at 10:55
0

For other users, this is how I got PHPglue's code to work for me:

var xhttp = new XMLHttpRequest();
xhttp.open('GET', 'JSON/birds.json');
xhttp.onreadystatechange = function () {
  if (this.readyState === 4 && this.status === 200) {
    var response = JSON.parse(this.responseText);
    BirdLister(response, document.getElementById('overview'));
  }
};

function BirdLister(xhrResponse, appendTo) {
  var allBirds = xhrResponse.birds;
  var all = document.createElement('ul');
  for (var i = 0, b, ti, ui, u, m, l = allBirds.length; i < l; i++) {
    b = allBirds[i]; ti = document.createElement('h4'); ti.innerHTML = b.family;
    ui = document.createElement('h5'); u = document.createElement('ul'); m = b.members;
    for (var n = 0, li, c = m.length; n < c; n++) {
      li = document.createElement('li'); li.innerHTML = m[n]; u.appendChild(li);
    }

    ui.appendChild(u); all.appendChild(ti); all.appendChild(ui);
  }

  appendTo.appendChild(all);
}

xhttp.send();

The corresponding HTML file is simply a basic setup and one div with the ID 'overview in the body.

https://github.com/dariusk/corpora/blob/master/data/animals/birds_antarctica.json

JP Douma
  • 133
  • 1
  • 8