Reputation: 331
In my app, I have a shop item directive which has a price attribute. When the user clicks the directive, the total cost (a variable stored in the parent controller) is updated by the price of the clicked item.
However, as of right now, I am not able to transfer the price attribute in the shop item directive to the parent controller. Any help please?
HTML:
<div ng-app="Shop" ng-controller="MainCtrl">
<p>The total is {{ total }}.</p>
<shop-item price="100"></shop-item>
</div>
JavaScript:
var app = angular.module('Shop', []);
app.controller('MainCtrl', ['$scope',
function($scope) {
$scope.total = 0;
}
]);
app.directive('shopItem', function() {
return {
restrict: 'E',
template: '<div class="shop-item">Shop Item</div>',
scope: {
price: '@'
},
link: function(scope, element, attrs) {
element.on('click', function() {
// How can I update the parent scope's total by the attribute 'price' of this directive?
});
}
};
});
Upvotes: 0
Views: 32
Reputation: 123739
There could be many ways to approach this. But a simple directive as yours you could as well use a function binding to register the click event or even use 2-way binding.
2-way binding
<div ng-app="Shop" ng-controller="MainCtrl">
<shop-item price="100" total="total"></shop-item>
</div>
In the directive do not bind the event handler manually instead use angular events, example ng-click
app.directive('shopItem', function() {
return {
restrict: 'E',
/*register an ng-click*/
template: '<div class="shop-item" ng-click="addItem()">Shop Item</div>',
scope: {
price: '@',
total: '=' //<-- 2 way binding
},
link: function(scope, element, attrs) {
scope.addItem = function(){
//increment the price
scope.total = (scope.total || 0) + +scope.price;
}
}
};
});
Function binding
You can also use function binding approach so that you do not handle the price, instead you will just notify about the addCart event with the price, which in your case seems more desirable considering the separation of concerns. So that total calculation is just done by the controller which defines the price and not the cart. But this probably this example you have is too simple to find the difference, but if you were to do it that way then:
<shop-item price="100" total="total" on-add-cart="addToCart(price)"> </shop-item>
In the controller:
$scope.addToCart = function(price){
$scope.total += price;
}
In the directive (as an example i am adding a discount of 5%):
app.directive('shopItem', function() {
return {
restrict: 'E',
/*register an ng-click*/
template: '<div class="shop-item" ng-click="onAddCart({price: (+price)*.95})">Shop Item</div>',
scope: {
price: '@',
onAddCart: '&' //<-- 2 way binding
},
link: function(scope, element, attrs) {
scope.addItem = function(){
//increment the price
scope.total = (scope.total || 0) + +scope.price;
}
}
};
});
Event Bus
Another way is to use the angular event bus. Take a look at various options like $emit
/ $broadcast
with $on
. You may have to choose between $emit/$broadcast based on the hierarchy of the DOM elements.
It will look like:
<shop-item price="100" total="total"> </shop-item>
In the directive:
return {
restrict: 'E',
/*register an ng-click*/
template: '<div class="shop-item" ng-click="onAddCart()">Shop Item</div>',
scope: {
price: '@'
},
link: function(scope, element, attrs) {
scope.onAddCart = function(){
scope.$emit("ITEM_ADDED", +scope.price); //emit an event with price
}
}
};
In the controller:
$scope.$on('ITEM_ADDED', function(e, price){
$scope.total += price;
});
Upvotes: 1