【问题标题】:How to update child components from the updated list of parents如何从更新的父级列表中更新子组件
【发布时间】:2017-09-04 00:13:34
【问题描述】:

我是 Angular 新手,目前使用的是 1.6 版。

我正在实现 Angular 的组件样式。我只想问从父组件到子组件的最佳通信方式是什么?我知道存在一个问题,但我有一个特定的场景(我不确定它是否独特)。

这是场景:

Modal -> 创建新的 todo -> Parent(更新对象)-> Personal todo(更新列表)

  1. 我有一个创建待办事项的模式。
  2. 然后在创建新的 todo 后,将值传递给父级以更新 todo 的对象。
  3. 当我更新了 todo 的父列表时,将传递给个人 todo 组件以更新视图上的列表。
  angular.module('tab')
    .controller('TabController', TabController);

  function TabController() {
    let vm = this;
    let updatedTodoObject = {};

    vm.$onInit = function () {
      vm.personalTodo = vm.todo.own_todo;
      vm.externalTodo = vm.todo.external_todo;
    }

    vm.$onChanges = function (changes) {
      console.log('I\'m triggered');
    }

    vm.updateTodoList  = updateTodoList;

   function updateTodoList( result ) {
    updatedTodoObject = angular.copy(vm.todo);
    updatedProjectObject.user_todos.push(result)
    if( vm.todo !== updatedTodoObject) {
     vm.todo = updatedTodoObject;
    } else {
     console.log("Still in reference");
    }
   }

    vm.getUpdatedTodotList = function( ) {
      return vm.todo;
    }
  }
angular.module('...')
    .component('...', {
      bindings: {
        onResultTodoUpdated: '&'
      },
      controllerAs: 'todo',
      controller: ['TodoService', '$log', '$state', function(TodoService, $log, $state) {
        let vm = this;
        let todo = {};

        vm.newTodoModal = function() {
          TodoService.newTodoModal()
            .then(function (TodoName) {
              TodoService.createTodo(TodoName)
                .then(function(response) {
                  if( response.status === 201 ) {

                    todo = {
                      ...
                      ...
                    }

                    vm.onResultTodoUpdated( { result: todo } );
                  }
                })
                .catch(function(error) {
                  console.log(error);
                });
  angular.module('...')
    .component('...', {
      bindings: {
        todos: "<"
      },
      controllerAs: 'personal',
      controller: function(){
        let vm = this;
        vm.isShowTodoArchived = false;

        vm.$onInit = function () {
          getWatchedTodo();
        }

        function getWatchedTodo () {
         vm.todos = vm.todos;
         vm.todosSize = vm.todos.length;
        }

我的问题又是如何在创建后将更新的数据传递给负责显示待办事项列表的子组件?

更新

<div class="tab-pane active" id="todosTab">
  <nv-new-todo on-result-todo-updated="todo.updateTodoList(result)"></nv-new-project>

  <div class="my-todos">
    <nv-personal-todo todos="todo.personalTodo" ></nv-personal-todo>
    <nv-external-todo todos="todo.externalTodo"></nv-external-todo>
  </div>
</div>

【问题讨论】:

  • 当询问由您的代码引起的问题时,如果您提供人们可以用来重现问题的代码,您将获得更好的答案。 尽可能少地使用仍然会产生相同问题的代码。参见How to create a Minimal, Complete, and Verifiable example
  • 如果TabController 是用ng-controller 指令实例化的,$onChanges 钩子将永远不会触发,因为ng-controller 指令不会绑定任何东西。
  • 该问题定义了两个名为 '...' 的组件。哪个是nvPersonalTodo?哪个是nvExternalTodo

标签: angularjs angular-components


【解决方案1】:

如何使用父组件的更改更新子组件

使用one-way bindings &lt;

  • &lt;&lt;attr - 在本地范围属性和通过属性 attr 传递的表达式之间设置单向(单向)绑定。表达式在父作用域的上下文中计算。如果未指定 attr 名称,则假定属性名称与本地名称相同。您还可以通过添加?&lt;?&lt;?attr 使绑定成为可选。

例如,给定&lt;my-component my-attr="parentModel"&gt;scope: { localModel:'&lt;myAttr' } 的指令定义,那么隔离作用域属性localModel 将在父作用域上反映parentModel 的值。对parentModel 的任何更改都将反映在localModel 中,但localModel 的更改不会反映在parentModel 中。

——AngularJS Comprehensive Directive API Reference - scope

还有$onChanges 生命周期钩子:

  • $onChanges(changesObj) - 每当更新单向绑定时调用。 changesObj 是一个散列,其键是已更改的绑定属性的名称,值是{ currentValue, previousValue, isFirstChange() } 形式的对象。使用此挂钩触发组件内的更新。

——AngularJS Developer Guide - Components


使用对象 content — 使用 $doCheck 生命周期挂钩

在绑定对象或数组reference时,$onChanges 挂钩仅在引用的发生变化时执行。要检查对象或数组的内容的变化,请使用$doCheck生命周期挂钩:

app.component('nvPersonalTodo', {
  bindings: {
    todos: "<"
  },
  controller: function(){
    var vm = this;
    this.$doCheck = function () {
      var oldTodos;
      if (!angular.equals(oldTodos, vm.todos)) {
        oldTodos = angular.copy(vm.todos);
        console.log("new content");          
        //more code here
      };
    }
})

来自文档:

控制器可以提供以下方法作为生命周期钩子:

  • $doCheck() - 在摘要循环的每一轮调用。提供检测变化并采取行动的机会。必须从这个钩子中调用您为响应检测到的更改而希望采取的任何操作;实现这一点对何时调用 $onChanges 没有影响。例如,如果您希望执行 深度相等性检查,或检查 Date 对象,Angular 的更改检测器不会检测到更改并因此不会触发,则此挂钩可能很有用$onChanges. 这个钩子在没有参数的情况下被调用;如果检测到更改,您必须存储之前的值以供比较与当前值。

——AngularJS Comprehensive Directive API Reference -- Life-cycle hooks

如需了解更多信息,


简单演示

angular.module("app",[])
.component("parentComponent", {
    template: `
        <fieldset>
            Inside parent component<br>
            parentData={{$ctrl.parentData}}
            <child-component in-data="$ctrl.parentData"></child-component>
        </fieldset>
    `,
    controller: function () {
        this.$onInit = () => {
            this.parentData = 'test'
        };
    },
})
.component("childComponent",{
    bindings: {
        inData: '<',
    },
    template: `
        <fieldset>Inside child component<br>
            inData={{$ctrl.inData}}
        </fieldset>
    `,
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
    <parent-component>
    </parent-component>
<body>

有关详细信息,请参阅

【讨论】:

  • 老实说,我已经这样做了,但是当我更新 $onChanges 的父值时,它没有触发将该值传播到其他子组件。有什么想法吗?
  • 如果你使用对象或数组,你真的必须小心!看到这个:blog.kwintenp.com/the-onchanges-lifecycle-hook
  • @dom 谢谢你的信息。我更新了答案以展示如何使用 $doCheckangular.equals 进行深度相等检查。
猜你喜欢
  • 2017-06-18
  • 1970-01-01
  • 2019-05-02
  • 2020-08-08
  • 2016-12-02
  • 1970-01-01
  • 2023-02-20
  • 2013-01-19
  • 1970-01-01
相关资源
最近更新 更多