Binvention
Binvention

Reputation: 1077

using ng-repeat with directives causes child directives not to update

so if found this very interesting bug in angular.js. if you have a custom directive inside a ng-repeat that is actively changing the variables in the directive don't update. meaning if i have 3 elements in my array for ng-repeat it initializes just fine but if i delete element 1 from the array any variables that element 1 had passed to its child directive somehow end up in element 2's child directive here is my example code.

<div ng-app='testing'>
    <div ng-controller='testing as test'>
        <div ng-repeat='item in test.example track by $index'>
            {{item.title}}
            <child scope='item.data'></child>
            <button ng-click="test.delete($index)">
               Delete
            </button>
        </div>
    </div>
</div>

then in my js file

console.log('hello world');
var app=angular.module('testing',['testingChild']);
app.controller('testing',[function(){
    this.example=[{
        title:"this is the first title",
        data:"this is the first index"
    },{
        title:"this is the second title",
        data:"this is the second index"
    },{
        title:"this is the third title",
        data:"this is the third index"
    }];
    this.delete=function(index){
        this.example.splice(index,1);
    };
}]);
var child=angular.module('testingChild',[]);
child.directive('child',[function(){
    return{
        restrict:"E",
        scope:{
            parent:"=scope"
        },
        template:"<div>{{child.parent}}</div>",
        controller:['$scope',function($scope){
            this.parent=$scope.parent;
        }],
        controllerAs:"child"
    };
}]);

and i have a functioning jsfiddle here. all you have to do to see it work is delete one of the first elements. does anyone know what causes this and how to fix it?

Side note:

I thought it might be useful also to mention that when using this in a slighty different situation with editable elements in the child (like a text box) the data binding worked from the child to the parent. so assigning a variable attached to the controller to the scoped variable from the parent worked in that direction. this seems to be the only situation i have come across where it would be from the parent to the child and that is what is not working.

Upvotes: 2

Views: 684

Answers (2)

Binvention
Binvention

Reputation: 1077

I found a property in the $compile service that fixes this problem. adding the attribute bindToController:true to the directive takes all of the variables defined in your scope attribute and attaches them to the controller rather then the scope itself meaning the 2 way data binding is to the variable on the controller rather then the variable on the scope. so the end result has these changes

in your directive definition

scope:{
    parent:"=scope"
},
bindToController:true,

and in the controller remove the this.parent=$scope.parent

here is an updated jsfiddle

Upvotes: 1

Xavero
Xavero

Reputation: 3389

Change:

template:"<div>{{child.parent}}</div>",
controller:['$scope',function($scope){ this.parent=$scope.parent; }]

To:

template:"<div>{{parent}}</div>"
controller:function(){ }

since you are using controllerAs syntax, you dont need the $scope injection. For the binding work as expected, you dont use child.parent, only parent (or whatever you inject in the this context on your controller

Upvotes: 1

Related Questions