Angular 2 - Передача данных в дочерний компонент после родительской инициализации
У меня есть родительский компонент, который получает данные с сервера через службу. Мне нужно, чтобы некоторые из этих данных были переданы в дочерний компонент.
Я пытался передать эти данные с обычным@Input()
Однако, как я ожидал, данные, которые я получаю в дочернем компонентеundefined
.
пример
Родительский компонент
@Component({
selector: 'test-parent',
template: `
<test-child [childData]="data"></test-child>
`
})
export class ParentComponent implements OnInit {
data: any;
ngOnInit() {
this.getData();
}
getData() {
// calling service and getting data
this.testService.getData()
.subscribe(res => {
this.data = res;
});
}
}
Дочерний компонент
@Component({
selector: 'test-child',
template: `
<!-- Content for child.... -->
`
})
export class ChildComponent implements OnInit {
@Input() childData: any;
ngOnInit() {
console.log(childData); // logs undefined
}
}
Я сохранил простой пример, чтобы показать, что я пытаюсь сделать. У меня вопрос, можно ли передать данные ребенку после инициализации. Я не уверен, но поможет ли в этом случае двусторонняя привязка данных?
Больше расследования
После опубликованных ответов я попытался использоватьngOnChanges
жизненный цикл крюка. У меня проблема в том, чтоngOnChanges
функция не запускается при обновлении данных. Данные - это объект, поэтому я думаю, что изменения не обнаруживаются.
Обновлен код в дочернем компоненте
@Component({
selector: 'test-child',
template: `
<!-- Content for child.... -->
`
})
export class ChildComponent implements OnChanges {
@Input() childData: any;
ngOnChanges() {
console.log(childData); // logs undefined
}
}
Я попробовал провести тест с примерами на Plunker от команды Angular, демонстрирующий крюки жизненного цикла. В тесте я обновил OnChangesComponent для передачи объекта, который, как видно из примера при обновлении объекта, ngOnChanges не обнаруживает изменения. (Это также показано в этомвопрос)
https://plnkr.co/edit/KkqwpsYKXmRAx5DK4cnV
Кажется, чтоngDoCheck
может помочь решить эту проблему, но мне кажется, что это не поможет производительности в долгосрочной перспективе, так как каждое изменение обнаруживается этим Lifecycle Hook.
Также я знаю, что я мог бы использовать@ViewChild()
чтобы получить доступ к дочернему компоненту и установить необходимые мне переменные, но я не думаю, что для этого варианта использования это имеет большой смысл.
Размещение большего количества кода, чтобы помочь объяснить лучше
Родительский компонент
@Component({
selector: 'test-parent',
template: `
<test-child [childType]="numbers" [childData]="data" (pickItem)="pickNumber($event)">
<template let-number>
<span class="number" [class.is-picked]="number.isPicked">
{{ number.number }}
</span>
</template>
</test-child>
<test-child [childType]="letters" [childData]="data" (pickItem)="pickLetter($event)">
<template let-letter>
<span class="letter" [class.is-picked]="letter.isPicked">
{{ letter.displayName }}
</span>
</template>
</test-child>
<button (click)="submitSelections()">Submit Selection</button>
`
})
export class ParentComponent implements OnInit {
data: any;
numbersData: any;
lettersData: any;
ngOnInit() {
this.getData();
}
getData() {
// calling service and getting data for the game selections
this.testService.getData()
.subscribe(res => {
this.data = res;
setChildData(this.data);
});
}
setChildData(data: any) {
for(let i = 0; i < data.sections.length; i++) {
if(data.sections[i].type === 'numbers') {
this.numbersData = data.sections[i];
}
if(data.sections[i].type === 'letters') {
this.lettersData = data.sections[i];
}
}
}
pickNumber(pickedNumbers: any[]) {
this.pickedNumbers = pickedNumbers;
}
pickLetter(pickedLetters: any[]) {
this.pickedLetters = pickedLetters;
}
submitSelections() {
// call service to submit selections
}
}
Дочерний компонент
@Component({
selector: 'test-child',
template: `
<!--
Content for child...
Showing list of items for selection, on click item is selected
-->
`
})
export class ChildComponent implements OnInit {
@Input() childData: any;
@Output() onSelection = new EventEmitter<Selection>;
pickedItems: any[];
// used for click event
pickItem(item: any) {
this.pickedItems.push(item.number);
this.onSelection.emit(this.pickedItems);
}
}
Это более или менее тот код, который у меня есть. В основном у меня есть родительский объект, который обрабатывает выборки из дочерних компонентов, а затем я отправляю эти выборки в службу. Мне нужно передать определенные данные ребенку, потому что я пытаюсь получить объект, который ребенок возвращает в формате, ожидаемом службой. Это помогло бы мне не создавать весь объект, ожидаемый службой в родительском компоненте. Также это сделало бы ребенка повторно используемым в том смысле, что он отправляет обратно то, что ожидает служба.
Обновить
Я ценю, что пользователи все еще публикуют ответы на этот вопрос. Обратите внимание, что код, который был размещен выше, работал для меня. Проблема, с которой я столкнулся, заключалась в том, что в конкретном шаблоне была опечатка, из-за которой данные былиundefined
.
Надеюсь, что это окажется полезным :)