AngularJS multiple uses of Controller and rootScope
Solution 1
I would suggest to use a service that holds the menu and its methods. The service will update the menu which is referenced by the controller(s).
See a working plunker here: http://plnkr.co/edit/Bzjruq
This is the sample JavaScript code:
angular
.module( 'sampleApp', [] )
.service( 'MenuService', [ '$rootScope', function( $rootScope ) {
return {
menu: [ 'item 1' ],
add: function( item ) {
this.menu.push( item );
}
};
}])
.controller( 'ControllerA', [ 'MenuService', '$scope', function( MenuService, $scope ) {
$scope.menu = MenuService.menu;
$scope.addItem = function() {
MenuService.add( $scope.newItem );
};
}]);
And the sample Html page:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="sampleApp">
<div ng-controller="ControllerA">
<ul>
<li ng-repeat="item in menu">{{item}}</li>
</ul>
<input type="text" ng-model="newItem" /><input type="submit" ng-click="addItem()" />
</div>
<div ng-controller="ControllerA">
<ul>
<li ng-repeat="item in menu">{{item}}</li>
</ul>
</div>
</body>
</html>
Solution 2
Edit:
Here is the updated version plunker. it works in two controller.
Main idea is using service and broadcast to sync the data with the directive.
app.service('syncSRV', function ($rootScope) {
"use strict";
this.sync = function (data) {
this.syncData = data;
$rootScope.$broadcast('updated');
};
});
app.controller('MainCtrl1', ['$scope', function ($scope) {
}])
.controller('MainCtrl2', ['$scope', function ($scope) {
}]);
app.directive('sync',function (syncSRV) {
"use strict";
return {
template: '<div><input ng-model="syncdata" type="text" /></div> ',
controller: function ($scope, $element, $attrs) {
$scope.$watch('syncdata', function (newVal, oldVal, $scope) {
syncSRV.sync(newVal);
}, true);
}
};
}).directive('dataview', function (syncSRV) {
"use strict";
return {
template: '<div>Sync data : {{data}}</div> ',
controller: function ($scope, $element, $attrs) {
$scope.$on('updated', function () {
$scope.data = syncSRV.syncData;
});
}
};
});
<div ng-controller="MainCtrl1">
<fieldset>
<legend> Controller 1</legend>
<div dataview></div>
<div sync></div>
</fieldset>
</div>
<div ng-controller="MainCtrl2">
<fieldset>
<legend> Controller 2</legend>
<div dataview></div>
<div sync></div>
</fieldset>
</div>
Here is what I would do for this case.
I will create a directive for
<ul class="nav" ng-controller="Menu">
<li ng-repeat="item in menu">
<a href="{{item.href}}">{{item.title}}</a>
</li>
</ul>
so once item is updated, it will be updated in both directive.
Solution 3
I just want to update and simplify the selected answer. It seems you can reduce this by deleting this line:
$rootScope.$broadcast( 'MenuService.update', this.menu );
and this chunk:
$scope.$on( 'MenuService.update', function( event, menu ) {
$scope.menu = menu;
});
The reason being, we are already using a Service, and that basically binds the two identical controllers, so no need to use $rootScope.$broadcast and add an observable.
Working plunk here: http://plnkr.co/edit/1efEwU?p=preview
You only need to link the service, when I refactor the code I was able to reduce it to 13 lines instead of 22.
Pete
I'm a web developer/full stack developer/programmer/nerd/internet person what ever you want to call me, I currently make websites and APIs, with CFML(ACF and Lucee), Node.js and Vue.js. I've done some Native iOS and Phonegap/Cordova iOS and Android work in the past. I'll can fix a computer, manage servers, monitor logs, build databases, optimize queries, shrink download sizes, speed up sites, write back end code, build front end interfaces, analyze user behaviours, get conversions and leads... just don't ask me to design anything. I'm a father, husband, 1st degree taekwondo black belt and Grade 2 guitarist who likes drawing, driving, gaming and all the usual sci-fi nerd stuff.
Updated on July 05, 2022Comments
-
Pete almost 2 years
I want to use a controller on 2 seperated HTML elements, and use the $rootScope to keep the 2 lists in sync when one is edited:
HTML
<ul class="nav" ng-controller="Menu"> <li ng-repeat="item in menu"> <a href="{{item.href}}">{{item.title}}</a> </li> </ul> <div ng-controller="Menu"> <input type="text" id="newItem" value="" /> <input type="submit" ng-click="addItem()" /> <ul class="nav" ng-controller="Menu"> <li ng-repeat="item in menu"> <a href="{{item.href}}">{{item.title}}</a> </li> </ul> </div>
JS
angular.module('menuApp', ['menuServices']). run(function($rootScope){ $rootScope.menu = []; }); angular.module('menuServices', ['ngResource']). factory('MenuData', function ($resource) { return $resource( '/tool/menu.cfc', { returnFormat: 'json' }, { getMenu: { method: 'GET', params: {method: 'getMenu'} }, addItem: { method: 'GET', params: {method: 'addItem'} } } ); }); function Menu($scope, MenuData) { // attempt to add new item $scope.addNewItem = function(){ var thisItem = $('#newItem').val(); MenuData.addItem({item: thisItem},function(data){ $scope.updateMenu(); }); } $scope.updateMenu = function() { MenuData.getMenu({},function(data){ $scope.menu = data.MENU; }); } // get menu data $scope.updateMenu(); }
When the page loads, both the
UL
and theDIV
display the correct contents from the database, but when i use theaddNewItem()
method only theDIV
gets updated.Is there a better way to structure my logic, or can I do something to make sure the
$scope.menu
in theUL
gets updated at the same time?Here's an example of something similar: http://plnkr.co/edit/2a55gq
-
Pete over 11 yearsYour example only has 1 controller, would that still work across 2 different controllers? e.g.: plnkr.co/edit/2a55gq. I'm restricted in how I can modify my page HTML
-
Pete over 11 yearsThat's the stuff, I was just looking into this after you posted that comment, thanks!
-
KajMagnus about 10 yearsWon't
$scope.menu
automatically be updated whenMenuSerice.add
is called, even without the$rootScope.$broadcast
and$scope.$on
stuff? Since$scope.menu
points directly toMenuService.menu
, it's not a copy of it. -
David Riccitelli about 10 years@KajMagnus thanks, I updated the answer and the related Plunker.
-
spaffy about 9 yearsSo is it a very bad practice to attach same controller to many view elements? Or are there any times during development, that such solution is acceptable? I see no errors in webdev tools console, when running webapp which has such dirty hack (?).