无法理解Angular组件

时间:2016-11-08 01:12:15

标签: angularjs

我正在尝试了解Angular组件,但却无法让它们在嵌套组件配置中工作。基本上我想要做的是拥有一个定期更新值的父组件。然后我希望内部子组件绑定到父组件中的值,并在值更改时触发对$ onChanges的调用。

我做了一个jsFiddle来展示我想要完成的事情。父组件似乎正在工作并显示更新的值,但由于某种原因,子组件根本没有呈现。以下是我用来完成此任务的代码:

let app = angular.module('app', []);

class ParentController {
  constructor($interval) {
    this.value = 0;

    $interval(() => this.value++, 1000);
  }
}

let ParentComponent = {
  controller: ParentController,
  template: `<div>parent value: {{$ctrl.value}}</div>`
};

app.component('parent', ParentComponent);

class ChildController {
  $onChanges(changesObj) {
    console.log(changesObj);
  }
}

let ChildComponent = {
    bindings: {
    value: '='
  },
  controller: ChildController,
  require: {
    parent: '^^parent'
  },
  template: `<div>child value: {{$ctrl.value}}</div>`
};

app.component('child', ChildComponent);

HTML:

<div ng-app="app">
  <parent>
    <child value="$ctrl.parent.value"></child>
  </parent>
</div>

我做错了什么或是我想要完成的事情不可能?

2 个答案:

答案 0 :(得分:0)

关于组件的事情是,除非你使用&#39; ng-transclude&#39;指令。

要显示您的子元素,您需要进行以下更改:

let ParentComponent = {
  controller: ParentController,
  transclude: true,
  template: `<div>parent value: {{$ctrl.value}}</div><div ng-transclude></div>`
};

为了澄清,您将transclude: true添加到组件对象以及模板中具有ng-transclude指令的元素。任何具有ng-transclude指令的元素都将其内容替换为<parent>标记中的任何内容。

这只会让你的子组件呈现,你的HTML中还有另一个错误,就是你正在尝试使用

<child value="$ctrl.parent.value"></child>

在JavaScript中,它等同于未定义的$scope.$ctrl.parent.value

只需将您的HTML更改为:

<div ng-app="app">
  <parent>
    <child></child>
  </parent>
</div>

并将子组件:

let ChildComponent = {
  controller: ChildController,
  require: {
    parent: '^^parent'
  },
  template: `<div>child value: {{$ctrl.parent.value}}</div>`
};

然后你一切都好!

编辑(来自评论): 为了在父值更改时触发更新调用,您需要将ChildController替换为以下内容:

let ChildController = function (scope) {
  scope.$watch('$ctrl.parent.value', function (newValue, oldValue) {
    console.log(newValue);
  });
};

这会在子控制器上添加一个监视器,每次parent.value更改时都会调用该函数。

答案 1 :(得分:0)

我对你的代码进行了修改。 有一种不同的方式来实现你想要做的事情。 这是我的代码,我将尝试解释它应该如何完成。

   let app = angular.module('app', []);

        class ParentController {
            constructor($interval) {
            this.value = 0;

            $interval(() => this.value++, 1000);
          }
        }

        let ParentComponent = {
            controller: ParentController,
//here is the important edit. loading child component inside the parent component
          template: `<div>
                      parent value: {{$ctrl.value}}
                      <child value="$ctrl.value"></child>
                     </div>`
        };

        app.component('parent', ParentComponent);

        class ChildController {
            $onChanges(changesObj) {
            if(changesObj.hasOwnProperty('value')){
              this.value=changesObj.value.currentValue //this referes to current scope. 
            }
          }
        }

        let ChildComponent = {
            bindings: {
            value: '<'
          },
            controller: ChildController,
          require: {
            //parent: '^^parent' no need for this. we will use $onChanges
          },
          template: `<div>child value: {{$ctrl.value}}</div>`
        };

        app.component('child', ChildComponent);


    <div ng-app="app"><parent></parent></div> 

我在此代码示例中所做的事情:

  1. 我在父组件模板中包含了组件 因为你想要做的是在父母内部加载孩子。所以在父模板中添加了一个孩子。

  2. 删除了子组件定义中的Require,因为它会使您的子组件依赖于父组件。有一个不同的用例,你必须使用父。你最好使用绑定和$ onChanges来更新来自父母的孩子的数据,

  3. 为$ onChanges数据添加了一些验证。

    如果(changesObj.hasOwnProperty(&#39;值&#39;)){               THIS.VALUE = changesObj.value.currentValue             }

  4. 您需要了解更改obj是一个简单的更改对象。它有多个属性,如第一个change(),当前值,OldValue等。 你必须始终从这里验证你想要的东西。 我也将它设置为this.value,这是当前的范围。 我们不是直接使用父作用域或绑定作用域变量。我正在创建一个新的范围对象,您将用它来显示数据。它将由绑定对象填充。

    总体而言,这种情况正在发生 1.parent interval更新父母范围

    2. this.value作为Bindings

    传递给子节点

    3. $onChanges验证绑定并将其分配给本地范围this.value

    4.child模板在UI中呈现this.value