Simple Ng-Repeat (Not Repeating) Scenario Directive TemplateUrl
-
21-12-2019 - |
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
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.
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.