Zaktualizuj zmienną zakresu rodzica w AngularJS

113

Mam dwa kontrolery, jeden w drugim. Teraz wiem, że zakres podrzędny dziedziczy właściwości z zakresu nadrzędnego, ale czy istnieje sposób na zaktualizowanie zmiennej zakresu nadrzędnego? Jak dotąd nie znalazłem żadnych oczywistych rozwiązań.

W mojej sytuacji mam kontrolera kalendarza w formularzu. Chciałbym zaktualizować daty rozpoczęcia i zakończenia z zakresu nadrzędnego (którym jest formularz), aby formularz miał daty rozpoczęcia i zakończenia w momencie przesłania.

Malcr001
źródło
wygląda na to, że kontroler kalendarza powinien być dyrektywą.
Jonah

Odpowiedzi:

193

Musisz użyć obiektu (nie prymitywu) w zakresie nadrzędnym, a wtedy będziesz mógł go zaktualizować bezpośrednio z zakresu podrzędnego

Rodzic:

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

Dziecko:

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

Działające demo : http://jsfiddle.net/sh0ber/xxNxj/

Zobacz Jakie są niuanse dziedziczenia prototypowego / prototypowego zakresu w AngularJS?

Dan
źródło
1
Otrzymuję ten błąd, kiedy próbuję to zaimplementować: „Nie można ustawić właściwości„ właściwość nadrzędna ”na wartość undefined”.
Malcr001
Czy możesz wysłać swój kod? Działa w wersji demo skrzypiec. Jeśli formant kalendarza używa zakresu izolowanego, nie będzie dziedziczyć z zakresu nadrzędnego, więc trzeba będzie przekazać wartość do zakresu dyrektywy.
Dan
Przepraszam, że zapomniałem o tym pytaniu. Zaakceptowałem to, ponieważ w końcu udało mi się to uruchomić z pomocą tej odpowiedzi.
Malcr001
Rozumiem, że umieszczenie {{parentobj.parentproperty}} w elemencie div ctrlParent jest tym, co deklaruje obiekt parentobj i ustawia ten obiekt jako będący w zakresie ctrlParent. Czy to prawidłowe założenie?
Stephane
1
Dzięki, to działa! Zdecydowanie powinienem poczytać o tym (dziedziczenie prototypowe i prymitywy). Czy możesz polecić dobrą lekturę, która wyjaśnia nieco więcej niż twój link do SO?
jvannistelrooy
116

Jest jeszcze jeden sposób, aby wykonać to zadanie i nie używać $scope.$parent zmiennej.

Po prostu przygotuj metodę zmiany wartości w zakresie nadrzędnym i użyj jej w zakresie podrzędnym. Lubię to:

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

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

Działa również i zapewnia większą kontrolę nad zmianami wartości.

Następnie można również wywołać metodę nawet w HTML, takich jak: <a ng-click="changeSimpleValue('y')" href="#">click me!</a>.

Ravbaker
źródło
1
Dobre rozwiązanie! to działa, ponieważ gdy coś nie zostanie znalezione w bieżącym $ zasięgu, Angular wyszukuje w $ parent. docs.angularjs.org/guide/scope (patrz „Hierarchie zakresu”).
Elo
Podoba mi się ta odpowiedź, nie ma potrzeby tworzenia niepotrzebnego obiektu.
grimmdude
3
Przyszli czytelnicy: Wszystkie te piątkowe komentarze są nieco błędne. Tworzenie dwóch funkcji ustawiających (które są „niepotrzebnymi obiektami”) dla każdej zmiennej jest niezgrabnym i niepotrzebnym zachwianiem dziedziczenia i nie jest sposobem Angular. Misko Hevery, twórca Angulara, wygłasza wykład, w którym uczy: „Kiedy masz model ng, gdzieś musi być kropka. Jeśli nie masz kropki, robisz to źle”. Film Misko @ 29:19
Dan,
jak mogę zastosować to rozwiązanie przy użyciu składni controllerAS?
niran
6

To również działa (ale nie jestem pewien, czy jest to zgodne z najlepszą praktyką, czy nie)

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

app.controller('ctrlChild',function($scope){
    $scope.$parent.simpleValue = 'y';
});
DynamicNate
źródło
1
Masz rację, użycie $ scope. $ Parent.value zadziała w większości przypadków, jednak zwykle nie jest to najlepszy pomysł, aby używać go na szeroką skalę, ponieważ może być trudny do zarządzania w większych, bardziej skomplikowanych projektach.
Alex Johnson,
4

Kiedy przypisujesz prymitywny atrybut do zakresu, zawsze tak jest lokalny dla zakresu (prawdopodobnie tworzony w locie), nawet jeśli zasięg nadrzędny ma atrybut o tej samej nazwie. To jest decyzja projektowa i dobra decyzja IMHO.

Jeśli chcesz zmienić jakieś prymitywy (ints, booleans, strings) w zakresie nadrzędnym, z widoku potrzebujesz, aby był to atrybut innego obiektu w tym zakresie, więc przypisanie może brzmieć:

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

i to z kolei:

  1. uzyskać viewData obiekt z dowolnego zakresu, w którym jest zdefiniowany
  2. przypisz 4 do jego myAttratrybutu.
przepisany
źródło
4

Aby uzyskać dostęp do zmiennych zadeklarowanych w rodzicu, powinniśmy użyć $ parent w kontrolerze podrzędnym lub pliku szablonu

W kontrolerze

$scope.$parent.varaiable_name

W szablonie html

ng-model="$parent.varaiable_name"
Nibu
źródło