简体   繁体   中英

AngularJS - Json to Tree structure

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?

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/

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM