在我正在研究的新项目中,我已经开始使用组件而不是指令。
然而,我遇到了一个问题,我无法找到具体的标准方法。
从孩子到父母通知一个事件很容易,你可以在我的plunkr下面找到它,但是从父母到孩子通知一个事件的正确方法是什么?
Angular2似乎通过使用以下内容解决了这个问题:https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-local-var 但是,我不认为定义子组件的“指针”是可能的,就像#timer
中的示例一样为了保证可以轻松转换为Angular2,我想避免:
示例代码:
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示例
答案 0 :(得分:29)
要允许父组件将事件传递给子组件,请让子组件发布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
属性定义的Angular Expression,其API公开为$API
。这种方法的优点是父级可以通过使用Angular Expression将函数传递给子组件来对子初始化做出反应。
来自文档:
'isolate'范围对象哈希定义了一组从指令元素的属性派生的局部范围属性。这些本地属性对于模板的别名值很有用。对象哈希中的键映射到隔离范围上的属性名称;这些值通过匹配指令元素的属性来定义属性如何绑定到父作用域:
&
或&attr
- 提供了在父作用域的上下文中执行表达式的方法。如果未指定attr名称,则假定属性名称与本地名称相同。给定<my-component my-attr="count = count + value">
和隔离范围定义范围:{ localFn:'&myAttr' }
,隔离范围属性localFn
将指向count = count + value expression
的函数包装器。通常需要通过表达式将数据从隔离范围传递到父范围。这可以通过将局部变量名称和值的映射传递到表达式包装器fn来完成。例如,如果表达式为increment($amount)
,那么我们可以通过将localFn
称为localFn({$amount: 22})
来指定金额值。
- AngularJS Comprehensive Directive API -- scope
作为惯例,我建议在$
前加上局部变量,以区别于父变量。
注意:为了简化向Angular 2+的过渡,请避免使用双向=
绑定。而是使用单向<
绑定和表达式&
绑定。有关详细信息,请参阅AngularJS Developer Guide - Understanding Components。
要允许父组件将事件传递给子组件,请让子组件发布API:
<grid-component api="$ctrl.gridApi"></grid-component>
在上面的示例中,grid-component
使用绑定将其API发布到使用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++;
}
}
});
然后,父组件可以使用已发布的API调用子save
函数:
ctrl.click = function(){
console.log("Search clicked");
ctrl.gridApi.save();
}
答案 1 :(得分:3)
这是一种简单的方法:http://morrisdev.com/2017/03/triggering-events-in-a-child-component-in-angular/
基本上,你添加一个名为“command”(或任何你想要的)的绑定变量,并使用$ onChanges来关注该变量的变化并触发它所说的手动触发的任何事件。
我个人喜欢将所有变量放入一个名为“settings”的对象中,并将其发送到我的所有组件。但是,更改对象中的值不会触发$ onChanges事件,因此您需要告诉它使用平面变量触发事件。
我认为这不是“正确”的方式,但它确实更容易编程,更容易理解,并且在以后的路上更容易转换为A2。 / p>
答案 2 :(得分:1)
我面对同样的问题。您如何看待这种方法:通过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++;
}
}
});
或者我们可以为父级定义setter方法以使其更明确。
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++;
}
}
});
答案 3 :(得分:0)
简单:您只需要一个属性以1向绑定,因为2向绑定仅在创建时调用onChanges。
在父控制器上设置一个新的布尔属性。
vm.changeNow = false; //当您要告诉组件执行以下操作时,将其更新为vm.changeNow =!vm.changeNow //调用一个方法。
“打开子组件”,在“绑定”部分,
绑定:{ a2waybind:'=', changenow:“ <” }
您现在需要对该子项进行$ onChanges事件。
$ onChanges(){ //做一些您想听父母说的甜话。 }
现在调用模板时:
childComponent a2waybind =“ $ ctrl.mycoolvalue” changenow =“ $ ctrl.changeNow” / childComponent“
第二种方法是在子组件中:
var vm = this;
var myprop;
Object.defineProperty(vm, 'mytwowayprop', {
get() {
return myprop;
},
set(value) {
myprop = value;
vm.onchangeseventbecausemypropchanged();
}
});
vm.onchangeseventbecausemypropchanged = function () {//woot}
当双向绑定属性在内部和外部同时更改时,这将使您具有已定义的onchanges事件。