Angular-styleguide: Хорошая практика для доступа к свойствам родительского контроллера

Созданный на 28 июл. 2015  ·  13Комментарии  ·  Источник: johnpapa/angular-styleguide

Что является хорошей практикой для доступа / изменения простых свойств родительского контроллера при использовании синтаксиса 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;
    }
});
question

Самый полезный комментарий

Используя более компонентно-ориентированный подход:

<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>

Все 13 Комментарий

Можете привести реальный пример? Я могу думать только о ситуациях, когда родитель уже знает объект, который дочерние контроллеры будут использовать / изменять, и что вы передаете этот объект дочерним контроллерам через 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});
    }
});
Была ли эта страница полезной?
0 / 5 - 0 рейтинги