angularJS: วิธีการเรียกฟังก์ชันขอบเขตลูกในขอบเขตหลัก


95

จะเรียกเมธอดที่กำหนดในขอบเขตลูกจากขอบเขตหลักได้อย่างไร

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

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

http://jsfiddle.net/wUPdW/


2
เดิมพันที่ดีที่สุดกำหนดบริการฉีดบริการนั้นลงในตัวควบคุมทั้งสอง หรือใช้ rootscope.
tymeJV

คำตอบ:


146

คุณสามารถใช้ได้$broadcastตั้งแต่ผู้ปกครองจนถึงเด็ก:

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

เล่นซอ: http://jsfiddle.net/wUPdW/2/

อัปเดต : มีอีกเวอร์ชันหนึ่งซึ่งมีคู่น้อยกว่าและสามารถทดสอบได้มากกว่า:

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

ซอ: http://jsfiddle.net/uypo360u/


เจ๋งมาก! แต่ถ้าคุณไม่ (ต้องการ) รู้ว่าขอบเขตผู้โทรอยู่ที่ไหน (ฉันหมายถึงใน$scope.$parentหรือใน$scope.$parent.$parentฯลฯ )? อ่าใช่: ส่งการโทรกลับใน params! :)
user2173353

@ user2173353 คุณพูดถูกมาก มีอีกวิธีหนึ่ง: $emitจากเด็กไปสู่ผู้ปกครอง ฉันคิดว่าถึงเวลาอัปเดตคำตอบของฉัน ..
Ivan Chernykh

เป็นความคิดที่ดีหรือไม่ที่จะโทรไปหาผู้ฟังทั่วโลกในกรณีนี้ตัวควบคุมเด็กอยู่ที่ไหน มันไม่ต่อต้านและยากที่จะทดสอบในภายหลัง? เราไม่ควรใช้ยาฉีดหรือ smth?
Pikachu

@calmbird แต่ละอย่างต้องใช้อย่างระมัดระวังแน่นอน .. บางคนชอบใช้บริการในกรณีที่คล้ายกัน อย่างไรก็ตามฉันได้เพิ่มเวอร์ชันที่หรูหรามากขึ้น (โดยไม่น่ารำคาญ$parent)
Ivan Chernykh

9
แนวทางนี้สะอาดกว่า ส่งการติดต่อกลับที่$broadcastและคุณสามารถกำจัดpingBackทั้งหมดได้
poshest

35

ให้ฉันแนะนำวิธีแก้ปัญหาอื่น:

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


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

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

รหัสน้อยลงและใช้การสืบทอดต้นแบบ

Plunk


มีใครช่วยอธิบายได้ไหมว่าแนวทางนี้ดีกว่าแนวทางขับเคลื่อนเหตุการณ์ที่กล่าวข้างต้นในกรณีใดและเป็นเพราะเหตุใด จะเกิดอะไรขึ้นถ้าคุณมีลำดับชั้นหลายระดับพร้อมตัวควบคุมเด็ก? สิ่งนี้จะใช้งานได้หรือไม่ถ้า obj.get ถูกกำหนดไว้ในตัวควบคุมลูกภายในตัวควบคุมเด็กตราบใดที่ไม่มีตัวควบคุมใดที่มีการกำหนดชื่อฟังก์ชันเหมือนกัน ขอบคุณล่วงหน้า.
ZvKa

1
ให้ฉันแก้ไขสิ่งที่ฉันพูดซึ่งไม่เป็นความจริงทั้งหมด คุณถูกต้องในสิ่งที่คุณพูด: การสืบทอดขอบเขตใช้กับทิศทางเดียวเท่านั้น .... child -> parent สิ่งที่เกิดขึ้นที่นี่คือถ้าคุณกำหนด $ scope.get ในขอบเขตลูก 'get' จะถูกกำหนดเฉพาะในขอบเขตลูกเท่านั้น (บางครั้งเรียกว่านิยามดั้งเดิม) แต่เมื่อคุณกำหนด $ scope.obj.get ขอบเขตลูกจะมองหา obj ซึ่งกำหนดไว้ในขอบเขตหลักซึ่งขึ้นอยู่กับลำดับชั้น
Canttouchit

3
สิ่งนี้จะทำงานอย่างไรหากเด็กมีขอบเขตการแยกของตัวเอง
Dinesh

2
คำถามไม่ได้อ้างถึงขอบเขตที่แยกต่างหากอย่างไรก็ตามหากคุณมีขอบเขตแยกคุณสามารถใช้การผูกขอบเขตแยกได้ Imo การแพร่ภาพค่อนข้างยุ่ง
Canttouchit

3
ฉันไม่คิดว่าตัวอย่างนี้เป็นไปได้ถ้าคุณต้องการเข้าถึงฟังก์ชั่นการควบคุมของเด็กจากผู้ปกครองควบคุมไม่ได้แม่แบบ ตัวอย่างนี้ใช้งานได้เฉพาะเนื่องจากการเชื่อมโยงสองทางกับเทมเพลตซึ่งฉันคิดว่าจะทำการสำรวจต่อไปจนกว่า$scope.obj.get()จะเป็นฟังก์ชันที่ถูกต้อง
danyim

12

ลงทะเบียนฟังก์ชันของเด็กกับผู้ปกครองเมื่อเด็กเริ่มต้น ฉันใช้สัญลักษณ์ "เป็น" เพื่อความชัดเจนในเทมเพลต

เทมเพลต

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

ตัวควบคุม

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

"แต่" คุณพูดว่า " ng-init ไม่ควรใช้แบบนี้ !". ใช่ แต่

  1. เอกสารนั้นไม่ได้อธิบายว่าทำไมไม่และ
  2. ฉันไม่เชื่อว่าผู้เขียนเอกสารจะพิจารณากรณีการใช้งานที่เป็นไปได้ทั้งหมด

ฉันบอกว่านี่คือการใช้งานที่ดีสำหรับมัน หากคุณต้องการลดคะแนนโปรดแสดงความคิดเห็นพร้อมเหตุผล! :)

ฉันชอบแนวทางนี้เพราะทำให้ส่วนประกอบเป็นโมดูลาร์มากขึ้น การเชื่อมโยงเท่านั้นที่อยู่ในเทมเพลตและหมายความว่า

  • ตัวควบคุมเด็กไม่จำเป็นต้องรู้อะไรเกี่ยวกับวัตถุที่จะเพิ่มฟังก์ชั่นของมัน (ดังในคำตอบของ @ canttouchit)
  • การควบคุมหลักสามารถใช้กับการควบคุมลูกอื่น ๆ ที่มีฟังก์ชัน get
  • ไม่จำเป็นต้องออกอากาศซึ่งจะดูน่าเกลียดมากในแอปขนาดใหญ่เว้นแต่คุณจะควบคุมเนมสเปซของเหตุการณ์

แนวทางนี้เข้าใกล้แนวคิดของ Tero ในเรื่องการสร้างโมดูลด้วยคำสั่งมากขึ้น (โปรดทราบว่าในตัวอย่างแบบแยกส่วนของเขาcontestantsจะถูกส่งต่อจากผู้ปกครองไปยังคำสั่ง "เด็ก" ในเทมเพลต)

วิธีแก้ปัญหาอื่นอาจต้องพิจารณาใช้ChildCntlเป็นคำสั่งและใช้การ&ผูกเพื่อลงทะเบียนinitวิธีการ


1
ฉันรู้ว่านี่เป็นโพสต์เก่า แต่ดูเหมือนจะเป็นความคิดที่ไม่ดีเพราะผู้ปกครองสามารถอ้างอิงถึงเด็กหลังจากที่เด็กถูกทำลาย
Amy Blankenship

นี่เป็นวิธีแก้ปัญหาที่สะอาดกว่าการแพร่ภาพกิจกรรม ไม่สมบูรณ์แบบ แต่ดีกว่า แม้ว่าการล้างข้อมูลจะเป็นปัญหาอย่างแท้จริง
mcv

-1

คุณสามารถสร้างวัตถุลูกได้

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

เด็กที่นี่กำลังพิสูจน์ปลายทางของวิธีการรับ

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