AngularJS acessa o escopo pai do controlador filho

382

Eu configurei meus controladores usando data-ng-controller="xyzController as vm"

Eu tenho um cenário com controladores aninhados pai / filho. Não tenho problemas para acessar as propriedades pai no html aninhado usando $parent.vm.property, mas não consigo descobrir como acessar a propriedade pai no meu controlador filho.

Eu tentei injetar $ scope e depois usar $scope.$parent.vm.property, mas isso não está funcionando?

Alguém pode oferecer conselhos?

zpydee
fonte

Respostas:

620

Se o seu HTML é como abaixo, você pode fazer algo assim:

<div ng-controller="ParentCtrl">
    <div ng-controller="ChildCtrl">
    </div>
</div>

Em seguida, você pode acessar o escopo pai da seguinte maneira

function ParentCtrl($scope) {
    $scope.cities = ["NY", "Amsterdam", "Barcelona"];
}

function ChildCtrl($scope) {
    $scope.parentcities = $scope.$parent.cities;
}

Se você deseja acessar um controlador pai na sua exibição, precisa fazer algo assim:

<div ng-controller="xyzController as vm">
   {{$parent.property}}
</div>

Veja jsFiddle: http://jsfiddle.net/2r728/

Atualizar

Na verdade, desde que você definiu citiesno controlador pai, seu controlador filho herdará todas as variáveis ​​de escopo. Então, teoricamente, você não precisa ligar $parent. O exemplo acima também pode ser escrito da seguinte maneira:

function ParentCtrl($scope) {
    $scope.cities = ["NY","Amsterdam","Barcelona"];
}

function ChildCtrl($scope) {
    $scope.parentCities = $scope.cities;
}

Os documentos do AngularJS usam essa abordagem, aqui você pode ler mais sobre o $scope.

Outra atualização

Eu acho que essa é uma resposta melhor para o pôster original.

HTML

<div ng-app ng-controller="ParentCtrl as pc">
    <div ng-controller="ChildCtrl as cc">
        <pre>{{cc.parentCities | json}}</pre>
        <pre>{{pc.cities | json}}</pre>
    </div>
</div>

JS

function ParentCtrl() {
    var vm = this;
    vm.cities = ["NY", "Amsterdam", "Barcelona"];
}

function ChildCtrl() {
    var vm = this;
    ParentCtrl.apply(vm, arguments); // Inherit parent control

    vm.parentCities = vm.cities;
}

Se você usar o controller asmétodo, também poderá acessar o escopo pai da seguinte maneira

function ChildCtrl($scope) {
    var vm = this;
    vm.parentCities = $scope.pc.cities; // note pc is a reference to the "ParentCtrl as pc"
}

Como você pode ver, existem muitas maneiras diferentes de acessar $scopes.

Violino atualizado

function ParentCtrl() {
    var vm = this;
    vm.cities = ["NY", "Amsterdam", "Barcelona"];
}
    
function ChildCtrl($scope) {
    var vm = this;
    ParentCtrl.apply(vm, arguments);
    
    vm.parentCitiesByScope = $scope.pc.cities;
    vm.parentCities = vm.cities;
}
    
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.min.js"></script>
<div ng-app ng-controller="ParentCtrl as pc">
  <div ng-controller="ChildCtrl as cc">
    <pre>{{cc.parentCities | json}}</pre>
    <pre>{{cc.parentCitiesByScope | json }}</pre>
    <pre>{{pc.cities | json}}</pre>
  </div>
</div>

Dieterg
fonte
6
Acho que os dois problemas com sua última atualização são: 1. Herdar o escopo pai pode ter potenciais conflitos de espaço para nome e 2. Requer conhecimento de que o alias do controlador pai é 'pc'. Isso dificulta a reutilização.
tchen 31/07
2
Você definiu controladores como a função CtrlName (...) {}, mas como podemos conseguir isso usando a nomenclatura angular? como: angular.module (MdlName) .controller (CtrlName, function (...) {});
Pedro Justo
11
O que você quer dizer? Um controlador é apenas uma função? ieangular.module('app').controller('ParentCtrl', ParentCtrl);
Dieterg 3/14/14
11
desculpe, você está certo! No método 'controller as', usando '$ scope.pc.cities;' acessar as cidades dos pais me parece um 'retrocesso', porque se em childCtrl não tivermos a propriedade 'cidades', ele acessará automaticamente as cidades dos pais. Não há outra maneira de resolver este problema?
Pedro Justo
46

Acabei de verificar

$scope.$parent.someProperty

funciona para mim.

e será

{{$parent.someProperty}}

para a vista.

Stepan Suvorov
fonte
hmmm, não está funcionando para mim. Gostaria de saber se isso tem a ver com o controlador como sintaxe vm.
zpydee
Se você nomeou o controlador pai, então você iria cair $ pai no modelo e tem {{vm.someProperty}}
solbs
8

Quando você estiver usando a assintaxe, como ParentController as parentCtrl, para definir um controlador e acessar a variável de escopo pai no controlador filho, use o seguinte:

var id = $scope.parentCtrl.id;

Onde parentCtrlé o nome do controlador pai usando assintaxe e idé uma variável definida no mesmo controlador.

Rubi saini
fonte
2

Algumas vezes, pode ser necessário atualizar as propriedades pai diretamente no escopo filho. por exemplo, é necessário salvar uma data e hora do controle pai após alterações de um controlador filho. por exemplo, código no JSFiddle

HTML

<div ng-app>
<div ng-controller="Parent">
    event.date = {{event.date}} <br/>
    event.time = {{event.time}} <br/>
    <div ng-controller="Child">
        event.date = {{event.date}}<br/>
        event.time = {{event.time}}<br/>
        <br>
        event.date: <input ng-model='event.date'><br>
        event.time: <input ng-model='event.time'><br>
    </div>
</div>

JS

    function Parent($scope) {
       $scope.event = {
        date: '2014/01/1',
        time: '10:01 AM'
       }
    }

    function Child($scope) {

    }
Gayan Pathirage
fonte
1

Você também pode contornar a herança do escopo e armazenar coisas no escopo "global".

Se você tiver um controlador principal em seu aplicativo que agrupe todos os outros controladores, poderá instalar um "gancho" no escopo global:

function RootCtrl($scope) {
    $scope.root = $scope;
}

Em qualquer controlador filho, você pode acessar o escopo "global" com $scope.root. Tudo o que você definir aqui será visível globalmente.

Exemplo:

function RootCtrl($scope) {
  $scope.root = $scope;
}

function ChildCtrl($scope) {
  $scope.setValue = function() {
    $scope.root.someGlobalVar = 'someVal';
  }
}

function OtherChildCtrl($scope) {
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app ng-controller="RootCtrl">
  
  <p ng-controller="ChildCtrl">
    <button ng-click="setValue()">Set someGlobalVar</button>
  </p>
  
  <p ng-controller="OtherChildCtrl">
    someGlobalVar value: {{someGlobalVar}}
  </p>

</div>

rustyx
fonte
Isso realmente não escala. É como definir variáveis ​​globais que devem ser únicas em muitos arquivos / contextos.
ZachB
Eu não vejo uma questão de escala, mas chamando a variável âmbito algo diferente de 'root' pode ser melhor em outros contextos
Nico Westerdale
Também é um pouco incômodo ter um estado que permanece por mais tempo do que a vida útil da subárvore de componente que precisa.
Roboprog 28/03/19
0

Eu acredito que tive um dilema semelhante recentemente

function parentCtrl() {
   var pc = this; // pc stands for parent control
   pc.foobar = 'SomeVal';
}

function childCtrl($scope) {

   // now how do I get the parent control 'foobar' variable?
   // I used $scope.$parent

   var parentFoobarVariableValue = $scope.$parent.pc.foobar;

   // that did it
}

Minha configuração era um pouco diferente, mas a mesma coisa provavelmente ainda deve funcionar

Benjamin Thvedt
fonte
0

Em um componente filho, é possível acessar as propriedades e métodos do componente pai com 'require'. Aqui está um exemplo:

Pai:

.component('myParent', mymodule.MyParentComponent)
...
controllerAs: 'vm',
...
var vm = this;
vm.parentProperty = 'hello from parent';

Criança:

require: {
    myParentCtrl: '^myParent'
},
controllerAs: 'vm',
...
var vm = this;
vm.myParentCtrl.parentProperty = 'hello from child';
Donato Szilagyi
fonte
0

Super fácil e funciona, mas não sei por que ....

angular.module('testing')
  .directive('details', function () {
        return {
              templateUrl: 'components/details.template.html',
              restrict: 'E',                 
              controller: function ($scope) {
                    $scope.details=$scope.details;  <=== can see the parent details doing this                     
              }
        };
  });
John Peters
fonte
-1

Talvez isso seja ruim, mas você também pode apontar os dois para algum objeto externo:

var cities = [];

function ParentCtrl() {
    var vm = this;
    vm.cities = cities;
    vm.cities[0] = 'Oakland';
}

function ChildCtrl($scope) {
    var vm = this;
    vm.cities = cities;
}

O benefício aqui é que as edições no ChildCtrl agora se propagam de volta aos dados no pai.

Peter Hollingsworth
fonte
a introdução de variáveis ​​globais é perigosa.
Dementic