I have the below HTML on a page:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="myCart">
<head>
<title>AngularJS Shopping Cart</title>
<link href="css/jsonstore.css" rel="stylesheet" />
</head>
<body>
<div id="container">
<div id="header">
<h1>The JSON Store</h1>
<div class="cart-info">
My Cart (<span class="cart-items">{{item.basketCount}}</span> items)
</div>
</div>
<div id="main" ng-view>
</div>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular-resource.js"></script>
<script src="js/routing.js"></script>
<script src="js/dataresource.js"></script>
<script src="js/basketinfo.js"></script>
<script src="js/index.js"></script>
<script src="js/detail.js"></script>
</body>
</html>
The div "main" gets replaced by HTML templates by my routes however I would like to update the header section with a shopping basket count.
I have tried model binding it as shown in the HTML and below:
function DetailController($scope, item, basketDetail) {
$scope.item = item;
$scope.item.basketCount = basketDetail.getCount();
//more code
}
I've also tried just injecting the service and calling it from the HTML. Both ways do not do anything.
Can someone help please?
Thanks
Your header
div is really a view, just like the other views you've defined for use with ng-view. Someday, you might want to show more than just a basketCount model in that header view. But the fact that you are projecting even one piece of model data into that header section makes that section a view. So, I would recommend that be given its own $scope to project that model, hence its own controller.
What remains then is where to put the basketCount model? And we must consider that multiple views may allow the user to do something that need to affect that model. Angular's normal answer for "many need access" is dependency injection. So, I would put the basketCount model into a service. Views/controllers that need access to it can inject it. Someday your app may have additional views that don't need access to these models, so those views would not inject the service.
Potentially, the entire basket could be modeled in this service:
app.factory('basketService', function() {
return {
items: [],
itemCount: 0,
...
}
});
function HeaderCtrl($scope, basketService) {
$scope.basket = basketService;
...
}
function DetailCtrl($scope, basketService) {
$scope.basket = basketService;
...
}
<div id="header" ng-controller="HeaderCtrl">
<h1>The JSON Store</h1>
<div class="cart-info">
My Cart (<span class="cart-items">{{basket.itemCount}}</span> items)
</div>
You'll need to inject $rootScope, then update it:
function DetailController($scope, $rootScope, basketDetail) {
$rootScope.item = $rootScope.item || {};
$rootScope.item.basketCount = basketDetail.getCount();
//more code
}
There are a lot more ways to do this, but this is my first suggestion, because it's probably the easiest.
EDIT: per your request, other ways to do this...
You could use $parent to push to your parent scope. The upside is it's pretty quick and clean... the downside is it's a little sloppy in that one of your controllers makes assumptions about what it's parent is to some degree (but that's still not terrible, really):
{{item.basketCount}}
<div ng-controller="InnerCtrl">
</div>
function InnerCtrl($scope, basketDetail) {
$scope.$parent.item = $scope.$parent.item || {};
$scope.$parent.item.basketCount = basketDetail.getCount();
}
Then there's the method @asgoth mentioned above where you use nested controller and a method on the parent scope to update the parent scope. Valid, but like my other solution in this "other ways to do it" section, it relies on assumptions made about the controller's container, and it also relies on you creating an additional controller.
Finally, you could create a service. Now services aren't generally used this way, but you could use one this way.. Where you could take your basketDetail service, and use it to pass the value back and forth. Like so:
app.factory('basketDetail', function() {
return {
items: { basketCount: 0 },
getCount: function() {
//return something here
return 123;
}
}
});
function FooCtrl($scope, basketDetail) {
$scope.items = basketDetail.items;
$scope.items.basketCount = basketDetail.getCount();
}
function BarCtrl($scope, basketDetail) {
$scope.items = basketDetail.items;
}
<div ng-controller="FooCtrl">
{{items.basketCount}}
</div>
<div ng-controller="BarCtrl">
{{items.basketCount}}
</div>
This works because the $scope in both controllers is keeping a reference to the same object, which is maintained by your basketDetail service. But again, this isn't really the recommended way.
All of that said: $rootScope, IMO is most likely what you're looking for.
No real need for $rootScope
. Create a parent controller (e.g. RootController
) with a function on its scope. The child scopes will automatically inherit it:
<div id="container" ng-controller="RootController">
...
function RootController($scope) {
$scope.item = {};
$scope.setBasketCount = function (detail) {
$scope.item.basketCount = detail.getCount();
}
}
In your detail controller you just use the setBasketCount()
function:
function DetailController($scope, item, basketDetail) {
$scope.item = item;
$scope.setBasketCount(basketDetail);
//more code
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With