Что является хорошей практикой для доступа / изменения простых свойств родительского контроллера при использовании синтаксиса controllerAs
? См. Пример ниже. Мне не нравится обращаться к ним через $scope.$parent.parent
. Как вы, ребята, справляетесь с подобными ситуациями, не создавая сервис для такой тривиальной логики.
<div ng-controller="Parent as parent">
<div ng-if="parent.showMessage">
Some simple message.
</div>
<div ng-controller="ChildOne as childOne"></div>
</div>
app.controller('Parent', function () {
var self = this;
self.showMessage = true;
});
app.controller('ChildOne', function ($scope) {
var self = this;
self.foo = 'bar';
// Some simple logic.
if (self.foo === 'bar') {
$scope.$parent.parent.showMessage = false;
}
});
Можете привести реальный пример? Я могу думать только о ситуациях, когда родитель уже знает объект, который дочерние контроллеры будут использовать / изменять, и что вы передаете этот объект дочерним контроллерам через data-ng-model. Если вы сделаете это, родительский контроллер получит доступ к объекту. Таким образом, вашим контроллерам не нужно знать друг друга или область действия друг друга.
Или вы делаете что-то другое, чем я думаю?
@dietergeerts благодарит за ваш вклад. В вашем примере передача примитивного значения дочернему элементу с помощью ng-model не влияет на то, когда дочерний элемент изменяет это значение.
Мне в основном нужно показать первый div, если в дочернем элементе верна некоторая простая логика.
(ChildOne привязан к маршруту, поэтому я не могу просто вставить первый div в дочерний элемент)
@Bekt , это может иметь такой эффект, поскольку data-ng-if может быть = "parent.object.property == 'some_value'", конечно, в зависимости от того, что такое логика и насколько сложной должна быть эта логика.
Если они установлены через маршруты с помощью ui-router и являются дочерними маршрутами, то они оба могут использовать объект.
Как правило, это очень плохая идея - просить что-то у родителя, так как это означает, что контроллер не является самодостаточным, что им и нужно. Обычно существует гораздо лучший способ сделать такое «общение». Вот почему я спрашивал о реальной ситуации, которая у вас есть, поскольку могут быть лучшие способы делать то, что вы хотите.
мне нравится, когда вещи не связаны. НО есть несколько абсолютов ... в общем, мои директивы, мои контроллеры, мои сервисы ... Мне нравится, чтобы они были самодостаточными, и если им нужны внешние аспекты, я их ввожу или привязываю. Я не люблю полагаться на что-то, что будет использоваться в конкретном контексте. Есть смысл?
Я бы решил эту директиву инкапсулировать дочерний контроллер, например:
<div ng-controller="Parent as parent">
<div ng-if="parent.showMessage">
Some simple message.
</div>
<div child-one parent="parent"></div>
</div>
app.controller('Parent', function () {
var self = this;
self.showMessage = true;
});
app.directive('childOne', function() {
return {
controllerAs: 'childOne',
controller: function($scope, $attrs) {
var parent = $scope.$eval($attrs.parent);
var self = this;
self.foo = 'bar';
// Some simple logic.
if (self.foo === 'bar') {
parent.showMessage = false;
}
}
};
});
Или использовать ng-init на втором контроллере.
<div ng-controller="ChildOne as childOne" ng-init="childOne.setParent(parent)"></div>
Используя более компонентно-ориентированный подход:
<html ng-app="myApp">
<body>
<div ng-controller="ParentCtrl as vm">
<my-directive on-foo-eq-bar="vm.updateMessage(msg)"></my-directive>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script>
angular.module('myApp', [])
.controller('ParentCtrl', function($window) {
var vm = this;
vm.updateMessage = function(msg) {
$window.alert(msg);
};
})
.directive('myDirective', function() {
return {
scope: {
onFooEqBar:'&'
},
controllerAs:'vm',
controller: function($scope) {
var self = this;
self.foo = 'bar';
// Some simple logic.
if (self.foo === 'bar') {
$scope.onFooEqBar({msg: false});
}
}
};
});
</script>
</body>
</html>
@dbabaioff @leandrocosta : спасибо, интересные предложения.
В итоге я выбрал $on
для родителя и $broadcast
для детей.
хороший разговор, но тут нечего добавить к гайду, ИМО
: +1:
в вашем родительском контроллере подпишитесь на событие в $ rootScope
$rootScope.$on('myEvent', function(data){/*do something*/})
затем в дочернем элементе запустите событие, используя $ rootScope
$rootScope.$emit('myEvent', someData);
Имхо, гораздо лучше иметь 2 компонента вместо контроллеров и при необходимости вводить свойства в дочерний компонент, а если вы хотите их установить, выводите что-то из дочернего в родительский. Гораздо эффективнее и проще рассуждать + проще модульное тестирование.
Использование $ rootScope и обработка событий в настоящее время больше не используются.
Вы можете проверить, существует ли свойство, а затем присвоить значение, как показано ниже.
if ($ scope. $ parent.showMessage) {
var parent = $ scope. $ parent;
while (! parent.hasOwnProperty ('showMessage')) {
родитель = родитель ['$ родитель'];
}
parent.showMessage = false;
}
Извините за некро, но на всякий случай, если кто-то еще приземлится здесь, моим решением было бы преобразовать дочерний контроллер непосредственно в компонент, а затем привязать функцию обновления от родителя к дочернему, как показано ниже:
<div ng-controller="Parent as parent">
<div ng-if="parent.showMessage">
Some simple message.
</div>
<child-one update-parent="parent.showMessage = value"></child-one>
</div>
app.controller('Parent', function () {
var self = this;
self.showMessage = true;
});
app.component('childOne', /* component def stuff including updateParent: '&' in bindings */);
function childOneController() {
var self = this;
self.foo = 'bar';
// Some simple logic.
if (self.foo === 'bar') {
self.updateParent({value: false});
}
});
Самый полезный комментарий
Используя более компонентно-ориентированный подход: