问题
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 )
- I have a modal for creating todo.
- Then after creating new todo pass the value on the parent to update the object of todo.
- 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>
回答1:
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 attributeattr
. 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 ofscope: { localModel:'<myAttr' }
, then the isolated scope propertylocalModel
will reflect the value ofparentModel
on the parent scope. Any changes toparentModel
will be reflected inlocalModel
, but changes inlocalModel
will not reflect inparentModel
.— AngularJS Comprehensive Directive API Reference - scope
And the $onChanges
life-cycle hook:
$onChanges(changesObj)
- Called whenever one-way bindings are updated. ThechangesObj
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,
- AngularJS angular.equals API Reference
- AngularJs 1.5 - Component does not support Watchers, what is the work around?
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>
For more information, see
- AngularJS Developer Guide - Component-based application architecture
- AngularJS Comprehensive API Reference - scope
来源:https://stackoverflow.com/questions/43297962/how-to-update-child-components-from-the-updated-list-of-parents