In angular 5 I have made the functionality for add new row and remove row by using formarray. Its working fine for now. But lets say I have some data and I want to show them in the rows one by one so lets say I have data for 3 rows so the form should automatically show 3 rows by default with all the values populated in it with add and remove row functionality.
This is the code what I have done so far
appponent.html
looks like this
<div class="container col-md-12">
<h1 class="page-header">Create Event</h1>
<div class="row show-hide-message">
<div [ngClass]= "messageClass">{{message}}</div>
</div>
<form [formGroup] = "form" (ngSubmit)="onEventSubmit()">
<fieldset>
<div class="form-group">
<label for="eventname">Event Name</label>
<div class='form-group' [ngClass]="{'has-error': form.controls.eventname.errors && form.controls.eventname.dirty,
'has-success': !form.controls.eventname.errors
}">
<input type="text" class="form-control" autoplete="off" placeholder="Event Name" formControlName="eventname">
<ul class="help-block">
<li *ngIf="(form.controls.eventname.errors?.minlength ) && form.controls.eventname.dirty">Event name should be atleast 5 characters</li>
</ul>
</div>
</div>
<h4>Package Price</h4>
<hr>
<div class="row" formArrayName="sections">
<div class="col-md-12" *ngFor="let section of getSections(form); let i = index" [formGroupName]="i">
<div class="form-group col-md-5">
<label for="packagename">Package Name</label>
<input type="text" class="form-control" autoplete="off" placeholder="Package Name" formControlName="packagename" >
</div>
<div class="form-group col-md-2">
<label for="packageprice">Package Price</label>
<input type="number" class="form-control" autoplete="off" placeholder="Package Price" formControlName="packageprice" >
</div>
<div class="form-group col-md-2">
<label for="packagelimit">Max Purchase Limit</label>
<input type="number" class="form-control" formControlName="packagelimit" autoplete="off" >
</div>
<div class="form-group col-md-1">
<br/>
<input type="button" (click)="addPackageRow()" class="btn btn-md btn-success" value="+" name="">
</div>
<div class="form-group col-md-1" *ngIf="getSections(form).length > 1">
<br/>
<input type="button" (click)="removeSection(i)" class="btn btn-md btn-error" value="-" name="">
</div>
</div>
</div>
<input [disabled]=!form.valid type="submit" class="btn btn-primary" value="Submit">
<pre>{{form.value | json}}</pre>
</fieldset>
</form>
</div>
appponent.ts
looks like this
import { Component, OnInit } from '@angular/core';
import { FormArray, FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './appponent.html',
styleUrls: ['./appponent.css']
})
export class AppComponent implements OnInit {
form : FormGroup;
packagesArray: FormArray;
storageData = [
{"packagename":"Package One","packageprice":12,"packagelimit":9},
{"packagename":"Package Two","packageprice":78,"packagelimit":5},
{"packagename":"Package Three","packageprice":89,"packagelimit":7}
];
constructor(
private formBuilder : FormBuilder,
) { this.createEventForm() }
createEventForm() {
this.form = this.formBuilder.group({
eventname: ['', Validatorspose([
Validators.required,
Validators.minLength(5)
])],
packages: this.packagesArray
})
}
ngOnInit() {
this.form = new FormGroup({
eventname: new FormControl(''),
sections: new FormArray([
this.initSection(),
]),
});
}
initSection() {
return new FormGroup({
packagename: new FormControl(''),
packageprice: new FormControl(''),
packagelimit: new FormControl('')
});
}
initItemRows() {
return this.formBuilder.group({
itemname: ['']
});
}
onEventSubmit() {}
public addPackageRow() {
const control = <FormArray>this.form.get('sections');
control.push(this.initSection());
}
addSection() {
const control = <FormArray>this.form.get('sections');
control.push(this.initSection());
}
getSections(form) {
return form.controls.sections.controls;
}
public removeSection(i){
const control = <FormArray>this.form.get('sections');
control.removeAt(i);
}
}
So can someone tell me how to do this? Any help and suggestion will be really appreciable. Thanks
I just want to populate data of storageData with the respective rows.
Here is the working demo
In angular 5 I have made the functionality for add new row and remove row by using formarray. Its working fine for now. But lets say I have some data and I want to show them in the rows one by one so lets say I have data for 3 rows so the form should automatically show 3 rows by default with all the values populated in it with add and remove row functionality.
This is the code what I have done so far
app.ponent.html
looks like this
<div class="container col-md-12">
<h1 class="page-header">Create Event</h1>
<div class="row show-hide-message">
<div [ngClass]= "messageClass">{{message}}</div>
</div>
<form [formGroup] = "form" (ngSubmit)="onEventSubmit()">
<fieldset>
<div class="form-group">
<label for="eventname">Event Name</label>
<div class='form-group' [ngClass]="{'has-error': form.controls.eventname.errors && form.controls.eventname.dirty,
'has-success': !form.controls.eventname.errors
}">
<input type="text" class="form-control" autoplete="off" placeholder="Event Name" formControlName="eventname">
<ul class="help-block">
<li *ngIf="(form.controls.eventname.errors?.minlength ) && form.controls.eventname.dirty">Event name should be atleast 5 characters</li>
</ul>
</div>
</div>
<h4>Package Price</h4>
<hr>
<div class="row" formArrayName="sections">
<div class="col-md-12" *ngFor="let section of getSections(form); let i = index" [formGroupName]="i">
<div class="form-group col-md-5">
<label for="packagename">Package Name</label>
<input type="text" class="form-control" autoplete="off" placeholder="Package Name" formControlName="packagename" >
</div>
<div class="form-group col-md-2">
<label for="packageprice">Package Price</label>
<input type="number" class="form-control" autoplete="off" placeholder="Package Price" formControlName="packageprice" >
</div>
<div class="form-group col-md-2">
<label for="packagelimit">Max Purchase Limit</label>
<input type="number" class="form-control" formControlName="packagelimit" autoplete="off" >
</div>
<div class="form-group col-md-1">
<br/>
<input type="button" (click)="addPackageRow()" class="btn btn-md btn-success" value="+" name="">
</div>
<div class="form-group col-md-1" *ngIf="getSections(form).length > 1">
<br/>
<input type="button" (click)="removeSection(i)" class="btn btn-md btn-error" value="-" name="">
</div>
</div>
</div>
<input [disabled]=!form.valid type="submit" class="btn btn-primary" value="Submit">
<pre>{{form.value | json}}</pre>
</fieldset>
</form>
</div>
app.ponent.ts
looks like this
import { Component, OnInit } from '@angular/core';
import { FormArray, FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.ponent.html',
styleUrls: ['./app.ponent.css']
})
export class AppComponent implements OnInit {
form : FormGroup;
packagesArray: FormArray;
storageData = [
{"packagename":"Package One","packageprice":12,"packagelimit":9},
{"packagename":"Package Two","packageprice":78,"packagelimit":5},
{"packagename":"Package Three","packageprice":89,"packagelimit":7}
];
constructor(
private formBuilder : FormBuilder,
) { this.createEventForm() }
createEventForm() {
this.form = this.formBuilder.group({
eventname: ['', Validators.pose([
Validators.required,
Validators.minLength(5)
])],
packages: this.packagesArray
})
}
ngOnInit() {
this.form = new FormGroup({
eventname: new FormControl(''),
sections: new FormArray([
this.initSection(),
]),
});
}
initSection() {
return new FormGroup({
packagename: new FormControl(''),
packageprice: new FormControl(''),
packagelimit: new FormControl('')
});
}
initItemRows() {
return this.formBuilder.group({
itemname: ['']
});
}
onEventSubmit() {}
public addPackageRow() {
const control = <FormArray>this.form.get('sections');
control.push(this.initSection());
}
addSection() {
const control = <FormArray>this.form.get('sections');
control.push(this.initSection());
}
getSections(form) {
return form.controls.sections.controls;
}
public removeSection(i){
const control = <FormArray>this.form.get('sections');
control.removeAt(i);
}
}
So can someone tell me how to do this? Any help and suggestion will be really appreciable. Thanks
I just want to populate data of storageData with the respective rows.
Here is the working demo
https://stackblitz./edit/angular-mh3dpy
Share Improve this question edited Feb 14, 2018 at 8:21 Aref Zamani 2,0622 gold badges22 silver badges41 bronze badges asked Feb 14, 2018 at 7:04 NewUserNewUser 13.3k40 gold badges150 silver badges240 bronze badges 5- Don't you want to say "data" in your title ? – Gilsdav Commented Feb 14, 2018 at 7:09
- If I understand, you want an animation on your ngFor to show rows one by one (for the 3 first elements but if you add multiple rows at once too) ? – Gilsdav Commented Feb 14, 2018 at 7:11
- actually I want to populate the stored values in the formarray with add row and remove row functionality. It does not matter there will be 3 rows in the data there might be any number of data. – NewUser Commented Feb 14, 2018 at 7:15
- I have changed the title. Thanks for pointing typo error. – NewUser Commented Feb 14, 2018 at 7:16
- If you want to add a control : Use addControl function of your formGroup because controls attribute is readonly – Gilsdav Commented Feb 14, 2018 at 7:22
3 Answers
Reset to default 2I would go with:
this.form = new FormGroup({
eventname: new FormControl(''),
sections: new FormArray(this.storageData.map(item => {
const group = this.initSection();
group.patchValue(item);
return group;
}))
});
Ng-run Example
Change your ngOnInit :-
ngOnInit() {
this.form = new FormGroup({
eventname: new FormControl(''),
sections: new FormArray([
this.initSection(),
]),
});
var data;
for(data in this.storageData){
console.log(this.storageData[data]);
var temp = {};
for(var k in this.storageData[data]){
//console.log(k);
temp[k] = new FormControl(this.storageData[data][k]);
}
console.log(temp);
var formGrp = new FormGroup(temp);
const control = <FormArray>this.form.get('sections');
control.push(formGrp);
}
}
puff, I suggested make a functión that return the formArray
//this.fb is in the constructor private fb:FormBuilder
getSeccion(storageData: any[]): FormArray {
//create an arr of FormGroup
//each element of array storageData transform in a FormGroup
const arr = storageData.map(data => {
return this.fb.group({
packagename: [data.packagename,Validators.Required], //<--e.g. if Required
packageprice: [data.packageprice],
packagelimit: [data.packagelimit]});
})
//return a FormGroup with this array
return this.fb.array(arr);
}
So, your ngOnInit
ngOnInit() {
this.form = new FormGroup({
eventname: new FormControl(''),
sections: this.getSeccion(this.storageData )
});
MoreOver, if you has an object
mydata={eventname:'myEvent',
sections:[{packagename:'name1',packageprice:'100',packagelimit:30},
{..},
{..}..]
You can use
this.form = new FormGroup({
eventname: new FormControl(this.myData.eventname),
sections: this.getSeccion(this.myData.storageData )
});
Well, normally we get data from database. So our ngOnInit can be some like
ngOnInit()
{
myservice.getData().subscribe((res:any)=>{
this.data=res //normally we can save the data in a variable
this.form = new FormGroup({
eventname: new FormControl(res.eventname),
sections: this.getSeccion(res.storageData )
});
})
}