Code Monkey home page Code Monkey logo

Comments (1)

IllyaMoskvin avatar IllyaMoskvin commented on July 21, 2024

I am currently struggling with the same issue. I'm going to write up my thought process so far here. I'm sorry in advance for the lack of clarity. I'm not used to writing tutorials, but I hope this might help someone down the line.

First, I've set up my API to return JSON data with this general structure:

{
    "count" : "10",
    "pages" : {
        "current" : 1,
        "total" : 2,
        "size" : 5,
        "prev" : "#",
        "next" : "http://.../api/categories/all/id+category_id+title?size=5&page=2"
    },
    "items" : [
        {"id" : 1, "category_id" : 0, "title" : "Hello" },
        {"id" : 2, "category_id" : 1, "title" : "World" },
        {"id" : 4, "category_id" : 1, "title" : "Foo" },
        {"id" : 3, "category_id" : 1, "title" : "Bar" },
        {"id" : 7, "category_id" : 1, "title" : "Soap" }
    ]
}

This data is for a sample query on the categories database. I'm following PHP ActiveRecord conventions on table associations, so category_id represents the parent of each category. I chose to designate category_id=0 to categories that reside in the root, figuring that in SQL, auto-incrementing primary keys start with 1, so 0 is logically more appropriate than NULL. This also makes our filtering a bit easier down the line, since JavaScript and NULL tend to not get along all that well. Please note that I am querying the data with an ORDER BY category_id ASC.

Based on this article by Oskar Hane, I created this filter:

app.filter('nested', function($filter) {
    return function( arr, parent, $key_parent, $key_children ) {
        var out = [];
        for( var i in arr ) {
            if(arr[i][$key_parent] == parent) {
                var children = $filter('nested')( arr, arr[i].id, $key_parent, $key_children );
                if(children.length) {
                    arr[i][$key_children] = children;
                }
                out.push(arr[i]);
            }
        }
        return out;
    };
});

I think it's not the most efficient filter, but it works for now. A more efficient filter would likely work with a copy of the initial array made with an array.slice(), using a count-down while(array.length > 0) loop, assigning categories to children of the out array using the array.shift() method. I think this is also where ORDER BY category_id ASC would become important, wherein optimization is concerned, since it will assure that the parent is always added to out before its children. I had trouble writing such a filter, so I'm settling for Oskar Hane's very capable version!

I've set up a $resource factory. Let's say that I retrieve the categories from the server using this code:

$scope.categories = Category.get();

Now, if I want to, I can create my angular-treeview with this filter:

<div
    data-angular-treeview="true"
    data-tree-id="tree"
    data-tree-model="categories.items | nested:0:'category_id':'items'"
    data-node-id="id"
    data-node-label="title"
    data-node-children="items" >
</div>

However, this is very inefficient, since the filter will end up firing on every $digest. It seems to be a far better idea to nest the categories right away like so:

Category.get({}, function(data) { 
    $scope.categories = $filter('nested')( data.items, 0, 'category_id', 'items' );
});

...and then we can simply get the tree working with the above code, but using data-tree-model="categories" instead of the inline filter. This is the route I'm choosing to take in my project.

Alternatively, you can set up a $watch to manually apply this filter, as per the conclusion in this article by Ben Nadel. Your code might look something like this:

Category.get({},function(data){
    $scope.data.categories = data;
});

$scope.$watch('data.categories', function(newVal, oldVal) {
    if( newVal.$resolved ) // $watch is fired once on init
        $scope.nested = $filter('nested')( $scope.data.categories.items, 0, 'category_id', 'items' );
});

...and then set data-tree-model="nested" in our directive. Unfortunately, I could not figure out how to avoid using a callback in the Category.get() call in this scenario.

Lastly, if you are using the ngResource module to handle API calls, you might be able to filter the results using a custom action with the filter called inside transformResponse. I haven't tried this route yet, so I cannot provide example code.

Again, I'm sorry for this mess of a comment, but I hope it helps someone who is also dealing with this issue. I'll edit it if I find a better solution.

from angular.treeview.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.