2

I 've seen lots of answers that turn a Json response to a Ul Tree structure. The thing is that all these subjects where around a nested response pointing out the relationship between parent object and child object.

I have a non nested Json response indicating the relation by reference to the objects property.

The following is part of the response:

{"id":"1","parent_id":null,"name":"Item-0"}, {"id":"2","parent_id":"1","name":"Item-1"}, {"id":"3","parent_id":"2","name":"Item-2"}, {"id":"4","parent_id":"2","name":"Item-4"}, {"id":"5","parent_id":"2","name":"Item-5"}, {"id":"6","parent_id":"2","name":"Item-6"}, {"id":"7","parent_id":"2","name":"Item-7"}, {"id":"8","parent_id":"2","name":"Item-8"}, {"id":"9","parent_id":"2","name":"Item-9"}, {"id":"10","parent_id":"1","name":"Item-3"}, {"id":"11","parent_id":"10","name":"Item-10"},

You might already noticed that the each object conects with his father through the parent_id which is conected to his parent's id.

I tried to create a custom directive to read the response and through recursion to build the Tree structure.

Till now I succeeded to only create the first level of the tree. Demo

app.directive('tree',function(){
    var treeStructure = {
        restrict: "E",
        transclude: true,
        root:{
            response : "=src",
            Parent : "=parent"
        },
        link: function(scope, element, attrs){
            var log = [];
            scope.recursion = "";
            angular.forEach(scope.response, function(value, key) {
                if(value.parent_id == scope.Parent){
                    this.push(value);
                }
            }, log);
            scope.filteredItems = log;

            scope.getLength = function (id){
                var test = [];
                angular.forEach(scope.response, function(value, key) {
                    if(value.parent_id == id){
                        this.push(value);
                    }
                }, test);
                if(test.length > 0){
                    scope.recursion = '<tree src="scope.response" parent="'+id+'"></tree>';
                }
                return scope.recursion;
            };
        },
        template:
            '<ul>'
                +'<li ng-repeat="item in filteredItems">'
                    +'{{item.name}}<br />'
                    +'{{getLength(item.id)}}'
                +'</li>'
            +'<ul>'
    };
    return treeStructure;
});

app.controller('jManajer', function($scope){
    $scope.information = {
        legend : "Angular controlled JSon response",
    };

    $scope.response = [
        {"id":"1","parent_id":null,"name":"Item-0"},
        {"id":"2","parent_id":"1","name":"Item-1"},
        {"id":"3","parent_id":"2","name":"Item-3"},
        {"id":"4","parent_id":"2","name":"Item-4"},
        {"id":"5","parent_id":"2","name":"Item-5"},
        {"id":"6","parent_id":"2","name":"Item-6"},
        {"id":"7","parent_id":"2","name":"Item-7"},
        {"id":"8","parent_id":"2","name":"Item-8"},
        {"id":"9","parent_id":"2","name":"Item-9"},
        {"id":"10","parent_id":"1","name":"Item-2"},
        {"id":"11","parent_id":"10","name":"Item-10"},
    ];
});

Is there any one who could show me how to convert this kind of array to Tree structure through recursion?

2 Answers 2

3

Transform your array first recursive in a nested one

var myApp = angular.module('myApp', []);

myApp.controller('jManajer', function($scope) {
  $scope.res = [];
  $scope.response = [{
    "id": "1",
    "parent_id": 0,
    "name": "Item-0"
  }, {
    "id": "2",
    "parent_id": "1",
    "name": "Item-1"
  }, {
    "id": "3",
    "parent_id": "2",
    "name": "Item-3"
  }, {
    "id": "4",
    "parent_id": "2",
    "name": "Item-4"
  }, {
    "id": "5",
    "parent_id": "2",
    "name": "Item-5"
  }, {
    "id": "6",
    "parent_id": "2",
    "name": "Item-6"
  }, {
    "id": "7",
    "parent_id": "2",
    "name": "Item-7"
  }, {
    "id": "8",
    "parent_id": "2",
    "name": "Item-8"
  }, {
    "id": "9",
    "parent_id": "2",
    "name": "Item-9"
  }, {
    "id": "10",
    "parent_id": "1",
    "name": "Item-2"
  }, {
    "id": "11",
    "parent_id": "10",
    "name": "Item-10"
  }, ];

  function getNestedChildren(arr, parent) {
    var out = []
    for (var i in arr) {
      if (arr[i].parent_id == parent) {
        var children = getNestedChildren(arr, arr[i].id)

        if (children.length) {
          arr[i].children = children
        }
        out.push(arr[i])
      }
    }
    return out
  }
  $scope.res = getNestedChildren($scope.response, "0");

  console.log($scope.res);
  $scope.nested_array_stingified = JSON.stringify($scope.res);

});
<!DOCTYPE html>
<html>

<head>
  <script src="https://code.angularjs.org/1.3.11/angular.js"></script>

</head>

<body ng-app="myApp" ng-controller="jManajer">

  {{nested_array_stingified}}
</body>

</html>

After that you can follow the tutorial here for example http://sporto.github.io/blog/2013/06/24/nested-recursive-directives-in-angular/

Sign up to request clarification or add additional context in comments.

Comments

1

You need to unflatten your data before passing it to your view. I have modified your code a bit, also I have transformed your data and replaced the depth and relational fields with integers, it's more easy to compare integers rather than comparing strings and null values.

In this example I have used Undescore.js' powerful functions in order to unflatten the array.

The code can be found as a helper function inside your directive:

unflatten = function (array, parent, tree) {

    tree = typeof tree !== 'undefined' ? tree : [];
    parent = typeof parent !== 'undefined' ? parent : {
        id: "0"
    };

    var children = _.filter(array, function (child) {
        return child.parent_id == parent.id;
    });

    if (!_.isEmpty(children)) {
        if (parent.id == "0" || parent.id == null) {
            tree = children;
        } else {
            parent['children'] = children
        }
        _.each(children, function (child) {
            unflatten(array, child)
        });
    }
    console.log(tree)
    return tree;
}

If you want a VanillaJs solution check out this piece of code

Also here is a demo simulating an interactive tree with your data

The underscore unflatten function was taken from here .

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.