I am pretty new to the AngularUI Router and would like the use it for the following scenario:
The layout common to all pages includes a top navbar c
$scope is not the model, its a reference to a model, glue in between the data & the view. If $scopes in two, or more, controllers need to share one model/state/data use a singleton object instance by registering a angular service. That one service/factory can be injected into as many controllers as you like, and then everything can work off that one source of truth.
Heres a demo of 1 factory linking $scopes in navbar & body with ui-router http://plnkr.co/edit/P2UudS?p=preview (left tab only)
ui-router (viewC is navbar):
$stateProvider
.state('left', {
url: "/",
views: {
"viewA": {
controller: 'LeftTabACtrl',
template: 'Left Tab, index.viewA <br>' +
'<input type="checkbox" ng-model="selected2.data" />' +
'<pre>selected2.data: {{selected2.data}}</pre>'
},
{...},
"viewC": {
controller: 'NavbarCtrl',
template: '<span>Left Tab, index.viewC <div ui-view="viewC.list"></div>' +
'<input type="checkbox" ng-model="selected.data" />' +
'<pre>selected.data: {{selected.data}}</pre></span>'
}
}
})
Factory & Controllers:
app.factory('uiFieldState', function () {
return {uiObject: {data: null}}
});
app.controller('NavbarCtrl', ['$scope', 'uiFieldState', '$stateParams', '$state',
function($scope, uiFieldState, $stateParams, $state) {
$scope.selected = uiFieldState.uiObject;
}
]);
app.controller('LeftTabACtrl', ['$scope', 'uiFieldState', '$stateParams', '$state',
function($scope, uiFieldState, $stateParams, $state) {
$scope.selected2 = uiFieldState.uiObject;
}
]);
As you can see, the factory object {uiObject: {data: null}}
is injected into the controller with uiFieldState
& then its simply $scope.selected = uiFieldState.uiObject;
for connecting the factory to the scope ng-model="selected.data"
.`
You should use:
$on and $emit
The emit controller, that sends the data.
angular.module('MyApp').controller('MyController', ['$scope', '$rootScope', function ($scope, $rootScope){
$rootScope.$emit('SomeEvent', data);
}]);
An example of how to implement $rootScope a safe way so it destroys and fixes stuff after use:
angular
.module('MyApp')
.config(['$provide', function($provide){
$provide.decorator('$rootScope', ['$delegate', function($delegate){
Object.defineProperty($delegate.constructor.prototype, '$onRootScope', {
value: function(name, listener){
var unsubscribe = $delegate.$on(name, listener);
this.$on('$destroy', unsubscribe);
},
enumerable: false
});
return $delegate;
}]);
}]);
And the controller with the data that should be treated.
angular.module('MyApp')
.controller('MySecondController', ['$scope', function MyController($scope) {
$scope.$onRootScope('SomeEvent', function(event, data){
console.log(data);
});
}
]);
You could pass in $rootScope instead of using the $scopes method $onRootScope that we defined in the config. However, this is not a recommended way of using $emit and $onRootScope.
Instead of using $emit, you could always use $broadcast. This would however give you very huge performance issues as your app grows. Since it bubbles the data through all controllers.
If your controllers are parents and child to each other, they don't have to use the $rootScope.
Here is and example of the difference between $emit and $broadcast: jsFiddle
And their is really performance differences: