Atualizar variável de escopo pai em AngularJS

113

Tenho dois controladores, um dentro do outro. Agora eu sei que o escopo filho herda propriedades do escopo pai, mas há uma maneira de atualizar a variável de escopo pai? Até agora não encontrei nenhuma solução óbvia.

Na minha situação, tenho um controlador de calendário em um formulário. Gostaria de atualizar as datas de início e término do escopo pai (que é o formulário) para que o formulário tenha as datas de início e término ao ser enviado.

Malcr001
fonte
parece que seu controlador de calendário deve ser uma diretiva.
Jonah

Respostas:

193

Você precisa usar um objeto (não um primitivo) no escopo pai e então você será capaz de atualizá-lo diretamente do escopo filho

Pai:

app.controller('ctrlParent',function($scope){
    $scope.parentprimitive = "someprimitive";
    $scope.parentobj = {};
    $scope.parentobj.parentproperty = "someproperty";
});

Criança:

app.controller('ctrlChild',function($scope){
    $scope.parentprimitive = "this will NOT modify the parent"; //new child scope variable
    $scope.parentobj.parentproperty = "this WILL modify the parent";
});

Demonstração de trabalho : http://jsfiddle.net/sh0ber/xxNxj/

Consulte Quais são as nuances da herança prototípica / prototípica do escopo no AngularJS?

Dan
fonte
1
Recebo este erro quando tento implementar isso: 'Não é possível definir a propriedade' parentproperty 'of undefined'.
Malcr001
Você pode postar o código? Ele está funcionando na demonstração do violino. Se o seu controle de calendário usa escopo isolado, ele não herdará do escopo pai, então você precisa passar o valor para o escopo da diretiva.
Dan
Desculpe, eu esqueci esta questão. Aceitei porque, finalmente, consegui fazê-lo funcionar com a ajuda desta resposta.
Malcr001
Eu entendo que colocar o {{parentobj.parentproperty}} no elemento div ctrlParent é o que declara o objeto parentobj e define esse objeto como estando no escopo ctrlParent. Será esta uma suposição correta ?
Stephane
1
Obrigado, isso funciona! Definitivamente, eu deveria ler sobre isso (herança prototípica e primitivos). Você pode recomendar uma boa leitura que explique um pouco mais do que seu link do SO?
jvannistelrooy
116

Existe mais uma maneira de fazer esta tarefa e não usar a $scope.$parentvariável.

Basta preparar um método para alterar o valor no escopo pai e usá-lo no filho um. Como isso:

app.controller('ctrlParent',function($scope) {
  $scope.simpleValue = 'x';
  $scope.changeSimpleValue = function(newVal) {
    $scope.simpleValue = newVal;
  };
});

app.controller('ctrlChild',function($scope){
    $scope.changeSimpleValue('y');
});

Também funciona e oferece mais controle sobre as alterações de valor.

Você pode, então, também chamar o método, mesmo em HTML como: <a ng-click="changeSimpleValue('y')" href="#">click me!</a>.

Ravbaker
fonte
1
Boa solução! isso funciona porque quando algo não é encontrado no $ escopo atual, o Angular procura no $ pai. docs.angularjs.org/guide/scope (consulte 'Hierarquias de escopo').
Elo
Eu gosto dessa resposta, não há necessidade de criar um objeto desnecessário.
grimmdude
3
Leitores futuros: todos esses comentários de mais cinco são um pouco mal orientados. A criação de duas funções setter (que são "objetos desnecessários") para cada variável é uma confusão desajeitada e desnecessária de herança e não é a maneira Angular. Misko Hevery, o criador do Angular, dá uma palestra na qual ensina "Sempre que você tem ng-model, deve haver um ponto em algum lugar. Se você não tiver um ponto, está fazendo errado". Vídeo de Misko @ 29:19
Dan
como posso aplicar esta solução usando a sintaxe controllerAS?
niran
6

Isso também funciona (mas não tenho certeza se segue as práticas recomendadas ou não)

app.controller('ctrlParent',function($scope) {
    $scope.simpleValue = 'x';
});

app.controller('ctrlChild',function($scope){
    $scope.$parent.simpleValue = 'y';
});
DynamicNate
fonte
1
Você está correto, usando $ scope. $ Parent.value funcionará na maioria dos casos, no entanto, geralmente não é a melhor ideia para usar extensivamente, pois pode ficar difícil de gerenciar em projetos maiores e mais complicados.
Alex Johnson
4

Quando você atribui um atributo primitivo a um escopo, ele é sempre local para o escopo (possivelmente criado em tempo real), mesmo se um escopo pai tiver um atributo com o mesmo nome. Esta é uma decisão de design, e uma boa IMHO.

Se você precisar alterar alguma primitiva (ints, booleanos, strings) no escopo pai, na visualização, você precisa que seja um atributo de outro objeto nesse escopo, então a atribuição pode ser:

<a ng-click="viewData.myAttr = 4">Click me!</a>

e irá, por sua vez:

  1. obter o viewDataobjeto de qualquer escopo definido em
  2. atribua 4 ao seu myAttratributo.
reescrito
fonte
4

Para acessar variáveis ​​declaradas no pai, devemos usar $ pai no controlador filho ou arquivo de modelo

No controlador

$scope.$parent.varaiable_name

Em modelo html

ng-model="$parent.varaiable_name"
Nibu
fonte