Может ли один контроллер AngularJS вызвать другой? - PullRequest
572 голосов
/ 15 февраля 2012

Возможно ли, чтобы один контроллер использовал другой?

Например:

Этот документ HTML просто печатает сообщение, доставленное контроллером MessageCtrl, в файле messageCtrl.js.

<html xmlns:ng="http://angularjs.org/">
<head>
    <meta charset="utf-8" />
    <title>Inter Controller Communication</title>
</head>
<body>
    <div ng:controller="MessageCtrl">
        <p>{{message}}</p>
    </div>

    <!-- Angular Scripts -->
    <script src="http://code.angularjs.org/angular-0.9.19.js" ng:autobind></script>
    <script src="js/messageCtrl.js" type="text/javascript"></script>
</body>
</html>

Файл контроллера содержит следующий код:

function MessageCtrl()
{
    this.message = function() { 
        return "The current date is: " + new Date().toString(); 
    };
}

, который просто печатает текущую дату;

Если бы я добавил еще один контроллер, DateCtrl, которыйвернул дату в определенном формате обратно к MessageCtrl, как можно это сделать?Структура DI, кажется, касается XmlHttpRequests и доступа к услугам.

Ответы [ 13 ]

2 голосов
/ 27 декабря 2013

Существует метод, не зависящий от услуг, $broadcast или $emit.Это подходит не во всех случаях, но если у вас есть 2 связанных контроллера, которые можно абстрагировать в директивы, то вы можете использовать опцию require в определении директивы.Это наиболее вероятно, как ngModel и ngForm общаются.Вы можете использовать это для связи между контроллерами директив, которые либо вложены, либо находятся в одном и том же элементе.

Для ситуации родитель / потомок использование будет следующим:

<div parent-directive>
  <div inner-directive></div>
</div>

Иосновные моменты, чтобы заставить это работать: в родительской директиве, с методами, которые будут вызваны, вы должны определить их на this (не на $scope):

controller: function($scope) {
  this.publicMethodOnParentDirective = function() {
    // Do something
  }
}

В определении дочерней директивы, вы можете использовать опцию require, чтобы родительский контроллер был передан функции связывания (чтобы вы могли затем вызывать функции из него из scope дочерней директивы.

require: '^parentDirective',
template: '<span ng-click="onClick()">Click on this to call parent directive</span>',
link: function link(scope, iElement, iAttrs, parentController) {
  scope.onClick = function() {
    parentController.publicMethodOnParentDirective();
  }
}

быть замеченным в http://plnkr.co/edit/poeq460VmQER8Gl9w8Oz?p=preview

Аналогичная директива используется, но обе директивы для одного и того же элемента:

<div directive1 directive2>
</div>

Используется при создании метода в directive1:

controller: function($scope) {
  this.publicMethod = function() {
    // Do something
  }
}

И в директиве 2 это можно вызвать с помощью опции require, которая приводит к передаче siblingController в функцию ссылки:

require: 'directive1',
template: '<span ng-click="onClick()">Click on this to call sibling directive1</span>',
link: function link(scope, iElement, iAttrs, siblingController) {
  scope.onClick = function() {
    siblingController.publicMethod();
  }
}

Это можно увидеть в http://plnkr.co/edit/MUD2snf9zvadfnDXq85w?p=preview.

Использование этогоs?

  • Родитель: Любой случай, когда дочерние элементы должны «зарегистрироваться» у родителя.Очень похоже на отношения между ngModel и ngForm.Это может добавить определенное поведение, которое может повлиять на модели.У вас также может быть что-то чисто на основе DOM, где родительский элемент должен управлять позициями определенных потомков, скажем, управлять прокруткой или реагировать на нее.

  • Брат: разрешение директиве иметьего поведение изменено.ngModel - классический случай добавления парсеров / проверки к использованию ngModel на входах.

1 голос
/ 23 марта 2016

В угловой версии 1.5 это можно сделать, выполнив следующие действия:

(function() {
  'use strict';

  angular
    .module('app')
    .component('parentComponent',{
      bindings: {},
      templateUrl: '/templates/products/product.html',
      controller: 'ProductCtrl as vm'
    });

  angular
    .module('app')
    .controller('ProductCtrl', ProductCtrl);

  function ProductCtrl() {
    var vm = this;
    vm.openAccordion = false;

    // Capture stuff from each of the product forms
    vm.productForms = [{}];

    vm.addNewForm = function() {
      vm.productForms.push({});
    }
  }

}());

Это родительский компонент. В этом я создал функцию, которая помещает другой объект в мой массив productForms - заметка - это всего лишь мой пример, эта функция может быть чем угодно.

Теперь мы можем создать еще один компонент, который будет использовать require:

(function() {
  'use strict';

  angular
    .module('app')
    .component('childComponent', {
      bindings: {},
      require: {
        parent: '^parentComponent'
      },
      templateUrl: '/templates/products/product-form.html',
      controller: 'ProductFormCtrl as vm'
    });

  angular
    .module('app')
    .controller('ProductFormCtrl', ProductFormCtrl);

  function ProductFormCtrl() {
    var vm = this;

    // Initialization - make use of the parent controllers function
    vm.$onInit = function() {
      vm.addNewForm = vm.parent.addNewForm;
    };  
  }

}());

Здесь дочерний компонент создает ссылку на функцию родительского компонента addNewForm, которая затем может быть связана с HTML и вызываться, как и любая другая функция.

1 голос
/ 21 февраля 2014

Ниже приведен publish-subscribe подход, который не зависит от Angular JS.

Контроллер параметров поиска

//Note: Multiple entities publish the same event
regionButtonClicked: function () 
{
        EM.fireEvent('onSearchParamSelectedEvent', 'region');
},

plantButtonClicked: function () 
{
        EM.fireEvent('onSearchParamSelectedEvent', 'plant');
},

Контроллер вариантов поиска

//Note: It subscribes for the 'onSearchParamSelectedEvent' published by the Search Param Controller
localSubscribe: function () {
        EM.on('onSearchParamSelectedEvent', this.loadChoicesView, this);

});


loadChoicesView: function (e) {

        //Get the entity name from eData attribute which was set in the event manager
        var entity = $(e.target).attr('eData');

        console.log(entity);

        currentSelectedEntity = entity;
        if (entity == 'region') {
            $('.getvalue').hide();
            this.loadRegionsView();
            this.collapseEntities();
        }
        else if (entity == 'plant') {
            $('.getvalue').hide();
            this.loadPlantsView();
            this.collapseEntities();
        }


});

Менеджер событий

myBase.EventManager = {

    eventArray:new Array(),


    on: function(event, handler, exchangeId) {
        var idArray;
        if (this.eventArray[event] == null) {
            idArray = new Array();
        } else { 
            idArray = this.eventArray[event];
        }
        idArray.push(exchangeId);
        this.eventArray[event] = idArray;

        //Binding using jQuery
        $(exchangeId).bind(event, handler);
    },

    un: function(event, handler, exchangeId) {

        if (this.eventArray[event] != null) {
            var idArray = this.eventArray[event];
            idArray.pop(exchangeId);
            this.eventArray[event] = idArray;

            $(exchangeId).unbind(event, handler);
        }
    },

    fireEvent: function(event, info) {
        var ids = this.eventArray[event];

        for (idindex = 0; idindex < ids.length; idindex++) {
            if (ids[idindex]) {

                //Add attribute eData
                $(ids[idindex]).attr('eData', info);
                $(ids[idindex]).trigger(event);
            }
        }
    }
};

Global

var EM = myBase.EventManager;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...