I am making an application using angular 6, where i am using angular dynamic form.
As of creating the form and submitting i have completed everything, You could able to see the working stackblitz, https://stackblitz.com/edit/angular-x4a5b6-hne6fg
FYI: This form has children elemts which will gets opened and also gets append on click the add button and removes one by last on click the remove button..
The thing i am in the need is, i just need to patch the values to each inputs via service during edit of each row respectively..
Say i call the get service as,
this.dynamicFormService.getRest(url,token).subscribe(res => {
this.form.value = res.data; //Tried this line but got error (Cannot assign to 'value' because it is a constant or a read-only property)
})
I am trying to patch the values to the form which you can see in dynamic-form.ts in stacblitz,
ngOnInit() {
this.form = this.qcs.toFormGroup(this.questions);
}
If i console the the form as console.log(this.form.value)
, it gives the result as,
template_desc: ""
template_name: ""
template_properties: Array(0)
length: 0
__proto__: Array(0)
And console.log(res.data)
in get service result gives,
data:
template_obj_id: "123"
template_desc: "New template description"
template_name: "New Template"
template_properties: Array(1)
0:
property_name: "Property name"
property_origin: ["VBM"]
property_required: true
property_type: "Property type"
I just need to bind this data that comes from res.data to get patched to all the form inputs.
These are the values i need to patch to all the inputs respectively like template_name
has the value as New Template and template_desc
as New template description
etc..
And also an another important thing for template_properties
value which is array will get open on click add button during create but whereas during edit it should get opened automatically with number of rows present inside template_properties
..
Though the question went little bigger for explanation, the thing i am in the need is single.. I need to patch the data comes from service (res.data) to each form elements respectively and all the form elements including template_properties
needs to be visible in which user can edit and submit the form.
The screenshot of res.data,
Tried with the below answer,
this.form.patchValue({
template_desc: res.data.template_desc,
template_name: res.data.template_name,
});
But if i give template_properties: res.data.template_properties
, the template properties not getting binded but other two template name and desc
getting binded..
Kindly help to achieve the patching of data to the form elements...
in https://stackblitz.com/edit/angular-x4a5b6-xcychx?file=src%2Fapp%2Fdynamic-form.component.html, I put as "path the values".
The only thing to take account is that you need add to the form as element as has the array.
//This function serve to add to the array the elments of the arrays
//Is the same that we use when add a new line to the Array Form
addControls(control: string) {
let question: any = this.questions.find(q => q.key == control);
let children = question ? question.children : null;
if (children)
(this.form.get(control) as FormArray).push(this.qcs.toFormGroup(children))
}
this.dynamicFormService.getRest(url,token).subscribe(res => {
//In res.data you have the data.
//In res.dat.template_properties you has the array
//Create the Form
this.form = this.qcs.toFormGroup(this.questions);
//Add so element at array as was necesary
for (let i=0;i<this.data.myArray.length;i++)
{
this.addControls('template_properties')
}
//Finally use patchValue
this.form.patchValue(res.data);
}
Well, your data not corresponding with this.questions and there are a problem with your property_origin (about the problem with as convert propertyOrigin to a series of checkBox, let me some time -I'll updated this anwser more later-)
Updated
see stackblitz updated
Creating a new Question Type to create a list of checkBox
There're a problem with the checkBox. In Angular a checkBox can be have only two values "true" or "false". Until I know, there no effect the attrib value.
So, we can not make something like
<input type="checkbox" value="car" formControlName="checkName">
<input type="checkbox" value="dog" formControlName="checkName">
To get in "checkName" an array ['car','dog'] if you checked the two values.
How we can solutionated this? I think that the better idea is has a formGroup like
<div formGroupName="checkName">
<input type="checkBox" formControlName="car">
<input type="checkBox" formControlName="dog">
</div>
So, we'll get some like
checkName={car:true,dog:false}
Well one work is make a new QuestionType "ListCheckBoxQuestion"
export class ListCheckBoxQuestion extends QuestionBase<string> {
controlType = 'list-chekbox';
options: {key: string, value: string}[] = [];
constructor(options: {} = {}) {
super(options);
this.options = options['options'] || [];
}
}
After we can change the dinamic-formquestion.component adding a new switch. See that we create a formGroupName with the question.key, and inside this group we create a formControlName using "options"
<div [formGroupName]="question.key" *ngSwitchCase="'list-chekbox'" >
<ng-container *ngFor="let opt of question.options">
<input type="checkbox" [formControlName]="opt.key">
<label >{{opt.value}}</label>
</ng-container>
</div>
Well, the hard part is wen we create the form (the toFormGroup function of question-control-service
toFormGroup(questions: QuestionBase<any>[]) {
let group: any = {};
questions.forEach(question => {
if (question.controlType=="array") {
group[question.key]=new FormArray([]);
}else if (question.controlType=="list-chekbox")
{ //We create a FromGroup using the options
let controls:any={};
for (let option of question.options)
controls[option.key]=new FormControl(false);
group[question.key]=new FormGroup(controls);
console.log("*",question);
}
else {
...
}
});
return new FormGroup(group);
}
Well there're a job to to that is convert our form.value to data and the data received to form.value.
When we received some like ["car","dog"] we must transform to {car:true,dog:true} and when we have {car:true,dog:false} we must transform to ["car"]. We must use map
Update
Take a look to the function toFormGroup of question-control-service. This function is the function that create the form. In the last version we add so many lines to the array as values length. Change this funcion to add a linea if no value is indicated
questions.forEach(question => {
if (question.controlType == "array") {
group[question.key] = new FormArray([]);
if (question.value) {
if (question.children) {
//If question.children we must to give "value" to the children
//So the children has as value, the value given in dataArray
for (let value of question.value) {
Object.keys(value).forEach(key => {
let qu = question.children.find(x => x.key == key)
if (qu) {
qu.value = value[key];
qu.controlType = qu.elementType
}
})
group[question.key].push(this.toFormGroup(question.children))
}
}
} //Add this lines to add one line to the array if no
//value is indicated
else {
if (question.children) {
question.children.forEach(qu => {
qu.controlType = qu.elementType
})
group[question.key].push(this.toFormGroup(question.children))
}
}
Use patchValue
to set the data to form
this.dynamicFormService.getRest(url,token).subscribe(res => {
this.form.patchValue({
template_desc: res.data.template_desc,
template_name: res.data.template_name,
});
}