kailoon
kailoon

Reputation: 2069

angularjs: Bound data in custom direct no longer updating after using "track by" in ng-repeat

This is an addendum to this question I asked previously:

Why does my custom directive not update when I derive the output from the bounded data?

My current dilemma is that I have duplicates in data that I generate inside a custom directive used in an ng-repeat. This means I have to use "track by". This somehow breaks the binding and when I update the model, it no longer updates. If I don't use update and remove the duplicates (which for the example can be done easily but for my real problem I cannot), it works. Here is the jsfiddle of how the issue:

http://jsfiddle.net/Lwsq09d0/2/

My custom directive has this:

scope: {
    data: "="
},
link: function (scope, element, attrs) {
        scope.$watch(function () {
            return scope.data
        }, function () {
            var getPages = function(extra) {
                var pages = [];
                pages.push('...');
                for (var i = scope.data.list[0]; i <= scope.data.list[1] + extra; i++) {
                    pages.push(i);
                }
                pages.push('...');
                return pages;
            }
            scope.pages = getPages(1);
        }, true);
    },
    // Remove "track by $index" to see this working and make sure to remove the duplicates
    // "..." pushed in to the generated data.
    template: '<ul><li ng-repeat="d in pages track by $index" my-button="d"></li></ul>'

In the fiddle, I have an ng-click call a controller function to modify data.

I've seen other questions about track by breaking binding, but I haven't seen one where the ng-repeat variable is generated in the custom directive via the bound data.

Thanks for any help.

Upvotes: 1

Views: 196

Answers (1)

DRobinson
DRobinson

Reputation: 4481

Track by is optimized not to rebuild the DOM for already created items. In your example, you are using $index as the identifier. As such, ng-repeatsees the identifier 1 (for the second element in the pages array) and decides that it does not have to rebuild the DOM. This is causing the problem that you are experiencing.

One possible solution might be to generate page Objects that have a unique id, and to track by that:

var lastID = 0;
function createPage(name){
  return { name: name, id: lastID++ };
}

// ... Directive code
pages.push(createPage('...')); // Do this for everything that you push to pages array

// ... More directive code
template: '<ul><li ng-repeat="d in pages track by d.id" my-button="d.name"></li></ul>'

Your JSFiddle, updated to work: http://jsfiddle.net/uv11fe93/

Upvotes: 2

Related Questions