从 AngularJS 中的 parent 命令特定的 child 组件
Command a specific child component from parent in AngularJS
我正在使用 AngularJS 1.5.8。
我有 "myParent" 和 "myChild" 组件。
在我看来,我在 parent 里面有 1 parent 和 2 children。
所以我的问题是:我想在 "myParent" 组件的控制器中有 children "myChild" 组件的实例,并且 仅向特定的 child[ 发出命令=50=] 到 makePrimary(),或类似的...我怎样才能实现这个目标?
JS:
//var myApp =
angular.module('myApp', ['myChild', 'myParent']);
angular.
module('myChild', []).
component('myChild', {
template: '<div class="panel panel-default">' +
'<div class="panel-heading">Child</div>' +
'<div class="panel-body">' +
'Child content...' +
'</div>' +
'</div>',
controller: ['$scope', '$element',
function myChildController($scope, $element) {
}
]
});
angular.
module('myParent', ['myChild']).
component('myParent', {
template: '<div class="panel panel-default">' +
'<div class="panel-heading">Parent</div>' +
'<div class="panel-body">' +
'<my-child></my-child>' +
'<hr />' +
'<my-child></my-child>' +
'</div>' +
'</div>',
controller: ['$scope', '$element',
function myParentController($scope, $element) {
// TODO: MAKE CHILD-2 ".panel-primary" CLASS IN HERE.
// BUT ONLY A SPECIFIC CHILD!
}
]
});
HTML:
<div ng-app="myApp" class="container">
<my-parent></my-parent>
</div>
JSFIDDLE 示例:
https://jsfiddle.net/zhc12t1a/4/
我检查了一些相关问题,例如:
- angularJS: How to call child scope function in parent scope
- AngularJS - Access to child scope
但是我找不到合适的方法来通过简单的架构实现这个目标。
编辑
我知道一些复杂的方法(从架构的角度来看),但我不想使用它们。例如:
使用$parent 或
在 myParentController 中:
$scope.makeChild1Primary = function () {}
在 myParent 模板中:
<my-child make-primary="makeChild1Primary"></my-child>
在 myChild 组件中
//...
var ctrl = this;
ctrl.makePrimary = function () { /* MAKE PRIMARY LOGIC HERE... */ }
//...
,bindings: {
makePrimary: '='
}
如“AngularJS - Access to child scope”中所述,无法从父级访问子级作用域,因为 AngularJS 从子级到父级处理属性,而不是相反。
如果您不想将子元素的 ng-class 绑定到父元素的 属性 或使用公共服务,则必须明确地将子元素的作用域添加到父元素属性 像这样:
function myParentController($scope, $element) {
$scope.children = [];
...
}
function myChildController($scope, $element) {
$scope.$parent.children.push($scope);
}
然后你可以像这样访问父级的所有子级:
$scope.children[1].isPrimary = true;
在您的 HTML 中,您将面板的 class 绑定到 属性 "isPrimary",如下所示:
<div class="panel panel-default" ng-class="isPrimary ? 'panel-primary' : ''">
您可以在此处找到示例的完整实现:https://jsfiddle.net/81eesouy/7/
我通过使用 child 组件的 bindings 配置实现了这个目标。
这里的关键点是,(由 parent 所做的更改)反映到 child 的绑定 属性 中。我们必须永远记住这一点!因此,所需的更改如下:
JS:
function myParentController($scope) {
// the variables that controls children's primary statuses
$scope.child1Primary = false;
$scope.child2Primary = false;
}
// component definition
// ...
controller: ['$scope',
function myChildController($scope) {
// This $watch is not required. I used it for only showing that the changes are reflecting dynamically.
$scope.$watch('$ctrl.isPrimary', function(newVal) {
alert("CHANGE DETECTED BY CHILD\n$ctrl.isPrimary: " + newVal);
})
}
],
bindings: {
isPrimary: '<'
}
//...
PARENT 模板:
<my-child is-primary="child1Primary"></my-child><br />
<my-child is-primary="child2Primary"></my-child>
完成 JSFIDDLE LINK:
https://jsfiddle.net/zhc12t1a/5/
并且每当我们更改 childXPrimary 变量时,$ctrl.isPrimary 变量就会在 child 的范围内发生变化。因此,"myChild" 组件中不需要像 "makePrimary" 这样的函数。
注意:ng-class用于class变化,但它是一个细节。这里最重要的是通信架构。
使用 $emit 或 $broadcast 事件。
这是我认为最好的干净答案,您可以尝试使用服务,但这是我更喜欢的答案:)
快速示例
function controllerParent($scope){
$scope.emitActionClick = function(){
$scope.$broadcast('myTestEvent',{data:"passed"})
}
}
function controllerChildX($scope){
$scope.$on('myTestEvent',function(event,data){
// HERE WE ARE :)
console.log(data);
}
}
如果您正在使用 Controller As,您将需要注入 $scope 或 $rootScope。
不幸的是,没有其他方法可以处理发射和广播事件。
我已经尝试过触发器变量绑定,但是由于每次激活后需要重置触发器或使用 numerator
作为触发器,所以这很复杂。那是因为 child 需要区分触发器何时更改才能知道它是否被激活。
相反,我向 child 发送了一个 observable
。 child 正在侦听 observable
上的 parent 命令。我们可以在AngularJs
中使用Rxjs
。
一种有点类似的方法可以是从 parent 向 child 提供一个寄存器函数,其中 child 调用并提供一个接口 object然后 parent 可以存储和使用 child 上的激活方法。这种方法的问题是当 child 消失时需要清理 parent 中存储的接口。在parent observable solution
中,我们反方向进行。 child 负责在 parent 上注册自己并清理自己。
我正在使用 AngularJS 1.5.8。 我有 "myParent" 和 "myChild" 组件。 在我看来,我在 parent 里面有 1 parent 和 2 children。 所以我的问题是:我想在 "myParent" 组件的控制器中有 children "myChild" 组件的实例,并且 仅向特定的 child[ 发出命令=50=] 到 makePrimary(),或类似的...我怎样才能实现这个目标?
JS:
//var myApp =
angular.module('myApp', ['myChild', 'myParent']);
angular.
module('myChild', []).
component('myChild', {
template: '<div class="panel panel-default">' +
'<div class="panel-heading">Child</div>' +
'<div class="panel-body">' +
'Child content...' +
'</div>' +
'</div>',
controller: ['$scope', '$element',
function myChildController($scope, $element) {
}
]
});
angular.
module('myParent', ['myChild']).
component('myParent', {
template: '<div class="panel panel-default">' +
'<div class="panel-heading">Parent</div>' +
'<div class="panel-body">' +
'<my-child></my-child>' +
'<hr />' +
'<my-child></my-child>' +
'</div>' +
'</div>',
controller: ['$scope', '$element',
function myParentController($scope, $element) {
// TODO: MAKE CHILD-2 ".panel-primary" CLASS IN HERE.
// BUT ONLY A SPECIFIC CHILD!
}
]
});
HTML:
<div ng-app="myApp" class="container">
<my-parent></my-parent>
</div>
JSFIDDLE 示例: https://jsfiddle.net/zhc12t1a/4/
我检查了一些相关问题,例如:
- angularJS: How to call child scope function in parent scope
- AngularJS - Access to child scope
但是我找不到合适的方法来通过简单的架构实现这个目标。
编辑
我知道一些复杂的方法(从架构的角度来看),但我不想使用它们。例如:
使用$parent 或
在 myParentController 中:
$scope.makeChild1Primary = function () {}
在 myParent 模板中:
<my-child make-primary="makeChild1Primary"></my-child>
在 myChild 组件中
//...
var ctrl = this;
ctrl.makePrimary = function () { /* MAKE PRIMARY LOGIC HERE... */ }
//...
,bindings: {
makePrimary: '='
}
如“AngularJS - Access to child scope”中所述,无法从父级访问子级作用域,因为 AngularJS 从子级到父级处理属性,而不是相反。
如果您不想将子元素的 ng-class 绑定到父元素的 属性 或使用公共服务,则必须明确地将子元素的作用域添加到父元素属性 像这样:
function myParentController($scope, $element) {
$scope.children = [];
...
}
function myChildController($scope, $element) {
$scope.$parent.children.push($scope);
}
然后你可以像这样访问父级的所有子级:
$scope.children[1].isPrimary = true;
在您的 HTML 中,您将面板的 class 绑定到 属性 "isPrimary",如下所示:
<div class="panel panel-default" ng-class="isPrimary ? 'panel-primary' : ''">
您可以在此处找到示例的完整实现:https://jsfiddle.net/81eesouy/7/
我通过使用 child 组件的 bindings 配置实现了这个目标。 这里的关键点是,(由 parent 所做的更改)反映到 child 的绑定 属性 中。我们必须永远记住这一点!因此,所需的更改如下:
JS:
function myParentController($scope) {
// the variables that controls children's primary statuses
$scope.child1Primary = false;
$scope.child2Primary = false;
}
// component definition
// ...
controller: ['$scope',
function myChildController($scope) {
// This $watch is not required. I used it for only showing that the changes are reflecting dynamically.
$scope.$watch('$ctrl.isPrimary', function(newVal) {
alert("CHANGE DETECTED BY CHILD\n$ctrl.isPrimary: " + newVal);
})
}
],
bindings: {
isPrimary: '<'
}
//...
PARENT 模板:
<my-child is-primary="child1Primary"></my-child><br />
<my-child is-primary="child2Primary"></my-child>
完成 JSFIDDLE LINK: https://jsfiddle.net/zhc12t1a/5/
并且每当我们更改 childXPrimary 变量时,$ctrl.isPrimary 变量就会在 child 的范围内发生变化。因此,"myChild" 组件中不需要像 "makePrimary" 这样的函数。
注意:ng-class用于class变化,但它是一个细节。这里最重要的是通信架构。
使用 $emit 或 $broadcast 事件。
这是我认为最好的干净答案,您可以尝试使用服务,但这是我更喜欢的答案:)
快速示例
function controllerParent($scope){
$scope.emitActionClick = function(){
$scope.$broadcast('myTestEvent',{data:"passed"})
}
}
function controllerChildX($scope){
$scope.$on('myTestEvent',function(event,data){
// HERE WE ARE :)
console.log(data);
}
}
如果您正在使用 Controller As,您将需要注入 $scope 或 $rootScope。 不幸的是,没有其他方法可以处理发射和广播事件。
我已经尝试过触发器变量绑定,但是由于每次激活后需要重置触发器或使用 numerator
作为触发器,所以这很复杂。那是因为 child 需要区分触发器何时更改才能知道它是否被激活。
相反,我向 child 发送了一个 observable
。 child 正在侦听 observable
上的 parent 命令。我们可以在AngularJs
中使用Rxjs
。
一种有点类似的方法可以是从 parent 向 child 提供一个寄存器函数,其中 child 调用并提供一个接口 object然后 parent 可以存储和使用 child 上的激活方法。这种方法的问题是当 child 消失时需要清理 parent 中存储的接口。在parent observable solution
中,我们反方向进行。 child 负责在 parent 上注册自己并清理自己。