AngularJS - เข้าถึงขอบเขตลูก


110

หากฉันมีตัวควบคุมต่อไปนี้:

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

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

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

เป็นวิธีที่เหมาะสมเพื่อให้parentอ่านbออกมาจากchild? หากจำเป็นต้องกำหนดbในสิ่งparentนั้นจะไม่ทำให้ความหมายไม่ถูกต้องโดยสมมติว่าbเป็นคุณสมบัติที่อธิบายสิ่งที่เกี่ยวข้องหรือchildไม่parent?

อัปเดต:การพิจารณาเพิ่มเติมเกี่ยวกับเรื่องนี้หากมีเด็กมากกว่าหนึ่งคนbจะสร้างความขัดแย้งparentในbการดึงข้อมูล ฉันยังคงเป็นคำถามสิ่งที่เป็นวิธีการที่เหมาะสมในการเข้าถึงbจากparent?


1
นอกจากนี้อย่าลืมอ่านสิ่งนี้: stackoverflow.com/questions/14049480/…ภาพรวมขอบเขตและการถ่ายทอดทางพันธุกรรมที่ดีและเชิงลึกใน angularJS
Martijn

คำตอบ:


162

ขอบเขตใน AngularJS ใช้การสืบทอดต้นแบบเมื่อค้นหาคุณสมบัติในขอบเขตลูกล่ามจะค้นหาห่วงโซ่ต้นแบบโดยเริ่มจากเด็กและไปยังผู้ปกครองจนกว่าจะพบคุณสมบัติไม่ใช่ในทางอื่น

ตรวจสอบความคิดเห็นของ Vojta เกี่ยวกับปัญหานี้https://groups.google.com/d/msg/angular/LDNz_TQQiNE/ygYrSvdI0A0J

สรุป: คุณไม่สามารถเข้าถึงขอบเขตลูกจากขอบเขตหลัก

โซลูชันของคุณ:

  1. กำหนดคุณสมบัติในผู้ปกครองและเข้าถึงได้ตั้งแต่เด็ก ๆ (อ่านลิงค์ด้านบน)
  2. ใช้บริการเพื่อแบ่งปันสถานะ
  3. ส่งผ่านข้อมูลผ่านเหตุการณ์ $emitส่งเหตุการณ์ขึ้นไปยังผู้ปกครองจนถึงขอบเขตรูทและ$broadcastยื้อเหตุการณ์ลงด้านล่าง วิธีนี้อาจช่วยให้คุณรักษาความหมายได้ถูกต้อง

8
นอกจากนี้ความแตกต่างระหว่าง $ emit และ $ broadcast คือ $ emit สามารถยกเลิกได้และ $ broadcast dont
Azri Jamil

สถานที่หนึ่งที่คุณอาจต้องการรับขอบเขตย่อยคือเมื่อคำสั่งการทดสอบหน่วย หากคุณมีคำสั่ง transcluded ขอบเขตจะเป็นลูกของขอบเขตที่ใช้ในการคอมไพล์องค์ประกอบ การเข้าถึงขอบเขตของคำสั่งคอมไพล์สำหรับการทดสอบเป็นสิ่งที่ท้าทาย
pmc

ขอบคุณ. อีกทางเลือกหนึ่งอาจlocalStorageมีการพึ่งพาเช่นngStorage.
Akash

81

แม้ว่าคำตอบของ jm-'จะเป็นวิธีที่ดีที่สุดในการจัดการกรณีนี้ แต่สำหรับการอ้างอิงในอนาคตคุณสามารถเข้าถึงขอบเขตย่อยได้โดยใช้ $$ childHead, $$ childTail, $$ nextSibling และ $$ prevSibling สมาชิกของขอบเขต เหล่านี้ไม่ได้รับการบันทึกไว้เพื่อให้พวกเขาอาจมีการเปลี่ยนแปลงโดยไม่ต้องแจ้งให้ทราบล่วงหน้า แต่พวกเขากำลังมีถ้าคุณจริงๆต้องขวางขอบเขต

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

ซอ


49

คุณสามารถลองสิ่งนี้:

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

จากนั้นในตัวควบคุมเด็ก (ขอบเขต) เพิ่ม:

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

ตอนนี้ผู้ปกครองสามารถเข้าถึงขอบเขตของเด็กได้แล้ว


1
สะอาดและตรงไปตรงมามาก หากต้องการเพิ่มสิ่งนี้เพียงแค่ตระหนักว่าไม่มีการผูกมัดดังนั้นเมื่อคุณประกาศว่ามันเหมือนเหนือ parentScope เด็กถือขอบเขตของเด็กในขณะนั้น ในการแก้ปัญหานี้คุณสามารถเพิ่ม $ scope $ watch (function () {parentScope.child = $ scope}); ดังนั้นทุกครั้งที่แยกย่อยมันจะผลักขอบเขตใหม่ไปยังพาเรนต์ ในตอนท้ายของพาเรนต์หากคุณใช้ขอบเขตลูกใด ๆ สำหรับการแสดงภาพใน html คุณจะต้องเพิ่มนาฬิกาในตัวแปรลูกและบอกให้อัปเดตขอบเขตดังนี้: $ scope. $ watch ('child', function ( ) {$ scope. $ evalAsync ();}); . หวังว่านี่จะช่วยใครบางคนได้บ้าง!
IfTrue

2
@IfTrue ฉันเชื่อว่าไม่จำเป็นต้องใช้ $ watch () สิ่งเหล่านี้เป็นวัตถุและผ่านการอ้างอิง
Swanidhi

2
@Swanidhi = ฉันรู้ว่าคุณหมายถึงอะไรและฉันก็คิดเช่นนั้นเช่นกัน แต่มันไม่ได้ผลเมื่อฉันทำการทดลองในขณะที่เขียนความคิดเห็น สำหรับสิ่งที่คุ้มค่าฉันเปลี่ยนจากการทำสิ่งนี้เป็นการแพร่ภาพ / กระจายเสียง
IfTrue

1
จะทำใน Type Script ได้อย่างไร?
ถึง

คำตอบที่ดีที่สุดสำหรับฉัน !! ตัวอย่างที่ดีที่สุดของ Objects ถือว่าเป็นข้อมูลอ้างอิงใน javascript
Vikas Gautam

4

วิธีแก้ปัญหาหนึ่งที่เป็นไปได้คือฉีดตัวควบคุมลูกในตัวควบคุมหลักโดยใช้ฟังก์ชัน init

การใช้งานที่เป็นไปได้:

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

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

ChildControllerคุณมีที่ไหน:

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

}])

ตอนนี้ParentControllerคุณสามารถใช้:

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

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

}])

สำคัญ:
ในการทำงานอย่างถูกต้องคุณต้องใช้คำสั่งng-controllerและเปลี่ยนชื่อคอนโทรลเลอร์แต่ละตัวโดยใช้asเหมือนที่ฉันทำใน html เช่น

เคล็ดลับ:
ใช้ปลั๊กอิน chrome ng-inspectorในระหว่างกระบวนการ จะช่วยให้คุณเข้าใจต้นไม้


3

การใช้$ emitและ$ broadcast (ตามที่ walv กล่าวไว้ในความคิดเห็นด้านบน)

เพื่อเริ่มต้นเหตุการณ์ (จากเด็กไปยังผู้ปกครอง)

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

เพื่อเริ่มต้นเหตุการณ์ลง (จากแม่สู่ลูก)

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

และสุดท้ายที่จะฟัง

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

สำหรับรายละเอียดเพิ่มเติม: - https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

สนุก :)


1

ได้เราสามารถกำหนดตัวแปรจากตัวควบคุมลูกไปยังตัวแปรในตัวควบคุมหลักได้ นี่เป็นวิธีหนึ่งที่เป็นไปได้:

ภาพรวม:จุดมุ่งหมายหลักของโค้ดด้านล่างนี้คือการกำหนด $ scope ของตัวควบคุมเด็กตัวแปรให้กับ $ scope.assign ของตัวควบคุมหลัก

คำอธิบาย:มีตัวควบคุมสองตัว ใน html โปรดสังเกตว่าพาเรนต์คอนโทรลเลอร์อยู่ในตัวควบคุมลูก นั่นหมายความว่าตัวควบคุมหลักจะถูกดำเนินการก่อนตัวควบคุมลูก ดังนั้นขั้นแรก setValue () จะถูกกำหนดจากนั้นตัวควบคุมจะไปที่ตัวควบคุมลูก $ scope.variable จะถูกกำหนดให้เป็น "child" จากนั้นขอบเขตลูกนี้จะถูกส่งเป็นอาร์กิวเมนต์ไปยังฟังก์ชันของตัวควบคุมหลักโดยที่ $ scope.assign จะได้รับค่าเป็น "ลูก"

<!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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.