There are many approaches to solving this issue. One simple way, like the one you mentioned, is to use function binding to handle the click event or implement 2-way binding.
Using 2-way binding
<div ng-app="Shop" ng-controller="MainCtrl">
<shop-item price="100" total="total"></shop-item>
</div>
Instead of manually binding the event handler in the directive, use angular's events, for 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;
}
}
};
});
Check Plnkr for Demo
Using Function Binding
Another approach is to use function binding where the controller handles the price calculation instead of the directive. This separation of concerns can make the code easier to manage and understand. For example:
<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 (adding a discount of 5% as an example):
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;
}
}
};
});
Check Plnkr for Demo
Using Event Bus
Alternatively, you can utilize the angular event bus by utilizing $emit
or $broadcast
with $on
. The choice between $emit/$broadcast depends on the DOM element hierarchy. An example:
<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;
});
Check Plnkr for Demo