У меня есть @ViewChildren
дочерний компонент (BookFormComponent
) внутри родительского компонента (LibraryComponent
). В моем родительском компоненте я выполняю вызов службы для получения одного объекта BookData
.
Я передаю объект DookData методу дочернего компонента initBookData(...)
. Я хочу, чтобы дочерний компонент использовал BookData для инициализации элементов управления формой. BookData имеет атрибут selectedTypes
, который содержит массив книг, которые пользователь уже выбрал. Я использую массив для проверки его флажков.
Есть 10 флажков, и, например, если у пользователя 5 элементов в массиве selectedTypes
, тогда эти 5 элементов должны быть отмечены из 10 флажков при просмотре отображается.
Проблема, с которой сейчас сталкивается, заключается в том, что элементы управления формы для name
и color
инициализируются значениями из объекта BookData
, но флажки не отмечены (выбраны), когда представление отображается. Я сделал console.log () внутри initSelectedTypes(....)
дочернего компонента, и длины массивов равны 0, в то время как дочерний компонент использует те же массивы для отображения флажков в пользовательском интерфейсе, но когда он должен использовать тот же массив для установите (выберите) некоторые из флажков, тогда длины будут равны 0.
Я понимаю, что <book-form #book></book-form>
в пользовательском интерфейсе родительского компонента совпадает с атрибутом @ViewChildren(BookFormComponent) book: QueryList<BookFormComponent>;
в классе компонента. Итак, поскольку представление отображается, когда я вызываю метод для атрибута (книги), я ожидаю, что все атрибуты (книги) также будут инициализированы. Я не ожидаю, что массивы будут пустыми. Все флажки отображаются правильно в представлении, но когда я вызываю initBookData(...)
, массивы пусты.
Я использую @ViewChildren, потому что я пробовал @ViewChild, и я получал "undefined" (поэтому я не мог даже вызвать дочерние методы)
(я пропустил некоторые вещи в фрагменте кода для экономии места):
interface BookData {
name?: string,
color?: string,
selectedTypes?: Array<string> // this array contains the types a user has selected already
}
// PARENT COMPONENT CLASS
class LibraryComponent implements AfterViewInit, {
@ViewChildren(BookFormComponent) book: QueryList<BookFormComponent>;
// ADDITIONAL CHILDREN FOR OTHER mat-step omitted for clarity
bookData: BookData = {}
ngAfterViewInit(): void {
this.getBookData();
this.book.changes.subscribe((algemen: QueryList<BookFormComponent>) => {
book.first.initBookData(this.bookData);
});
}
// this method returns one book from the server and assigns it to "this.bookData"
getBookData() {
bookdataService.getBookData().subscribe(book => {
this.bookData = book;
});
}
}
// PARENT COMPONENT UI
<mat-horizontal-stepper #stepper linear>
<mat-step [stepControl]="book.bookForm">
<ng-template matStepLabel>Book</ng-template>
<book-form #book></book-form>
</mat-step>
<mat-step>
// ADDITIONAL STEPS ARE OMITTED FOR CLARITY
</mat-step>
</mat-horizontbal-stepper>
// CHILD COMPONENT CLASS
Component({
selector: 'book-form'
})
class BookFormComponent {
bookForm: FormGroup;
name = new FormControl('');
color = new FormControl('');
// Checkboxes for types of books a user can select. user can select multiple checkboxes
types = new FormArray([]);
optionsTypes = [];
ngOnInit(): void {
this.bookForm = this.fb.group({
name: this.name,
color: this.color
});
this.initializeTypesCheckboxes();
}
// This function will create 10 checkboxes that a user can select multiple of them
private initializeTypesCheckboxes() {
this.bookservice.getTypeOptions().subscribe(results => {
// the results from the server is array of strings of 10 elements
// eg: ["Maths", "English", "Chemistry", ...]
this.optionsTypes = results;
// we create checkboxes based on the number of types we get from the server
const typeCheckboxes = this.optionsTypes.map(t => new FormControl(false));
// we push the the checkboxes to the "this.types" form array
typeCheckboxes.forEach(type => this.types.push(type));
});
}
// This method is called from the parent component
public initBookData(bookData: BookData) {
this.naam.setValue(bookData.naam);
this.color.setValue(bookData.color);
this.initSelectedTypes(this.types, this.optionsTypes, bookData.selectedTypes);
}
// this method will use the already "alreadySelectedTypes" array to pre-select some of the checkboxes.
private initSelectedTypes(formArray: FormArray, optionsTypes: Array<string>, alreadySelectedTypes: Array<string>) {
for (let i = 0; i < formArray.controls.length; i++) {
for (const type of alreadySelectedTypes) {
if (optionsTypes === type) {
formArray.controls[i].patchValue(true);
}
}
}
console.log("LENGTH-formArray:", formArray.length); // i get O
console.log("LENGTH-optionsTypes:", optionsTypes.length); // i get O
}
}
Что я делаю не так?