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
Найкраще, визначте послугу, введіть цю послугу в обидва контролери. Або скористайтеся коренескопом.
tymeJV

Відповіді:


145

Ви можете використовувати $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";    
    }
}

Fiddle: http://jsfiddle.net/uypo360u/


Це досить круто! Але що робити, якщо ви не хочете (не хочете) знати, де знаходиться область виклику (я маю на увазі $scope.$parentабо в $scope.$parent.$parent, тощо)? А, так: передайте зворотний дзвінок у парамах! :)
user2173353

@ user2173353 ви дуже праві; є ще один спосіб: $emitвід дитини до батька. я думаю, настав час оновити свою відповідь ..
Чернів

Чи є гарною ідеєю зателефонувати глобальному слухачеві, де є десь, у цьому випадку дочірній контролер? Хіба це не антипатерн і важко перевірити пізніше? Чи не повинні ми використовувати ін’єкції чи щось?
calmbird

@calmbird, кожною річчю потрібно користуватися обережно, це точно ... Деякі воліють користуватися послугами в подібних випадках. У будь-якому разі, я додав більш елегантну версію (не дратуючи $parent)
Чернів

9
Такий підхід є більш чистим. Передайте зворотний дзвінок на $broadcastі ви можете повністю усунути його pingBack.
Пост

34

Дозвольте запропонувати інше рішення:

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


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

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

Менше коду та використання прототипічного успадкування.

Планку


Чи може хтось пояснити, чи є такий підхід кращим за підхід, орієнтований на події, згаданий вище, в яких випадках і якщо він є, чому? що якщо у вас є багаторівнева ієрархія з дочірніми контролерами? чи буде це працювати, якщо obj.get визначений у дочірньому контролері в дочірньому контролері до тих пір, поки жоден з контролерів не має однакової назви функції? Спасибі заздалегідь.
ZvKa

1
Дозвольте мені виправити сказане мною, що не є абсолютно правдою. Ви вірно сказали: успадкування сфери застосування застосовується лише в одному напрямку .... дитина -> батько. Насправді тут відбувається те, що якщо ви визначите $ scope.get у дочірній області, 'get' буде визначено лише в дочірній області (Іноді називається примітивним визначенням). Але коли ви визначаєте $ scope.obj.get, тоді дочірня область буде шукати obj, який визначається в батьківській області, яка відповідає ієрархії.
Canttouchit

3
Як це буде працювати, якщо дитина має власну ізоляційну сферу?
Дінеш

2
Питання не стосувалось ізольованої області, однак, якщо у вас є ізольована область, ви можете використовувати прив'язку ізоляції області. Імо, мовлення трохи брудне.
Канттучіт,

2
Я не думаю, що цей приклад можливий, якщо вам потрібно отримати доступ до функції дочірнього контролера від батьківського контролера , а не шаблону. Цей приклад працює лише через двостороннє прив'язку до шаблону, яке, як я вважаю, продовжує опитувати, поки $scope.obj.get()не стане дійсною функцією.
Данім

11

Зареєструйте функцію дитини на батьків, коли дитина ініціалізується. Я використовував позначення "як" для наочності в шаблоні.

ТЕМПЛАТ

<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
  • не вимагає трансляції, що стане дуже потворним у великому додатку, якщо ви не будете жорстко контролювати простір імен подій

Цей підхід більш детально підходить до ідеї Теро про модуляцію з директивами (зауважте, що в його модульованому прикладі contestantsпередається ВІД ТЕМПЛАТИ від батьківської до "дочірньої" директиви).

Дійсно, іншим рішенням може бути розгляд використання ChildCntlдирективи та використання &прив'язки для реєстрації initметоду.


1
Я знаю, що це стара публікація, але це здається поганою ідеєю, оскільки батько може зберігати посилання на дитину після того, як дитина буде знищена.
Емі Бланкенсіп

Це набагато більш чисте рішення, ніж трансляція подій. Не ідеально, але краще. Хоча очищення справді є проблемою.
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";    
    };
});

Тут дитина доводить призначення методу get.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.