Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.1k views
in Technique[技术] by (71.8m points)

angularjs - How to update child components from the updated list of parents

I'm new to Angular and currently using version 1.6.

I'm implementing the component style of Angular. I just want to ask what's the best way to communicate from parent to child components? I know there is an existing question but I have a specific scenario (I'm not sure if it's unique or not).

Here is the scenario:

Modal -> create new todo -> Parent ( update the object ) -> personal todo ( update the list )

  1. I have a modal for creating todo.
  2. Then after creating new todo pass the value on the parent to update the object of todo.
  3. And when I updated the parent list of todo pass to the personal todo components to update the list on the view.
  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;
        }

My question again is how I can pass the updated data after I create to the child component which is in charge of displaying the todo list?

UPDATED

<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>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

How to update child components with changes from parents

Use one-way bindings <

  • < or <attr - set up a one-way (one-directional) binding between a local scope property and an expression passed via the attribute attr. The expression is evaluated 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. You can also make the binding optional by adding ?: <? or <?attr.

For example, given <my-component my-attr="parentModel"> and directive definition of scope: { localModel:'<myAttr' }, then the isolated scope property localModel will reflect the value of parentModel on the parent scope. Any changes to parentModel will be reflected in localModel, but changes in localModel will not reflect in parentModel.

AngularJS Comprehensive Directive API Reference - scope

And the $onChanges life-cycle hook:

  • $onChanges(changesObj) - Called whenever one-way bindings are updated. The changesObj is a hash whose keys are the names of the bound properties that have changed, and the values are an object of the form { currentValue, previousValue, isFirstChange() }. Use this hook to trigger updates within a component.

AngularJS Developer Guide - Components


With object content — Use the $doCheck Life-cycle Hook

When binding an object or array reference, the $onChanges hook only executes when the value of the reference changes. To check for changes to the contents of the object or array, use the $doCheck life-cycle hook:

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
      };
    }
})

From the Docs:

The controller can provide the following methods that act as life-cycle hooks:

  • $doCheck() - Called on each turn of the digest cycle. Provides an opportunity to detect and act on changes. Any actions that you wish to take in response to the changes that you detect must be invoked from this hook; implementing this has no effect on when $onChanges is called. For example, this hook could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which would not be detected by Angular's change detector and thus not trigger $onChanges. This hook is invoked with no arguments; if detecting changes, you must store the previous value(s) for comparison to the current values.

AngularJS Comprehensive Directive API Reference -- Life-cycle hooks

For more information,


Simple DEMO

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>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...