Передача событий от родителя к потомку в компонентах AngularJS

в новом проекте, над которым я работаю, я начал использовать компоненты вместо директив.

однако, я столкнулся с проблемой, где я не могу найти конкретный стандартный способ сделать это.

легко уведомить событие от ребенка к родителю, вы можете найти его на моем plunkr ниже, но каков правильный способ уведомить событие от родителя к ребенку?

Angular2, похоже, решает эту проблему, используя что-то вроде этого: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-local-var Но я не думаю, что есть возможность определить "указатель" на дочерний компонент, как в Примере с #timer

чтобы сохранить возможное простое преобразование в Angular2, я хочу избежать:

  • излучение событий (излучение и трансляция из областей)
  • использование require from the child (а затем добавление обратного вызова в родитель..Уродливый)
  • используя одностороннюю привязку, вводя область в дочерний элемент, а затем" наблюдайте " за этим свойством.. БОЛЕЕ УРОДЛИВОЙ

пример кода:

var app = angular.module('plunker', []);

app.controller('RootController', function() {
});

app.component('parentComponent', {
  template: `
    <h3>Parent component</h3>
    <a class="btn btn-default btn-sm" ng-click="$ctrl.click()">Notify Child</a>
    <span data-ng-bind="$ctrl.childMessage"></span>
    <child-component on-change="$ctrl.notifiedFromChild(count)"></child-component>
  `,
  controller: function() {
    var ctrl = this;
    ctrl.notifiedFromChild = function(count){
      ctrl.childMessage = "From child " + count;
    }
    ctrl.click = function(){
    }
  },
  bindings: {
  }
});

app.component('childComponent', {
  template: `
    <h4>Child component</h4>
    <a class="btn btn-default btn-sm" ng-click="$ctrl.click()">Notify Parent</a>
  `,
  controller: function() {
    var ctrl = this;
    ctrl.counter = 0;
    ctrl.click = function(){
        ctrl.onChange({ count: ++ctrl.counter });
    }
  },
  bindings: {
    onChange: '&'
  }
});

вы можете найти здесь пример:

http://plnkr.co/edit/SCK8XlYoYCRceCP7q2Rn?p=preview

это возможное решение, которое я создал

http://plnkr.co/edit/OfANmt4zLyPG2SZyVNLr?p=preview

где ребенок требуется родитель, а потом ребенок задает Родительский ссылкой на ребенка... теперь родитель может использовать ребенка... уродливый, но это похоже на пример angular2 выше

3 ответов


передача событий от родителя к ребенку в компонентах AngularJS

опубликовать директиву $API с использованием привязки выражений

чтобы разрешить родительским компонентам передавать события дочернему компоненту, попросите ребенка опубликовать API:

<grid-component grid-on-init="$ctrl.gridApi=$API; $ctrl.someFn($API)">
</grid-component>    

JS

app.component('gridComponent', {
  //Create API binding
  bindings: {gridOnInit: "&"},
  template: `
    <h4>Grid component</h4>
    <p> Save count = {{$ctrl.count}}</p>
  `,
  controller: function() {
    var ctrl = this;
    this.$onInit = function() {
        ctrl.count = 0;
        ctrl.api = {};
        //Publish save function
        ctrl.api.save = save;
        //Invoke Expression with $API as local
        ctrl.gridOnInit({$API: ctrl.api});
    };
    function save(){
      console.log("saved!");
      ctrl.count++;
    }
  }
});

приведенный выше пример вызывает Угловое выражение, определенное grid-on-init атрибут с его API, выставленным как $API. Преимущество этого подхода заключается в том, что родитель может реагируйте на дочернюю инициализацию, передавая функцию дочернему компоненту с угловым выражением.

документы:

хэш объекта области "изолировать"определяет набор свойств локальной области, производных от атрибутов элемента директивы. Эти локальные свойства полезны для сглаживания значений шаблонов. Ключи в хэш-сопоставлении объекта с именем свойства в области изолировать; значения определяют, как свойство привязано к родительская область, через соответствующие атрибуты элемента директивы:

  • & или &attr - предоставляет способ выполнения выражения в контексте родительской области. Если имя attr не указано, то предполагается, что имя атрибута совпадает с локальным именем. Дано <my-component my-attr="count = count + value"> и область определения области изоляции:{ localFn:'&myAttr' }, изолировать область недвижимость localFn укажет на оболочку функции для count = count + value expression. Часто желательно передавать данные из изолированная область через выражение для родительской области. Это можно сделать, передав карту имен и значений локальных переменных в оболочку выражений FN. Например, если выражение increment($amount) затем мы можем указать значение суммы, вызвав localFn as localFn({$amount: 22}).

-- AngularJS всеобъемлющая директива API -- scope

в качестве соглашения я рекомендую префикс локальных переменных с $ чтобы отличить их от родительские переменные.


попеременно используйте двунаправленную привязку

Примечание: чтобы облегчить переход на угловой 2+, Избегайте использования двунаправленного = привязка. Вместо этого используйте односторонний < привязка и выражение & привязка. Дополнительные сведения см. В разделе AngularJS Руководство Разработчика-Понимание Компонентов.

чтобы разрешить родительским компонентам связывать события с дочерним компонентом, у ребенка опубликовать API:

<grid-component api="$ctrl.gridApi"></grid-component>

в приведенном выше примере grid-component использует привязки для публикации своего API в родительской области с помощью .

app.component('gridComponent', {
  //Create API binding
  bindings: {api: "="},
  template: `
    <h4>Grid component</h4>
    <p> Save count = {{$ctrl.count}}</p>
  `,
  controller: function() {
    var ctrl = this;
    this.$onInit = function() {
        ctrl.count = 0;
        ctrl.api = {};
        //Publish save function
        ctrl.api.save = save;
    };
    function save(){
      console.log("saved!");
      ctrl.count++;
    }
  }
});

тогда родительский компонент может вызвать дочерний save функция с использованием опубликованного API:

ctrl.click = function(){
  console.log("Search clicked");
  ctrl.gridApi.save();
}

на демо на PLNKR.


вот простой способ: http://morrisdev.com/2017/03/triggering-events-in-a-child-component-in-angular/

в принципе, вы добавляете связанную переменную под названием "command" (или что угодно) и используете $onChanges, чтобы обратить внимание на изменения этой переменной и вызвать любое событие, которое она говорит, чтобы вызвать вручную.

Мне лично нравится помещать все мои переменные в объект под названием "Настройки" и отправлять его всем моим компонентам. Однако, изменение значение в объекте не вызывает событие $onChanges, поэтому вам нужно сообщить ему, чтобы вызвать событие с плоской переменной.

Я бы сказал, что это не "правильный" способ сделать это, но это, конечно, намного проще программировать, намного проще понять и намного проще преобразовать в A2 позже по дороге.


я столкнулся с тем же вопросом. Что вы думаете об этом подходе: к использовать наследование via require вместо двунаправленной привязки?

http://plnkr.co/edit/fD1qho3eoLoEnlvMzzbw?p=preview

var app = angular.module('plunker', []);

    app.controller('RootController', function() {
    });

    app.component('filterComponent', {
      template: `
        <h3>Filter component</h3>
        <a class="btn btn-default btn-sm" ng-click="$ctrl.click()">Search</a>
        <span data-ng-bind="$ctrl.childMessage"></span>

        <grid-component api="$ctrl.gridApi"></grid-component>
      `,
      controller: function() {
        var ctrl = this;

        ctrl.click = function(){
          console.log("Search clicked");
          ctrl.gridApi.save();
        };
      }
    });

    app.component('gridComponent', {
      require: {parent:'^^filterComponent'},
      bindings: {api: "<"},
      template: `
        <h4>Grid component</h4>
        <p> Save count = {{$ctrl.count}}
      `,
      controller: function() {
        var ctrl = this;



        this.$onInit = function() {
            ctrl.count = 0;
            ctrl.api = {};
            ctrl.api.save = save;

            ctrl.parent.gridApi = ctrl.api;
        };
        function save(){
          console.log("saved!");
          ctrl.count++;
        }
      }
    });

или определить способ сеттер для родителей, чтобы сделать его более четким.

http://plnkr.co/edit/jmETwGt32BIn3Tl0yDzY?p=preview

var app = angular.module('plunker', []);

app.controller('RootController', function() {
});

app.component('filterComponent', {
  template: `
    <h3>Filter component</h3>
    <a class="btn btn-default btn-sm" ng-click="$ctrl.click()">Search</a>
    <span data-ng-bind="$ctrl.childMessage"></span>

    <grid-component pass-api="$ctrl.setGridApi(api)"></grid-component>
  `,
  controller: function() {
    var ctrl = this;

    var gridApi = {};

    ctrl.setGridApi = function(api){
      gridApi = api;
    };

    ctrl.click = function(){
      console.log("Search clicked");
      gridApi.save();
    };
  }
});

app.component('gridComponent', {
  bindings: {
    passApi:'&'
  },
  template: `
    <h4>Grid component</h4>
    <p> Save count = {{$ctrl.count}}
  `,
  controller: function() {
    var ctrl = this;

    this.$onInit = function() {
        ctrl.count = 0;
        ctrl.api = {};
        ctrl.api.save = save;

        ctrl.passApi({api: ctrl.api});
    };
    function save(){
      console.log("saved!");
      ctrl.count++;
    }
  }
});