Два взгляда в одном из разделов общего доступа в режиме AngularUI Router
Я новичок в AngularUI Router и хотел бы использовать его для следующего сценария:
Макет , общий для всех страниц, включает верхнюю панель навигации, содержащую меню с кнопками справа и раздел содержимого, заполняющий пробел ниже. На странице есть несколько страниц, которые я сопоставляю с состояниями интерфейса UI (стр. 1, стр. 2,...). Каждая страница может иметь свои собственные пункты меню и собственный контент. Меню должно совместно использовать область с содержимым, поскольку они взаимодействуют (например, кнопка сохранения представляет форму в контенте, она должна быть включена только в том случае, если форма действительна).
![mockup]()
HTML выглядит примерно так:
<body>
<nav class="...">
<h1>my site</h1>
<div>MENU SHOULD GO HERE</div>
</nav>
<div class="row">
<div class="column ...">
CONTENT SHOULD GO HERE
</div>
</div>
</body>
Сейчас я использую два параллельных представления и два контроллера для каждого состояния. Но этот способ не может взаимодействовать с двумя областями/контроллерами.
Итак, как бы вы это сделали?
Ответы
Ответ 1
$scope - это не модель, ее ссылка на модель, склейка между данными и представлением. Если $scopes в двух или более контроллерах необходимо разделить одну модель/состояние/данные, используйте экземпляр объекта singleton, зарегистрировав службу angular. Эта одна услуга /factory может быть введена в любое количество контроллеров, как вам нравится, и тогда все может сработать с одним источником истины.
Вот пример 1 factory, связывающий $scopes в navbar и body с ui-router http://plnkr.co/edit/P2UudS?p=preview (только левая вкладка)
ui-router (viewC - 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 и контроллеры:
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;
}
]);
Как вы можете видеть, объект factory {uiObject: {data: null}}
вводится в контроллер с помощью uiFieldState
, а затем его просто $scope.selected = uiFieldState.uiObject;
для подключения factory к области ng-model="selected.data"
.
Ответ 2
Вы должны использовать:
$on and $emit
Испускающий контроллер, который отправляет данные.
angular.module('MyApp').controller('MyController', ['$scope', '$rootScope', function ($scope, $rootScope){
$rootScope.$emit('SomeEvent', data);
}]);
Пример того, как реализовать $rootScope безопасный способ, чтобы он уничтожал и исправлял материал после использования:
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;
}]);
}]);
И контроллер с данными, которые следует обрабатывать.
angular.module('MyApp')
.controller('MySecondController', ['$scope', function MyController($scope) {
$scope.$onRootScope('SomeEvent', function(event, data){
console.log(data);
});
}
]);
Вы можете передать $rootScope вместо использования метода $scopes $onRootScope, который мы определили в конфиге. Однако это не рекомендуется использовать $emit и $onRootScope.
Вместо использования $emit вы всегда можете использовать $broadcast. Это, тем не менее, даст вам очень большие проблемы с производительностью, так как ваше приложение растет. Так как это пузырьки данных через все контроллеры.
Если ваши контроллеры являются родителями и дочерьми друг к другу, им не нужно использовать $rootScope.
Вот и пример разницы между $emit и $broadcast: jsFiddle
И их действительно отличия в производительности:
![enter image description here]()