AngularJS - Akses ke lingkup anak

110

Jika saya memiliki pengontrol berikut:

function parent($scope, service) {
    $scope.a = 'foo';

    $scope.save = function() {
        service.save({
            a:  $scope.a,
            b:  $scope.b
        });
    }
}

function child($scope) {
    $scope.b = 'bar';
}

Apa cara yang tepat untuk membiarkan parentmembaca bdari child? Jika itu perlu untuk mendefinisikan bdi parent, tidak akan yang membuatnya semantik tidak benar dengan asumsi bahwa badalah properti yang menggambarkan sesuatu yang berhubungan denganchild dan tidak parent?

Update: Berpikir lebih lanjut tentang hal itu, jika lebih dari satu anak memiliki bitu akan menciptakan konflik untuk parentyang buntuk mengambil. Pertanyaan saya tetap, apa cara yang tepat untuk akses bdari parent?

Aziz Alfoudari
sumber
1
Juga, pastikan Anda membaca ini: stackoverflow.com/questions/14049480/… Tinjauan yang sangat baik dan mendalam tentang cakupan dan pewarisan di angularJS.
Martijn

Jawaban:

162

Cakupan di AngularJS menggunakan pewarisan prototipe, ketika mencari properti di lingkup anak, penerjemah akan mencari rantai prototipe mulai dari anak dan berlanjut ke orang tua hingga menemukan properti, bukan sebaliknya.

Periksa komentar Vojta tentang masalah tersebut https://groups.google.com/d/msg/angular/LDNz_TQQiNE/ygYrSvdI0A0J

Singkatnya: Anda tidak dapat mengakses cakupan anak dari lingkup induk.

Solusi Anda:

  1. Tentukan properti pada orang tua dan akses dari anak-anak (baca tautan di atas)
  2. Gunakan layanan untuk berbagi status
  3. Meneruskan data melalui peristiwa. $emitmengirim peristiwa ke atas ke orang tua sampai cakupan root dan $broadcastmengirim peristiwa ke bawah. Ini dapat membantu Anda untuk menjaga segala sesuatunya benar secara semantik.
jaime
sumber
8
Ditambah perbedaan antara $ emit dan $ broadcast adalah $ emit dapat dibatalkan dan $ siaran tidak.
Azri Jamil
Satu tempat Anda mungkin ingin mendapatkan cakupan anak adalah ketika arahan pengujian unit. Jika Anda memiliki direktif yang ditransklusikan, cakupannya adalah turunan dari cakupan yang digunakan untuk mengompilasi elemen. Mendapatkan akses ke cakupan arahan yang dikompilasi untuk pengujian itu menantang.
pmc
Terima kasih. Pilihan lain bisa localStoragedengan ketergantungan seperti ngStorage.
Akash
81

Meskipun jawaban jm-adalah cara terbaik untuk menangani kasus ini, untuk referensi di masa mendatang dimungkinkan untuk mengakses cakupan anak menggunakan anggota $$ childHead, $$ childTail, $$ nextSibling dan $$ prevSibling dari suatu cakupan. Ini tidak didokumentasikan sehingga mungkin berubah tanpa pemberitahuan, tetapi mereka ada di sana jika Anda benar - benar perlu melintasi cakupan.

// get $$childHead first and then iterate that scope's $$nextSiblings
for(var cs = scope.$$childHead; cs; cs = cs.$$nextSibling) {
    // cs is child scope
}

Biola

Jussi Kosunen
sumber
49

Anda bisa mencoba ini:

$scope.child = {} //declare it in parent controller (scope)

lalu di pengontrol anak (cakupan) tambahkan:

var parentScope = $scope.$parent;
parentScope.child = $scope;

Sekarang orang tua memiliki akses ke ruang lingkup anak.

Farzin Mo
sumber
1
Sangat bersih dan lugas. Untuk menambahkan ini, cukup sadari bahwa tidak ada pengikatan sehingga ketika Anda mendeklarasikannya seperti di atas, parentScope.child sedang memegang lingkup anak pada saat itu. Untuk mengatasi ini, Anda dapat menambahkan $ scope. $ Watch (function () {parentScope.child = $ scope}); sehingga setelah setiap intisari, cakupan baru itu mendorong ke induknya. Di sisi induk jika Anda menggunakan salah satu cakupan anak untuk visual di html, Anda akan perlu menambahkan jam tangan pada variabel anak dan menyuruhnya memperbarui cakupan seperti: $ scope. $ Watch ('child', function ( ) {$ scope. $ evalAsync ();}); . Semoga ini menghemat waktu seseorang!
IfTrue
2
@IfTrue Saya yakin $ watch () tidak diperlukan. Ini adalah objek dan mereka melewati referensi.
Swanidhi
2
@Swanidhi = Saya tahu apa yang Anda maksud dan saya juga berpikir begitu, tetapi tidak berhasil ketika saya bereksperimen pada saat menulis komentar. Untuk apa itu layak saya beralih dari melakukan ini ke memancarkan / menyiarkan.
IfTrue
1
Bagaimana melakukan ini di Type Script?
ATHER
Jawaban Terbaik untuk saya !! Contoh terbaik dari Objek yang diperlakukan sebagai referensi dalam javascript
Vikas Gautam
4

Salah satu solusi yang mungkin adalah menyuntikkan pengontrol anak di pengontrol induk menggunakan fungsi init.

Penerapan yang mungkin:

<div ng-controller="ParentController as parentCtrl">
   ...

    <div ng-controller="ChildController as childCtrl" 
         ng-init="ChildCtrl.init()">
       ...
    </div>
</div>

Di mana ChildControllerAnda memiliki:

app.controller('ChildController',
    ['$scope', '$rootScope', function ($scope, $rootScope) {
    this.init = function() {
         $scope.parentCtrl.childCtrl = $scope.childCtrl;
         $scope.childCtrl.test = 'aaaa';
    };

}])

Jadi sekarang ParentControllerAnda dapat menggunakan:

app.controller('ParentController',
    ['$scope', '$rootScope', 'service', function ($scope, $rootScope, service) {

    this.save = function() {
        service.save({
            a:  $scope.parentCtrl.ChildCtrl.test
        });
     };

}])

Penting:
Untuk bekerja dengan baik Anda harus menggunakan direktif ng-controllerdan mengganti nama setiap pengontrol menggunakan asseperti yang saya lakukan di html misalnya.

Tips:
Gunakan plugin chrome ng-inspector selama proses. Ini akan membantu Anda memahami pohon itu.

borracciaBlu
sumber
3

Menggunakan $ emit dan $ broadcast , (seperti yang disebutkan oleh walv di komentar di atas)

Untuk mengaktifkan acara ke atas (dari anak ke orang tua)

$scope.$emit('myTestEvent', 'Data to send');

Untuk mengaktifkan peristiwa ke bawah (dari orang tua ke anak)

$scope.$broadcast('myTestEvent', {
  someProp: 'Sending you some data'
});

dan akhirnya mendengarkan

$scope.$on('myTestEvent', function (event, data) {
  console.log(data);
});

Untuk detail lebih lanjut: - https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

Nikmati :)

Anjana Silva
sumber
1

Ya, kita dapat menetapkan variabel dari pengontrol anak ke variabel di pengontrol induk. Ini adalah salah satu cara yang mungkin:

Gambaran: Tujuan utama kode, di bawah ini, adalah untuk menetapkan $ scope.variable pengontrol anak ke $ scope.assign pengontrol induk

Penjelasan: Ada dua pengontrol. Di html, perhatikan bahwa pengontrol induk menyertakan pengontrol turunan. Itu berarti pengontrol induk akan dieksekusi sebelum pengontrol anak. Jadi, setValue () pertama akan ditentukan dan kemudian kontrol akan menuju ke kontroler anak. $ scope.variable akan ditetapkan sebagai "anak". Kemudian lingkup anak ini akan diteruskan sebagai argumen ke fungsi pengontrol induk, di mana $ scope.assign akan mendapatkan nilai sebagai "anak"

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script type="text/javascript">
    var app = angular.module('myApp',[]);

    app.controller('child',function($scope){
        $scope.variable = "child";
        $scope.$parent.setValue($scope);
    });

    app.controller('parent',function($scope){
        $scope.setValue = function(childscope) {
            $scope.assign = childscope.variable;
        }
    });

</script>
<body ng-app="myApp">
 <div ng-controller="parent">
    <p>this is parent: {{assign}}</p>
    <div ng-controller="child">
        <p>this is {{variable}}</p>
    </div>
 </div>
</body>
</html>
rupali317
sumber