1

I am currently learning AngularJS, and I am trying to achieve a JSON complex object displayer. I've read quite a lot about this kind of question in this question or even here, and there are elements of response, but those aren't quite helping me in my case.

The topic mentionned before showed me some good solutions when children always bear the same name (e.g, the child element is always called "Children" for example 1). But how can we deal with different names ? I searched for a way to get the children objects regardless of it's name, but didn't find it.

My JSON object looks like this:

{
  name: "Something",
  _id: "some ID",
  Firstchildren: [
       {
        name: "Children1"
        type: "Child"
        SecondChildren: [
          {
             name: "ChildrenOfDoom",
             type: "Doom"
             ThirdChildren: [
                {
                 name: "BoredOne",
                 type: "Bored
                },
                {
                 name: "AnotherOne",
                 type: "Boring"
                }
             ]
          },
       <another SecondChildren>
    ]}

Basically my question is the following: is there a way to deal with complex JSON object recursively regardless of the children's name ? So, in our example, to end up with a display like:

Something
     Child1 : Child
          ChildrenOfDoom : Doom
              BoredOne : Bored
              AnotherOne : Boring
          ChildrenOfChaos : Chaotic
              SomeOne : Random
              ...
          ...
     Child2 : Child
          ...

And, of course, if there are such ways, I would like to find out about it, whether it is complete solution, advices, documentation or useful tutorials.

Thank you in advance !

PS: If possible, avoid the "possible duplicate of " if they are already linked in the original question, I already went through. PPS: Despite the first above, I am not closed to other related questions either, as long as they are not already quoted here.

Community
  • 1
  • 1
Yassine Badache
  • 1,810
  • 1
  • 19
  • 38

1 Answers1

1

This function returns the name of any property containing "children" for a given object

function getChildrenProperty(object) {
  for (var property in object) {
    if (object.hasOwnProperty(property)) {
      if (property.toLowerCase().indexOf("children") > -1) {
        return property;
      }
    }
  }

  return null;
}

Then inside your recursive function, you can use it like this

var childrenProperty = getChildrenProperty(object);
if (childrenProperty !== null) {
  recursiveFunction(object[childrenProperty]);
}

[EDIT] If you want to check for numerous kind of children (e.g you introduce Brothers, Sisters or Cowboy Beepops in your structure), you can multiply your research terms:

function getChildrenProperty(object) {
  for (var property in object) {
    if (object.hasOwnProperty(property)) {
      if (property.toLowerCase().indexOf("children") > -1) {
        return property;
      }
      // You also search for cowboys here
      if (property.toLowerCase().indexOf("cowboys") > -1) {
        return property;
      }
      // And for demons, because you need it
      if (property.toLowerCase().indexOf("demons") > -1) {
        return property;
      }
     // As much as you want, you should use a function
     // if you need a lot of cases to check ;)
    }
  }

  return null;
}

Be also sure that you need those "lower cases", because it can cause you some issues. I just had an issue where my property was something like "halfWay" and this code snippet provided below couldn't find the property, because it was converting it into "halfway". Otherwise, it works pretty smoothly.

var app = angular.module("app", []);

app.controller("controller", function($scope) {
  $scope.object = {
    name: "Something",
    _id: "some ID",
    FirstChildren: [{
      name: "Child1",
      type: "Child",
      SecondChildren: [{
        name: "ChildrenOfDoom",
        type: "Doom",
        ThirdChildren: [{
          name: "BoredOne",
          type: "Bored"
        }, {
          name: "AnotherOne",
          type: "Boring"
        }]
      }]
    }, {
      name: "Child2",
      type: "Child",
      SecondChildren: [{
        name: "Child of Child2",
        type: "Space Cowboy"
      }]
    }]
  };

  var str = ""; // The string we'll be creating. We'll add it to scope once everything is done

  // Recursive function, this will keep calling itself if the object has children
  // The `level` parameter is used to determine how many tabs to adds to the start of each line
  function addObjectsToString(objects, level) {
    // We want an array of objects to iterate over and add to the string. So if it isn't an array, make a new array containing only `objects` which is actually a single object
    if (!Array.isArray(objects)) {
      objects = [objects];
    }

    for (var i = 0; i < objects.length; i++) {
      var object = objects[i];

      // Add indentation
      for (var j = 0; j < level; j++) {
        str += "    "; // 4 spaces because tab seemed a bit much
      }

      // Add the object name, presumably all objects will have a name
      str += object.name;

      // If the object has a type add " : type"
      if (angular.isDefined(object.type)) {
        str += " : " + object.type;
      }

      // Add a new line
      str += "\n";

      // If the object has a children property, call this function with reference to the object's children
      var childrenProperty = getChildrenProperty(object);
      if (childrenProperty !== null) {
        addObjectsToString(object[childrenProperty], level + 1);
      }
    }
  }

  // Returns the name of any property containing "children"
  function getChildrenProperty(object) {
    for (var property in object) {
      if (object.hasOwnProperty(property)) {
        if (property.toLowerCase().indexOf("children") > -1) {
          return property;
        }
      }
    }

    return null;
  }

  // Very first call to the recursive function
  addObjectsToString($scope.object, 0);

  // Add the string to the scope so we can display it on the page
  $scope.result = str;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<div ng-app="app" ng-controller="controller">
  <pre>{{result}}</pre>
</div>
Yassine Badache
  • 1,810
  • 1
  • 19
  • 38
Jaydo
  • 1,830
  • 2
  • 16
  • 21
  • This helped me working my way around the problem, and was efficient and clear enough. Thank you ! PS: Careful tho, you have to include other checkers if you want to go through objets that does not contain "children" in their name :p. – Yassine Badache Apr 01 '16 at 12:31