Reputation: 1895
I am building an app Using Angular 5 and I am trying to build a dynamic form. This form, which is like a bet slip or shopping cart, is a array of objects which comes from a service as an observable. I am having difficulty figuring out how to add an input field and bind it to a property in each bet object.
The observable betSlipItems array looks like this:
[
{
"Id": 1,
"betslipTeamName": "La Rochelle",
"stake": null
},
{
"Id": 2,
"betslipTeamName": "North Queensland Cowboys",
"stake": null
}
]
And what I want to do is create an input field and bind it to the 'stake' property of each bet object.
This is my code for bet-slip.component.ts so far:
import { FormBuilder, FormGroup, FormArray } from '@angular/forms';
import { Component, OnInit, Input } from '@angular/core';
import { Bets } from '../../../shared/models';
import { BetService } from '../../../shared/services/bet.service';
import { Observable } from 'rxjs';
import { of } from 'rxjs/observable/of';
@Component({
selector: 'bet-slip',
templateUrl: './bet-slip.component.html',
styleUrls: ['./bet-slip.component.scss']
})
export class BetSlipComponent implements OnInit {
public betSlipItems$: Observable<Bets[]> = of([]);
public betSlipItems: Bets[] = [];
public betsForm: FormGroup;
constructor( private betService: BetService, private _fb: FormBuilder) {
this.betSlipItems$ = this.betService.getBets();
}
ngOnInit() {
this.betsForm = new FormGroup({
stake: new FormControl()
});
this.betSlipItems$.subscribe((betSlipItems) => {
this.betSlipItems = betSlipItems;
});
}
}
and my component bet-slip.component.html looks like this:
<form [formGroup]="betsForm">
<div *ngFor="let bet of betSlipItems; let i=index">
{{bet.betslipTeamName }}
<input type="text" formControlName="stake">
</div>
</form>
I know this is incorrect. How can I fix this?
Upvotes: 2
Views: 3175
Reputation: 57961
The problem is that you must know what need and what expect. I suppose you want to make a form Array with "Id","betslipTeamName" and "stake" (as minimum you need Id and stake) not only stake. To work with a ReactiveForm with an array it's easy. In general we have a service that return our data. I put a full example, I expect this help you
//simple service that read a json (you have one yet -it's only to complete my example-)
@Injectable()
export class AppDataService {
constructor(private httpClient:HttpClient) { }
read(key:any)
{
return this.httpClient.get('../assets/data.json')
}
}
Our component have a .html like this
<div *ngIf="yet">
<!--I put a *ngIf to avoid an error at first-->
<form [formGroup]="dataForm" (ngSubmit)="submit(dataForm)" novalidate>
<!--see that the "formArrayName" is "lista"
don't confuse with the *ngFor of "lista" (the lista in ngFor is a getter)
-->
<div formArrayName="lista" *ngFor="let lista of lista.controls;let i=index">
<div [formGroupName]="i"> <!--it's necesary a formGroupName=i-->
<!--we can use labels here -->
{{labels[i].Id}}{{labels[i].Text}}
<!--the input we need , some can be readOnly -->
<input type="text" class="form-control" formControlName="Id">
<input type="text" class="form-control" formControlName="betslipTeamName">
<input type="text" class="form-control" formControlName="stake">
</div>
<hr>
</div>
</form>
<!---this it's only to check the value of the form-->
{{dataForm?.value |json}}
</div>
The component.ts it's like
@Component({
selector: 'app-app-form',
templateUrl: './app-form.component.html',
styleUrls: ['./app-form.component.css']
})
export class AppFormComponent implements OnInit {
dataForm: null | undefined | FormGroup; //we have a dataForm
data: any; //normally we have a data too. It's not necesary that the data was identical to dataFrom
labels:any[] //we create an array [{Id,Text}]
yet:boolean=false; //I use this variable when all it's ready
get lista() { //<--This is the gettet that we use in the *ngFor
return (this.dataForm) ? this.dataForm.get('lista') : null;
};
constructor(private fb: FormBuilder, private dataService: AppDataService) { }
ngOnInit() {
let key: any;
this.dataService.read(key).subscribe(
(response:any[]) => {
if (response) {
this.data = response; //this.data is an array[{"Id": 1,..}.{"Id":2..}]
//You can create a label array with Id,Text
this.labels=response.map((item:any)=>{return {Id:item.Id,Text:item.betslipTeamName}})
this.dataForm = this.createFormGroup(this.data);// dataForms is an object {lista:[{..},{..}]}
this.yet=true;
}
});
}
submit(dataForm:any)
{
if (dataForm.valid)
{
console.log(dataForm.value);
}
}
createFormGroup(data: any) {
let lista = this.buildArray(data); //create an array of Controls
let dataForm = this.fb.group({
lista: lista
});
//see that dataForms is an object {lista:[{..},{..}]}
return dataForm;
}
buildArray(myArray: any[]) {
//witch each data, we create a fbGroup
const arr = myArray.map(data => {
return this.fb.group({
"Id": [data.Id], //we can omit some control
"betslipTeamName": [data.betslipTeamName],
"stake": [data.stake],
});
});
//And return a array of fbGroup
return this.fb.array(arr);
}
}
Upvotes: 1