Angular-styleguide: Boa prática para acessar as propriedades do controlador pai

Criado em 28 jul. 2015  ·  13Comentários  ·  Fonte: johnpapa/angular-styleguide

Usando a sintaxe controllerAs , qual é uma boa prática para acessar / modificar propriedades simples de um controlador pai? Por favor, veja o exemplo abaixo. Não gosto de acessá-los via $scope.$parent.parent . Como vocês lidam com situações semelhantes sem criar um serviço para uma lógica tão trivial?

<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

Comentários muito úteis

Usando uma abordagem mais orientada a componentes:

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

Todos 13 comentários

Você pode dar um exemplo real? Eu só posso pensar em situações em que o pai já conhece o objeto que os controladores filhos usarão / modificarão, e que você dará esse objeto aos controladores filhos por meio do modelo data-ng. Se você fizer isso, o controlador pai pode acessar o objeto. Dessa forma, seus controladores não precisam se conhecer, ou o escopo uns dos outros.

Ou você está fazendo algo diferente do que eu penso?

@dietergeerts, obrigado por sua contribuição. Em seu exemplo, passar um valor primitivo para um filho usando o modelo ng não tem nenhum efeito quando o filho modifica esse valor.

Basicamente, preciso mostrar o primeiro div se alguma lógica simples é verdadeira na criança.

(ChildOne é anexado a uma rota, então não posso simplesmente inserir o primeiro div na criança)

@Bekt , pode ter esse efeito, pois data-ng-if poderia ser = "parent.object.property == 'some_value'", claro, dependendo de qual é a lógica e quão complicada essa lógica precisa ser.

Se forem configurados por meio de rotas com ui-router e forem rotas secundárias, ambos poderão usar o objeto.

Geralmente, é uma ideia muito ruim ter que pedir algo aos pais, pois isso significa que o controlador não é independente, o que eles precisam ser. Geralmente, há uma maneira muito melhor de fazer essa "comunicação". É por isso que eu estava perguntando sobre a situação real que você tem, já que poderia haver maneiras melhores de fazer o que você quer.

eu gosto de manter as coisas desacopladas. MAS existem poucos absolutos ... em geral minhas diretivas, meus controladores, meus serviços ... Eu gosto que sejam autocontidos e se eles precisam de aspectos externos, eu os injeto ou os amarro. Não gosto de depender de algo para ser usado em um contexto específico. Faz sentido?

Eu resolveria isso usando uma diretiva para encapsular o controlador filho, assim:

<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;
            }
        }
    };
});

Ou para usar um ng-init no segundo controlador.

<div ng-controller="ChildOne as childOne" ng-init="childOne.setParent(parent)"></div>

Usando uma abordagem mais orientada a componentes:

<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 : obrigado, sugestões interessantes.

Acabei indo com $on no pai e $broadcast nos filhos.

boa conversa, mas nada a acrescentar aqui ao guia, IMO

: +1:

em seu controlador pai, inscreva-se em um evento em $ rootScope

$rootScope.$on('myEvent', function(data){/*do something*/})

então, no filho, dispare o evento usando $ rootScope

$rootScope.$emit('myEvent', someData);

Imho, é muito melhor ter 2 componentes em vez de controladores e injetar propriedades no componente filho, se necessário, e se você quiser defini-las, imprima algo do filho para o pai. Muito mais desempenho e mais fácil de raciocinar sobre + mais fácil de testar a unidade.

Usar $ rootScope e eventos não é mais feito hoje em dia.

Você pode verificar se a propriedade existe e então atribuir o valor conforme mostrado abaixo.

if ($ scope. $ parent.showMessage) {
var parent = $ scope. $ parent;
while (! parent.hasOwnProperty ('showMessage')) {
pai = pai ['$ pai'];
}
parent.showMessage = false;
}

Desculpe necro isso, mas apenas no caso de alguém pousar aqui, minha solução seria converter o controlador filho diretamente em um componente e, em seguida, vincular uma função de atualização do pai para o filho, da seguinte maneira:

<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});
    }
});
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

Foxandxss picture Foxandxss  ·  13Comentários

bampakoa picture bampakoa  ·  3Comentários

jejja picture jejja  ·  25Comentários

yosiasz picture yosiasz  ·  7Comentários

philmerrell picture philmerrell  ·  10Comentários