Question

Closure With Simple Directive

I have a simple closure that has a couple properties hello and items. When I bind the hello world works fine but the list doesn't render when I use ng-repeat.

(function() {
    var app = angular.module('safety-plus-task-list', []);

    app.directive('taskList', function () {
        return {
            restrict: "E",
            templateUrl: "/Task/TaskList",
            scope: {

            },
            controller: function ($http, $scope, $element, $attrs) {
                this.hello = "HELLO WORLD";
                this.items = [
                    "gravida nisl, id fringilla neque ante vel mi.",
                    "quam gravida nisl, id fringilla neque ante vel mi."];
            },
            controllerAs: "task"
        };
    });
})();

Code Inside Directive

Here is the code that use to render the custom directive. The hello variable shows up correctly but items aren't rendering at all. If there is one item in the list it shows up.

{{ task.hello }}
<div ng-repeat="item in task.items">
    <div> {{ item }} </div>
</div>

Rendered Image

enter image description here

Identical Strings Break The Loop

This seems to be un-intuitive behavior. Try it your self. I changed one letter from my example and the template rendered as expected.

Can anyone tell me why this behaves like this?

Example of the code. This code produces different results and doesn't work for some reason unless you add the "$scope" prefix instead of "this" as in enter link description here. To make things more confusing the scoped version actually doesn't produce the problem that this post delineates.

Was it helpful?

Solution

ngRepeat expects items to be different objects (comparing by ===).
Since strings are primitives, 2 same strings are considered equal/identical.

You can use track by to instruct ngRepeat to compare something else, e.g. indices:

ng-repeat="item in task.items track by $index"

OTHER TIPS

Look at how ngRepeat is implemented:

        //...at line 225
        if (trackByExp) {
            trackByExpGetter = $parse(trackByExp);
            trackByIdExpFn = function(key, value, index) {
                // assign key, value, and $index to the locals so that they can be used in
                  hash functions
                if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
                hashFnLocals[valueIdentifier] = value;
                hashFnLocals.$index = index;
                return trackByExpGetter($scope, hashFnLocals);
            };
        } else {
            trackByIdArrayFn = function(key, value) {
                return hashKey(value);
            };
        }

        //...at line 289
        trackByIdFn = trackByIdExpFn || trackByIdArrayFn;

ngRepeat tracks elements by an id function, which can be provided by the track by expression (trackByIdExpFn), or is decided by the directive itself (trackByIdArrayFn). In this case, as you can see, the expression is simply return hashKey(value). This means that you have a collision for identical elements.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top