angularJS: Üst kapsamda çocuk kapsam işlevi nasıl çağırılır


95

Alt kapsamda tanımlanan bir yöntemi üst kapsamından nasıl çağırabilirim?

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

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

http://jsfiddle.net/wUPdW/


2
En iyisi, bir hizmet tanımlayın, bu hizmeti her iki denetleyiciye de enjekte edin. Veya rootcope kullanın.
tymeJV

Yanıtlar:


146

Sen kullanabilirsiniz $broadcastbir ebeveynden çocuğa:

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

Çalışma keman: http://jsfiddle.net/wUPdW/2/

GÜNCELLEME : Daha az bağlı ve daha fazla test edilebilir başka bir sürüm var:

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

Keman: http://jsfiddle.net/uypo360u/


Bu oldukça havalı! Peki $scope.$parentya arayan kapsamının nerede olduğunu bilmiyorsan (istemiyorsan) (yani içinde ya da içinde $scope.$parent.$parentvb.)? Ah, evet: params'da bir geri aramayı iletin! :)
user2173353

@ user2173353 çok haklısın; bir yol daha var: $emitçocuktan ebeveyne. Sanırım cevabımı güncellemenin zamanı geldi ..
Ivan Chernykh

Bir yerlerde nerede küresel dinleyiciyi, bu durumda çocuk denetleyiciyi aramak iyi bir fikir mi? Antipattern ve daha sonra test etmek zor değil mi? Enjeksiyon veya smth kullanmamız gerekmez mi?
Pikachu

@calmbird, her şey dikkatli kullanılmalı, elbette .. Bazıları benzer durumlarda hizmetleri kullanmayı tercih ediyor. Her neyse, daha zarif bir versiyon ekledim (sinir bozucu olmadan $parent)
Ivan Chernykh

9
Bu yaklaşım daha temiz. Adresinde bir geri arama geçirin $broadcastve pingBacktamamen ortadan kaldırabilirsiniz .
Poshest

35

Başka bir çözüm önereyim:

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


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

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

Daha az kod ve prototip kalıtım kullanma.

Düşmek


Birisi, bu yaklaşımın yukarıda bahsedilen olay odaklı yaklaşımdan daha iyi olup olmadığını açıklayabilir mi? Hangi durumlarda ve eğer öyleyse, neden? ya çocuk denetleyicileri olan çok düzeyli hiyerarşiniz varsa? denetleyicilerden hiçbiri aynı işlev adı tanımlı olmadığı sürece obj.get bir çocuk denetleyicide bir çocuk denetleyicide tanımlanmışsa bu işe yarar mı? Şimdiden teşekkür ederim.
ZvKa

1
Tamamen doğru olmayan söylediğimi düzeltmeme izin verin. Söylediğinizde haklısınız: kapsam kalıtımı yalnızca tek bir yöne uygulanır .... çocuk -> üst. Burada gerçekte olan şudur: $ kapsam.get'i alt kapsamda tanımlarsanız, 'get' yalnızca alt kapsamda tanımlanacaktır (Bazen ilkel tanım olarak adlandırılır). Ancak $ kapsam.obj.get'i tanımladığınızda, alt kapsam, hiyerarşinin üstünde olan üst kapsamda tanımlanan obj'i arayacaktır.
Canttouchit

3
Çocuğun kendi izole kapsamı varsa bu nasıl işleyecek?
Dinesh

2
Soru yalıtılmış kapsamı ifade etmiyordu, ancak izole kapsamınız varsa, izole kapsam bağlamayı kullanabilirsiniz. Imo, yayın biraz dağınık.
Canttouchit

3
Sana ebeveynin gelen çocuk kontrolörün işlevine ulaşmak gerekiyorsa bu örnek mümkün olduğunu düşünmüyorum denetleyici değil, şablonu. Bu örnek yalnızca şablondaki iki yönlü bağlama nedeniyle işe yarıyor ve $scope.obj.get()geçerli bir işlev olana kadar yoklamayı sürdürdüğünü varsayıyorum .
danyim

12

Çocuk başlangıç ​​aşamasındayken çocuğun işlevini ebeveyne kaydedin. Şablonda netlik için "as" notasyonu kullandım.

ŞABLON

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

KONTROLÖRLER

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

"Ama" diyorsunuz, " ng-init bu şekilde kullanılmamalıdır !". Evet ama

  1. bu dokümantasyon neden olmadığını açıklamıyor ve
  2. Dokümantasyon yazarlarının bunun için TÜM olası kullanım durumlarını değerlendirdiğine inanmıyorum.

Bunun onun için iyi bir kullanım olduğunu söylüyorum. Bana olumsuz oy vermek istiyorsanız, lütfen nedenlerle yorum yapın! :)

Bu yaklaşımı seviyorum çünkü bileşenleri daha modüler tutuyor. Tek bağlamalar şablondadır ve şu anlama gelir:

  • Çocuk Denetleyicinin hangi nesneye işlevini ekleyeceği hakkında hiçbir şey bilmesine gerek yoktur (@ canttouchit'in cevabında olduğu gibi)
  • ebeveyn kontrolü, alma işlevine sahip başka herhangi bir çocuk kontrolü ile kullanılabilir
  • yayın gerektirmez; bu, etkinlik ad alanını sıkı bir şekilde kontrol etmezseniz büyük bir uygulamada çok çirkinleşir

Bu yaklaşım , Tero'nun yönergelerle modülerleştirme fikrine daha yakından yaklaşır (modülerleştirilmiş örneğinde, contestantsŞABLON İÇİNDE ebeveynden "çocuk" yönergesine geçirildiğine dikkat edin ).

Aslında başka bir çözüm ChildCntl, bir yönerge olarak uygulamayı düşünmek &ve inityöntemi kaydetmek için bağlamayı kullanmak olabilir .


1
Bunun eski bir gönderi olduğunu biliyorum, ancak bu kötü bir fikir gibi görünüyor çünkü ebeveyn çocuk yok edildikten sonra çocuğa bir referans tutabilir.
Amy Blankenship

Bu, olayları yayınlamaktan çok daha temiz bir çözümdür. Mükemmel değil ama daha iyi. Temizleme gerçekten bir sorun olsa da.
mcv

-1

Alt nesne yapabilirsiniz.

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

Burada çocuk alma yönteminin hedefini kanıtlıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.