从 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 上注册自己并清理自己。