angularJS: Jak wywołać funkcję zakresu potomnego w zakresie nadrzędnym

95

Jak wywołać metodę zdefiniowaną w zakresie podrzędnym z zakresu nadrzędnego?

function ParentCntl() {
    // I want to call the $scope.get here
}

function ChildCntl($scope) {
    $scope.get = function() {
        return "LOL";    
    }
}

http://jsfiddle.net/wUPdW/

9niebieski
źródło
2
Najlepiej, zdefiniuj usługę, wstrzyknij tę usługę do obu kontrolerów. Lub użyj rootscope.
tymeJV

Odpowiedzi:

146

Możesz używać $broadcastod rodzica do dziecka:

function ParentCntl($scope) {

    $scope.msg = "";
    $scope.get = function(){
        $scope.$broadcast ('someEvent');
        return  $scope.msg;        
    }
}

function ChildCntl($scope) {               
    $scope.$on('someEvent', function(e) {  
        $scope.$parent.msg = $scope.get();            
    });

    $scope.get = function(){
        return "LOL";    
    }
}

Skrzypce robocze: http://jsfiddle.net/wUPdW/2/

AKTUALIZACJA : Istnieje inna wersja, mniej sprzężona i bardziej testowalna:

function ParentCntl($scope) {
    $scope.msg = "";
    $scope.get = function(){
        $scope.$broadcast ('someEvent');
        return  $scope.msg;        
    }

    $scope.$on('pingBack', function(e,data) {  
        $scope.msg = data;        
    });
}

function ChildCntl($scope) {               
    $scope.$on('someEvent', function(e) {  
        $scope.$emit("pingBack", $scope.get());        
    });

    $scope.get = function(){
        return "LOL";    
    }
}

Skrzypce: http://jsfiddle.net/uypo360u/

Ivan Chernykh
źródło
To fajnie! Ale co, jeśli nie (chcesz) wiedzieć, gdzie jest zakres wywołującego (mam na myśli in $scope.$parentlub in $scope.$parent.$parentitd.)? Ach, tak: przekaż wywołanie zwrotne w parametrach! :)
user2173353
@ user2173353 masz rację; jest jeszcze jeden sposób: $emitod dziecka do rodzica. Myślę, że nadszedł czas, aby zaktualizować moją odpowiedź ...
Ivan Chernykh
Czy to dobry pomysł, aby wywołać globalny odbiornik, gdzie gdzieś jest, w tym przypadku kontroler podrzędny? Czy to nie jest antywzorowe i trudne do późniejszego przetestowania? Czy nie powinniśmy używać zastrzyków czy czegoś takiego?
calmbird,
@calmbird, z każdej rzeczy trzeba korzystać ostrożnie, to na pewno… Niektórzy wolą korzystać z usług w podobnych przypadkach. W każdym razie dodałem bardziej elegancką wersję (bez denerwowania $parent)
Ivan Chernykh
9
To podejście jest czystsze. Przekaż oddzwonienie pod adresem $broadcasti możesz pingBackcałkowicie wyeliminować .
najpiękniejszy
35

Zasugeruję inne rozwiązanie:

var app = angular.module("myNoteApp", []);


app.controller("ParentCntl", function($scope) {
    $scope.obj = {};
});

app.controller("ChildCntl", function($scope) {
    $scope.obj.get = function() {
            return "LOL";    
    };
});

Mniej kodu i korzystanie z dziedziczenia prototypowego.

Dolar

Canttouchit
źródło
Czy ktoś mógłby wyjaśnić, czy to podejście jest lepsze niż wspomniane powyżej podejście oparte na zdarzeniach, w jakich przypadkach, a jeśli tak, to dlaczego? co jeśli masz hierarchię wielopoziomową z kontrolerami podrzędnymi? czy to zadziałałoby, gdyby obiekt obj.get został zdefiniowany w kontrolerze podrzędnym w kontrolerze podrzędnym, o ile żaden z kontrolerów nie ma zdefiniowanej tej samej nazwy funkcji? Z góry dziękuję.
ZvKa
1
Pozwólcie, że poprawię to, co powiedziałem, co nie jest do końca prawdą. Masz rację w tym, co powiedziałeś: dziedziczenie zakresu jest stosowane tylko w jednym kierunku ... dziecko -> rodzic. W rzeczywistości dzieje się tutaj to, że jeśli zdefiniujesz $ scope.get w zakresie potomnym, 'get' zostanie zdefiniowane tylko w zakresie potomnym (czasami określane jako definicja pierwotna). Ale kiedy zdefiniujesz $ scope.obj.get, wtedy zakres potomny będzie szukał obiektu, który jest zdefiniowany w zakresie nadrzędnym, który znajduje się wyżej w hierarchii.
Canttouchit
3
Jak to zadziała, jeśli dziecko ma swój własny izolowany zakres?
Dinesh
2
Pytanie nie odnosiło się do zakresu izolowanego, jednak jeśli masz zakres izolowany, możesz użyć powiązania zakresu izolowanego. Imo, nadawanie jest trochę bałaganiarskie.
Canttouchit
3
Nie sądzę, że ten przykład jest możliwe, jeśli chcesz mieć dostęp do funkcji regulatora podrzędnego od rodzica kontrolera , a nie szablonu. Ten przykład działa tylko z powodu dwukierunkowego wiązania w szablonie, które, jak zakładam, odpytuje, dopóki nie $scope.obj.get()będzie prawidłową funkcją.
danyim
12

Zarejestruj funkcję dziecka w rodzicu, gdy dziecko jest inicjowane. Użyłem notacji „jako” dla przejrzystości szablonu.

SZABLON

<div ng-controller="ParentCntl as p">
  <div ng-controller="ChildCntl as c" ng-init="p.init(c.get)"></div>
</div>

KONTROLERY

...
function ParentCntl() {
  var p = this;
  p.init = function(fnToRegister) {
    p.childGet = fnToRegister;
  };
 // call p.childGet when you want
}

function ChildCntl() {
  var c = this;
  c.get = function() {
    return "LOL";    
  };
}

„Ale”, mówisz, „ ng-init nie powinno być używane w ten sposób !”. Cóż, tak, ale

  1. ta dokumentacja nie wyjaśnia, dlaczego nie, i
  2. Nie wierzę, że autorzy dokumentacji rozważali WSZYSTKIE możliwe przypadki użycia tego.

Mówię, że to dobry użytek. Jeśli chcesz mnie zlekceważyć, skomentuj z uzasadnieniem! :)

Podoba mi się to podejście, ponieważ sprawia, że ​​komponenty są bardziej modułowe. Jedyne powiązania znajdują się w szablonie i to oznacza

  • kontroler podrzędny nie musi nic wiedzieć o tym, do którego obiektu dodać swoją funkcję (jak w odpowiedzi @ canttouchit)
  • formant nadrzędny może być używany z dowolnym innym formantem podrzędnym, który ma funkcję get
  • nie wymaga nadawania, co w dużej aplikacji będzie bardzo brzydkie, chyba że ściśle kontrolujesz przestrzeń nazw zdarzeń

To podejście jest bliższe idei Tero, polegającej na modularyzacji za pomocą dyrektyw (zauważ, że w jego zmodularyzowanym przykładzie contestantsjest przekazywana z dyrektywy rodzica do dyrektywy „dziecka” W SZABLONIE).

W istocie innym rozwiązaniem mogłoby być rozważenie implementacji ChildCntldyrektywy w formie dyrektywy i wykorzystanie &powiązania do zarejestrowania initmetody.

poshest
źródło
1
Wiem, że to stary post, ale wydaje się to złym pomysłem, ponieważ rodzic może zachować odniesienie do dziecka po zniszczeniu dziecka.
Amy Blankenship,
Jest to znacznie czystsze rozwiązanie niż transmitowanie wydarzeń. Nie idealnie, ale lepiej. Chociaż porządkowanie jest rzeczywiście problemem.
mcv
-1

Możesz zrobić obiekt potomny.

var app = angular.module("myApp", []);


app.controller("ParentCntl", function($scope) {
    $scope.child= {};
    $scope.get = function(){
      return $scope.child.get(); // you can call it. it will return 'LOL'
    }
   // or  you can call it directly like $scope.child.get() once it loaded.
});

app.controller("ChildCntl", function($scope) {
    $scope.obj.get = function() {
            return "LOL";    
    };
});

Tutaj dziecko udowadnia przeznaczenie metody get.

Ramu Agrawal
źródło