angularJS: Bagaimana memanggil fungsi lingkup anak dalam lingkup induk

95

Bagaimana memanggil metode yang didefinisikan dalam lingkup anak dari lingkup induknya?

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

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

http://jsfiddle.net/wUPdW/

9biru
sumber
2
Taruhan terbaik, tentukan layanan, masukkan layanan itu ke kedua pengontrol. Atau gunakan rootscope.
tymeJV

Jawaban:

145

Anda dapat menggunakan $broadcastdari orang tua ke anak:

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

Biola kerja: http://jsfiddle.net/wUPdW/2/

UPDATE : Ada versi lain, kurang digabungkan dan lebih dapat diuji:

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

Biola: http://jsfiddle.net/uypo360u/

Cherniv
sumber
Itu sangat keren! Tapi, bagaimana jika Anda tidak (ingin) tahu di mana cakupan pemanggil (maksud saya di dalam $scope.$parentatau di dalam $scope.$parent.$parent, dll)? Ah, ya: berikan panggilan balik di params! :)
user2173353
@ user2173353 Anda benar; ada satu cara lagi: $emitdari seorang anak menjadi orang tua. saya pikir ini adalah waktu untuk memperbarui jawaban saya ..
Cherniv
Apakah ide yang baik untuk menelepon ke pendengar global di mana saja, pengontrol anak dalam kasus ini? Bukankah itu antipattern dan sulit untuk diuji nanti? Bukankah kita harus menggunakan suntikan atau sesuatu?
calmbird
@ calmbird, setiap hal harus digunakan dengan hati-hati, yang pasti .. Beberapa lebih suka menggunakan layanan dalam kasus serupa. Bagaimanapun, saya menambahkan versi yang lebih elegan (tanpa mengganggu $parent)
Cherniv
9
Pendekatan ini lebih bersih. Meneruskan panggilan balik di $broadcastdan Anda dapat menghilangkan pingBacksemuanya.
poshest
34

Izinkan saya menyarankan solusi lain:

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


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

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

Lebih sedikit kode dan menggunakan pewarisan prototipe.

Memetik

Canttouchit
sumber
Dapatkah seseorang menjelaskan jika pendekatan ini lebih baik daripada pendekatan berdasarkan peristiwa yang disebutkan di atas dalam kasus apa dan jika ya, mengapa? bagaimana jika Anda memiliki multi lvl hierarki w pengontrol anak? akankah ini bekerja jika obj.get didefinisikan di dalam pengontrol anak dalam pengontrol anak selama tidak ada pengontrol yang memiliki nama fungsi yang sama? Terima kasih sebelumnya.
ZvKa
1
Izinkan saya mengoreksi apa yang saya katakan yang tidak sepenuhnya benar. Anda benar dengan apa yang Anda katakan: pewarisan lingkup hanya diterapkan ke satu arah saja .... anak -> orang tua. Apa yang sebenarnya terjadi di sini adalah jika Anda mendefinisikan $ scope.get dalam lingkup anak, 'get' hanya akan didefinisikan pada lingkup anak (Kadang-kadang disebut sebagai definisi primitif). Tetapi ketika Anda mendefinisikan $ scope.obj.get, maka lingkup anak akan mencari obj yang didefinisikan pada lingkup induk, yang merupakan hierarki atas.
Canttouchit
3
Bagaimana ini akan bekerja jika anak memiliki ruang lingkup isolasinya sendiri?
Dinesh
2
Pertanyaannya tidak mengacu pada lingkup terisolasi, Namun jika Anda memiliki lingkup terisolasi Anda dapat menggunakan pengikatan lingkup isolate. Imo, penyiarannya agak berantakan.
Canttouchit
2
Saya tidak berpikir contoh ini adalah mungkin jika Anda perlu untuk mengakses fungsi controller anak dari orang tua pengontrol , tidak Template. Contoh ini hanya berfungsi karena pengikatan dua arah pada template, yang saya asumsikan terus melakukan polling hingga $scope.obj.get()fungsi valid.
danyim
11

Daftarkan fungsi anak pada orang tua ketika anak tersebut melakukan inisialisasi. Saya menggunakan "sebagai" notasi untuk kejelasan dalam template.

TEMPLATE

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

PENGONTROL

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

"Tapi", Anda berkata, " ng-init tidak seharusnya digunakan dengan cara ini !". Ya, tapi

  1. dokumentasi itu tidak menjelaskan mengapa tidak, dan
  2. Saya tidak percaya penulis dokumentasi mempertimbangkan SEMUA kemungkinan kasus penggunaan untuk itu.

Saya mengatakan ini adalah penggunaan yang baik untuk itu. Jika Anda ingin downvote saya, silahkan berkomentar dengan alasan! :)

Saya suka pendekatan ini karena ini membuat komponen lebih modular. Binding hanya ada di template, dan artinya

  • Pengontrol anak tidak harus tahu apa-apa tentang objek mana yang akan ditambahkan fungsinya (seperti dalam jawaban @ canttouchit)
  • kontrol orang tua dapat digunakan dengan kontrol anak lain yang memiliki fungsi get
  • tidak memerlukan penyiaran, yang akan menjadi sangat buruk di aplikasi besar kecuali Anda mengontrol ruang nama acara dengan ketat

Pendekatan ini lebih mendekati gagasan Tero tentang modularising dengan arahan (perhatikan bahwa dalam contoh modularised, contestantsditeruskan dari induk ke arahan "anak" DI TEMPLATE).

Memang solusi lain mungkin mempertimbangkan penerapan ChildCntlsebagai arahan dan menggunakan &pengikatan untuk mendaftarkan initmetode.

poshest
sumber
1
Saya tahu ini adalah postingan lama, tetapi ini sepertinya ide yang buruk karena orang tua dapat menyimpan referensi ke anaknya setelah anaknya dimusnahkan.
Amy Blankenship
Ini adalah solusi yang jauh lebih bersih daripada acara penyiaran. Tidak sempurna, tapi lebih baik. Padahal pembersihan memang menjadi masalah.
mcv
-1

Anda bisa membuat objek anak.

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

Di sini anak membuktikan tujuan metode get.

Ramu Agrawal
sumber