在 AngularJS 组件中将事件从 Parent 传送到 Child

Communicating Events from Parent to Child in AngularJS Components

在我正在处理的新项目中,我已经开始使用组件而不是指令。

但是,我遇到了一个问题,我找不到具体的标准方法来做到这一点。

通知从child到parent的事件很容易,你可以在下面的我的plunkr上找到它,但是通知从parent到[的事件的正确方法是什么? =50=]?

Angular2 似乎通过使用如下方式解决了这个问题:https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-local-var 但我不认为有可能为 child 组件定义 "pointer" ,就像使用 #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

其中 child 需要 parent,然后 child 设置 parent 对 child 的引用...现在 parent 可以使用 child... 丑陋但它就像上面的 angular2 示例

在 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 属性定义的 Angular 表达式,其 API 公开为 $API。这种方法的优点是父级可以通过使用 Angular 表达式将函数传递给子组件来对子级初始化做出反应。

来自文档:

The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the directive's element. These local properties are useful for aliasing values for templates. The keys in the object hash map to the name of the property on the isolate scope; the values define how the property is bound to the parent scope, via matching attributes on the directive's element:

  • & or &attr - provides a way to execute an expression in the context of the parent scope. If no attr name is specified then the attribute name is assumed to be the same as the local name. Given <my-component my-attr="count = count + value"> and the isolate scope definition scope: { localFn:'&myAttr' }, the isolate scope property localFn will point to a function wrapper for the count = count + value expression. Often it's desirable to pass data from the isolated scope via an expression to the parent scope. This can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment($amount) then we can specify the amount value by calling the localFn as 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();
}

DEMO on PLNKR.

这是一个简单的方法:http://morrisdev.com/2017/03/triggering-events-in-a-child-component-in-angular/

基本上,您添加一个名为 "command" 的绑定变量(或任何您想要的)并使用 $onChanges 来关注该变量的变化并触发它所说的手动触发的任何事件。

我个人喜欢将所有变量放入一个名为 "settings" 的对象中,并将其发送到我的所有组件。但是,更改对象中的值不会触发 $onChanges 事件,因此您需要告诉它使用平面变量触发事件。

我会说这不是 "proper" 的方法,但它确实更容易编程,更容易理解,并且以后更容易转换为 A2路.

我遇到了同样的问题。您如何看待这种方法:通过 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++;
    }
  }
});

简单:您只需要一个 属性 1 路绑定,因为 2 路绑定仅在创建时调用 onChanges。

  1. 在 parent 控制器上设置一个新的布尔值 属性。

    vm.changeNow = 假; //当你想告诉组件 //调用一个方法。

  2. 打开Child组件,在绑定部分,

    绑定:{ a2waybind: '=', 现在改变:'<' }

  3. 您现在需要 child 上的 $onChanges 事件。

    $onChanges() { // 做一些你想从 parent 听到的甜言蜜语。 }

  4. 现在调用模板时:

    childComponent a2waybind="$ctrl.mycoolvalue" changenow="$ctrl.changeNow" /childComponent"

第二种方法是在您的 child 组件中:

        var vm = this;
        var myprop;
        Object.defineProperty(vm, 'mytwowayprop', {
            get() {
                return myprop;
            },
            set(value) {
                myprop = value; 
                vm.onchangeseventbecausemypropchanged();               
            }
        });
       vm.onchangeseventbecausemypropchanged = function () {//woot}

当您的双向绑定 属性 在内部和外部发生变化时,这将允许您定义 onchanges 事件。