У меня есть родительский компонент, который получает данные с сервера через службу. Мне нужно, чтобы некоторые из этих данных передавались дочернему компоненту.
Я пытался передать эти данные с обычным @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
lifecycle. Проблема, с которой я сталкиваюсь, заключается в том, что функция ngOnChanges
не запускается, когда данные обновляются. Данные являются объектом, поэтому я считаю, что изменения не обнаруживаются.
Обновлен код в дочернем компоненте
@Component({
selector: 'test-child',
template: `
<!-- Content for child.... -->
`
})
export class ChildComponent implements OnChanges {
@Input() childData: any;
ngOnChanges() {
console.log(childData); // logs undefined
}
}
Я пробовал тест с Live-примерами на Plunker из команды Angular, демонстрирующей привязки Lifecycle. В тесте я обновил OnChangesComponent для передачи объекта, который, как видно из примера при обновлении объекта, ngOnChanges не обнаруживает изменения. (Это также показано в этом question)
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
.
Надеюсь, что это окажется полезным:)