Monday, September 23, 2013

Angular treeview directive 0.5v (ui.treeview 0.5v).

Hi,

With this post, the new treeview directive version changes(ui.treeview.js v0.5) will be explained. The new plugin can be downloaded from this link.

The first and foremost change is in the implementation of search functionality of the treeview.

I noticed that using the default angular's filter is not suitable for the control like treeview. Hence with this release there's new custom filter in place which will be upgraded in coming versions.

Here's list of options and their usage description of this version.

AttributesDataTypeDescription
treeview-data (Required)Array (Binding)bind the data variable from your controller for which you wish to display treeview.
unique-id (Optional)Stringoptional attribute for now. Bind the attribute which is unique for the node.
display-attr (Required)String bind the attribute of the data which has to be displayed at each node.
data-check (Optional)booleanAttribute to specify whether to display check box for the nodes or not. Default is false.
data-check-rec (Optional)booleanAttribute to specify whether to select all children nodes on selection of a single node. Default is true.
expand-all (Optional)booleanAttribute to specify whether the tree should be expanded or not. Default is collapse
searchModel (Optional)String (Binding)Attribute for searching tree.

Check out the plugin and please leave your comments for improving this.

Happy Coding.

Monday, September 16, 2013

AngularJS - Accessing parent scope's variables/model inside nested ng-repeat


Hi,

Working with nested ng-repeat's can be tricky, here's a issue I ran into while I was designing html with nested ng-repeat.

Problem: Say I have scenario in which I have to design the template in such a way that the template is nested in itself.

<script type="text/ng-template" id="template.html">
 <div>{{data.name}}</div>
    <ul>
        <li ng-repeat="data in data.Children" ng-include="'template.html'" ></li>
    </ul>
</script>

This is our data which is bound to the template.

[{
  "id": "6000", "Name": "All Categories",
    "Children": [{
      "id": "6100", "Name": "Juice",
        "Children": [{
          "id": "6200", "Name": "Mom's Brands",
            "Children": [{ "id": "6454", "Name": "Mom's Apple Jug" },
              { "id": "6456", "Name": "Mom's Apple Juice" },
              { "id": "6458", "Name": "Mom's Grape Juice" },
              { "id": "6462", "Name": "Mom's Apple Grape Jug" },
              { "id": "6463", "Name": "Mom's Pear Blend" },
              { "id": "6464", "Name": "Mom's Juice Cocktail Lite" }
        ]
      }]
    }]
  }]

Now I have a model(say $scope.dontShowID = "6454") in controller based on which I need to check some condition to display or not to display the "<li>". And hence I modified the template code as follows.

<li ng-show="data.ID!=dontShowID" ng-repeat="data in data.Children" ng-include="'template.html'" ></li>

The above code doesn't work because ng-repeat creates its own scope and hence we might have to access parent's scope to access dontShowID. So to access parent's scopes the code will change as.

<li ng-show="data.ID!=$parent.dontShowID" ng-repeat="data in data.Children" ng-include="'template.html'" ></li>

Since this is a nested template our data will also be in nested form. Everytime there's a ng-repeat a new scope is created, in such a case the above code will not work as $parent will have reference to the parent ng-repeat's scope.

Now here's the problem to access dontShowID at each level of data. Even if we know the level at which data is it is difficult to access controller scope's model.

But somehow this rule doesn't apply to methods.

Solution: Nearest decent solution I have been able to find is to add a init method just before ng-repeat i.e, at {{data.name}} and pass data as argument to the init method. Inside the init method assign the dontShowID to data.dontShowID.

So the code will change as.

<script type="text/ng-template" id="template.html">
 <div ng-init="initData(data)">{{data.name}}</div>
    <ul>
        <li ng-show="data.dontShowID!=data.ID" ng-repeat="data in data.Children" ng-include="'template.html'" ></li>
    </ul>
</script>

And the code of initData method will be...

$scope.initData = function (data) {
    data.dontShowID = $scope.dontShowID;
};

Once we assign the model at the data level, the condition checking is easy as we no longer need to access parent scope. Hope this helps in solving ng-repeat scope issues. This is the solution I have found so far, any thoughts on how we can improve this?