Reputation: 1266
I have a directive pr-items
rendering instances of child-directives pr-item
using a template and ng-repeat
:
app.directive('prItems', function(){
console.log('prItems');
return {
restrict: 'E',
scope: {
items:'=',
},
template:'<pr-item ng-repeat="item in items"></pr-item>',
...
});
The child directive pr-item
renders content using another template:
app.directive('prItem', function($compile){
console.log('prItem');
return {
restrict: 'E',
template: '<div ng-style="{\'border-style\':item.border_style, \'color\':item.color}" style="cursor:pointer;"><span ng-if="item.selected">* </span>{{item.name}} {{item.selected}}</div>',
...
});
This works fine so far.
On a click on the item, the parent directive gets notified using an event via $emit
. When the parent element changes state of one of the items, this change does not show up in the respective item as demonstrated in this Plunk.
Now I am curious what I'm missing.
Upvotes: 0
Views: 53
Reputation: 11190
Here is a corrected Plunk
I've tried to note my changes (as opposed to your version)
app.directive('prItems', function(){
console.log('prItems');
return {
restrict: 'E',
scope: {
items:'=',
},
template:'<pr-item ng-repeat="item in items"></pr-item>',
link: function (scope, elem, attr) {
console.log('prItems.link, scope.$id = ' + scope.$id);
scope.$on('onSelecting', function (event, item) {
console.log('prItems: onSelecting ' + item.name);
//clear the selected flag for the other items
angular.forEach(scope.items, function (value) {
if (value.selected) {
//console.log(value);
value.selected = false;
}
});
//set it for the item that was sent in
item.selected = true;
//change, no $scope.$apply - not needed here
});
}
};
});
app.directive('prItem', function($compile){
console.log('prItem');
return {
restrict: 'E',
//ng-style will change camel case to - case borderStyle works (instead of using 'border-style' with escaped quotes.
template: '<div ng-style="{borderStyle:item.border_style, \'color\':item.color}" style="cursor:pointer;">CLICK ME: <span ng-if="item.selected">* </span>{{item.name}} {{item.selected}}</div>',
controller: function ($scope, $element) {
console.log('prItem.controller, $scope.$id = ' + $scope.$id);
//I left this in as-is, but there is a better way to do this by just using the template ($watch shouldn't be required)
$scope.$watch('item.selected', function (val) {
console.log('prItem.selected ' + $scope.item.name + ' changed to ' + val);
$scope.item.border_style = val ? 'solid' : 'none';
//console.log('$scope.item.border_style = ' + $scope.item.border_style);
});
},
link: function (scope, elem, attr) {
console.log('prItem.link ' + scope.item.name + ', scope.$id = ' + scope.$id);
elem.on('mousedown touchdown', function () {
//console.log('touché!');
//scope.$apply should "wrap" non-angular code. In the old version , you were calling scope.$apply() inline
scope.$apply(function(){
scope.$emit('onSelecting', scope.item);
//instead of changing scope.selected, change item.selected - this change was probably not necessary
item.selected = !item.selected;
});
//old $scope.$apply();
});
}
};
});
EDIT: Without $watch
app.directive('prItem', function($compile){
console.log('prItem');
return {
restrict: 'E',
//ng-style will change camel case to - case borderStyle works (instead of using 'border-style' with escaped quotes.
template: '<div ng-style="{borderStyle:item.selected ? \'solid\' : \'none\', \'color\':item.color}" style="cursor:pointer;">CLICK ME: <span ng-if="item.selected">* </span>{{item.name}} {{item.selected}}</div>',
controller: function ($scope, $element) {
console.log('prItem.controller, $scope.$id = ' + $scope.$id);
},
link: function (scope, elem, attr) {
console.log('prItem.link ' + scope.item.name + ', scope.$id = ' + scope.$id);
elem.on('mousedown touchdown', function () {
//console.log('touché!');
//scope.$apply should "wrap" non-angular code. In the old version , you were calling scope.$apply() inline
scope.$apply(function(){
scope.$emit('onSelecting', scope.item);
//instead of changing scope.selected, change item.selected - this change was probably not necessary
item.selected = !item.selected;
});
//old $scope.$apply();
});
}
};
});
Upvotes: 1