Передача событий от родителя к потомку в компонентах 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
aslocalFn({$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++;
}
}
});