Hope you can help me in the following question.
I have an dynamically set up form in Angular, with the option to add and remove fields from a nested array.
Now the next step is to pre-populate the array in case somebody wants to edit the list.
This all works fine, I create the list in my component:
ngOnInit() {
this.isLoggedIn = !!this.tokenStorageService.getToken();
if (this.isLoggedIn) {
const user = this.tokenStorageService.getUser();
this.roles = user.roles;
this.username = user.username;
}
// --------------------- LIST CREATION ------------------------ //
this.newList = this.fb.group({
listTitle: '',
id: '',
chapters: '',
sublist: this.fb.array([])
})
this.addSublist()
this.addItem(0)
this.addItem(0)
this.addItem(0)
this.prefillList();
}
I have some functions to create/remove the sublist and the items below:
// --------------------- SUBLIST CREATION --------------------- //
get sublistArray() {
return this.newList.get('sublist') as FormArray
}
addSublist() {
const sublistGroup = this.fb.group({
subListCreator: this.username,
item: this.fb.array([])
})
this.sublistArray.push(sublistGroup);
}
deleteSublist(i) {
this.sublistArray.removeAt(i);
}
// ---------------------- ITEM CREATION ------------------------ //
getItemArray(index) {
return this.sublistArray.get([index, 'item']) as FormArray;
}
addItem(index: number) {
const itemGroup = this.fb.group({
itemTitle: [],
itemContext: []
})
this.getItemArray(index).push(itemGroup);
}
deleteItem(userIndex: number, colorIndex: number) {
this.getItemArray(userIndex).removeAt(colorIndex)
}
And then finally I retrieve my complete document from the database to prefill the form:
prefillList(): void {
const listId = this.route.snapshot.paramMap.get('listId');
this.listService.getListNo404(listId)
.subscribe(list=> {
this.list = list;
console.log(this.list);
this.newList.patchValue({
listTitle: this.list.listTitle,
id: this.route.snapshot.paramMap.get('listId'),
sublist: this.list.sublist
});
}
);
}
However, and this is where my question comes into play. I get that I create my form by calling three times the
this.addItem(0)
Function
And now my form is fixed on three items always as a starting point. If my list would be 7 items long to start with, I now lose 4 items on the way.
Can you help me in creating the right (I assume) for-loop to push the array in a way that actually is sustainable ?
In case useful, hereby the complete component and template as well.
Complete component:
import { Component, Input } from '@angular/core';
import { FormArray, FormBuilder, FormGroup } from "@angular/forms";
import { ListService } from '../list.service';
import { TokenStorageService } from '../token-storage.service';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Component({
selector: 'app-main',
templateUrl: './main.component.html',
styleUrls: ['./main.component.css']
})
export class MainComponent {
@Input() list
newList: FormGroup;
private roles: string[] = [];
isLoggedIn = false;
username?: string;
constructor(
private tokenStorageService: TokenStorageService,
private fb: FormBuilder,
private listService: ListService,
private route: ActivatedRoute
) { }
ngOnInit() {
this.isLoggedIn = !!this.tokenStorageService.getToken();
if (this.isLoggedIn) {
const user = this.tokenStorageService.getUser();
this.roles = user.roles;
this.username = user.username;
}
// --------------------- LIST CREATION ------------------------ //
this.newList = this.fb.group({
listTitle: '',
id: '',
chapters: '',
sublist: this.fb.array([])
})
this.addSublist()
this.addItem(0)
this.addItem(0)
this.addItem(0)
this.prefillList();
}
// --------------------- SUBLIST CREATION --------------------- //
get sublistArray() {
return this.newList.get('sublist') as FormArray
}
addSublist() {
const sublistGroup = this.fb.group({
subListCreator: this.username,
item: this.fb.array([])
})
this.sublistArray.push(sublistGroup);
}
deleteSublist(i) {
this.sublistArray.removeAt(i);
}
// ---------------------- ITEM CREATION ------------------------ //
getItemArray(index) {
return this.sublistArray.get([index, 'item']) as FormArray;
}
addItem(index: number) {
const itemGroup = this.fb.group({
itemTitle: [],
itemContext: []
})
this.getItemArray(index).push(itemGroup);
}
deleteItem(userIndex: number, colorIndex: number) {
this.getItemArray(userIndex).removeAt(colorIndex)
}
// -------------- GET LIST TITLE FROM URL ------------------ //
prefillList(): void {
const listId = this.route.snapshot.paramMap.get('listId');
this.listService.getListNo404(listId)
.subscribe(list=> {
this.list = list;
console.log(this.list);
this.newList.patchValue({
listTitle: this.list.listTitle,
id: this.route.snapshot.paramMap.get('listId'),
sublist: this.list.sublist
});
}
);
}
// ---------------------- SUBMISSION! ------------------------ //
onSubmit() {
this.listService.dropList(this.newList.value)
.subscribe(list => this.list.push(list));
console.log(this.newList.value);
}
}
Complete template:
<form [formGroup]="newList" (ngSubmit)="onSubmit()">
<!-- LIST -->
<div><br></div>
<span class="row d-flex align-items-baseline p-0">
<span class="bd-highlight badge badge-dark mr-1 ">LIST</span>
<div class="col d-flex p-2">
<input class="form-control form-control-lg" placeholder="title" type="text" formControlName="listTitle" readonly>
</div>
</span>
<!-- SUBLIST -->
<div formArrayName="sublist">
<div *ngFor="let user of sublistArray.controls; let i=index" [formGroupName]="i">
<!-- ITEM -->
<div formArrayName="item">
<div *ngFor="let item of getItemArray(i).controls; let t=index" [formGroupName]="t">
<span class="row">
<div class="p-2 bd-highlight">
<span class="badge badge-dark p-1 m-1">P{{t+1}}</span>
</div>
<input class="flex-grow-1 bd-highlightform-control" placeholder="{{t+1 }} item" type="text"
formControlName="itemTitle">
<div class="p-2 bd-highlight self-align-center"><button type='button' class="btn btn-light btn-sm"
(click)="deleteItem(i, t)">x</button></div>
</span>
<div class="collapse" id="comments">
<input class=" col d-flex p-2 form-control form-control-sm" placeholder="comment" type="text"
formControlName="itemContext"><br>
</div>
</div>
</div>
<!-- ITEM END -->
<div class="d-flex flex-row bd-highlight mb-2">
<div class="d-flex p-2 ml-4"><button type="button" class="btn btn-light btn-sm" (click)="addItem(i)">add
item</button></div>
<div class="d-flex p-2 "> <button class="btn btn-light btn-sm" type="button" data-toggle="collapse"
data-target="#comments">
show / hide comments </button></div>
<div class="d-flex p-2 ">
<button class="btn btn-light btn-sm collapse show" id="chapters" type="button" data-toggle="collapse"
data-target="#chapters">add chapter</button>
</div>
</div>
</div>
</div>
<span *ngIf=newList class="row d-flex align-items-baseline p-0 collapse" id="chapters">
<span class="bd-highlight badge badge-light mr-1 collapse" id="chapters">CHAPTER</span>
<div class="col d-flex p-2 collapse" id="chapters">
<input class="form-control form-control-sm collapse" id="chapters" placeholder="chapter" type="text"
formControlName="chapters">
</div>
<button class="btn btn-light btn-sm collapse" id="chapters" type="button" data-toggle="collapse"
data-target="#chapters">hide chapter</button>
</span>
<div class="d-flex p-2 ml-4"> <button type="submit" class="btn btn-dark btn-primary">DROP</button></div>
<br><br>
<pre>{{ newList.value | json }}</pre>