I am working on a CMS with Angular 6, I have a form to create a page with two languages or more depending on supported locales from the settings. Firstly I am getting the supported locales from api and let's say the response has 2 locales (en - fr). So for each language I want to build a tab inside the form with its own locale like en['title'], en['body'], fr['title'], fr['body']. I tried to build the form like this:
let forms = [];
for(let lang of this.supportedLocales) {
forms.push(this.fb.group({
title: ['', [Validators.required]],
body: ['', [Validators.required]]
}))
}
this.form = this.fb.group({
template: ['default', [Validators.required]],
is_home: [0],
translatable: this.fb.array(forms)
});
}
And in HTML:
<div class="tab-content">
<div *ngFor="let lang of supportedLocales"
class="tab-pane {{lang.locale === currentLang ? 'active' : ''}}"
id="{{ 'tab_'+ lang.locale}}">
<div class="form-group">
<label [attr.for]="'title'+lang.locale">{{ translateField('page::pages.title') }}</label>
<input formControlName="?" [attr.id]="'title'+lang.locale" class="form-control">
</div>
</div>
</div>
How to define the formControlName for title field ? I have tried to use FormArray but it causes a problem and the browser not responding!
What should I do or what is the best approach for this case?
I'll just use .map
on this.supportedLocales
and then generate FormGroup
s using the getFormGroupForLocale
method. It's private
as it won't be used in your Template.
Now once the form is ready, first I'll bind the whole form to a form
tag using [formGroup]="form"
. After that, since my form has a FormArray
, I'll first have to create a wrapping div
for it. To this div
I'll assign formArrayName="translatable"
which will map this div to my translatable
FormArray
in the form
FormGroup
.
Inside this, I'll use *ngFor="let group of localeFormArray; let i = index;"
to loop through all the FormGroup
s in my FormArray
and bind them to a wrapping div
using <div [formGroupName]="i">
. Notice how I'm using formGroupName
as property binding syntax and assigning it the index i
of the FormGroup
in my FormArray
Finally inside each input
tag of this div
, I can then use formControlName="title"
and formControlName="body"
to bind to the FormControl
s in each FormGroup
s in the FormArray
.
Here's how:
<form [formGroup]="form">
template
is_home
translatable
<label for="template">Template</label>
<input type="text" id="template" formControlName="template">
<br><br>
<label for="is_home">Is Home</label>
<input type="text" formControlName="is_home" id="is_home">
<br><br>
<h1>translatable</h1>
<div formArrayName="translatable">
<div *ngFor="let group of localeFormArray; let i = index;">
<div [formGroupName]="i">
<label
[for]="'title'+supportedLocales[i].lang.locale">
{{ translateField('page::pages.title') }}
</label>
<input
formControlName="title"
[id]="'title'+supportedLocales[i].lang.locale"
class="form-control">
<br><br>
<label
[for]="'title'+supportedLocales[i].lang.locale">
{{ translateField('page::pages.title') }}
</label>
<input
formControlName="body"
[id]="'title'+supportedLocales[i].lang.locale"
class="form-control">
</div>
</div>
</div>
</form>
And for the Component Class:
import { Component } from '@angular/core';
import { FormGroup, FormControl, FormBuilder, Validators, FormArray } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
form: FormGroup;
supportedLocales = [
{ lang: { locale: 'en-US' } },
{ lang: { locale: 'en-FR' } },
];
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.form = this.fb.group({
template: ['default', [Validators.required]],
is_home: [0],
translatable: this.fb.array(this.supportedLocales.map(locale => this.getFormGroupForLocale(locale)))
});
}
private getFormGroupForLocale(language) {
return this.fb.group({
title: [language.lang.locale + 'Title', [Validators.required]],
body: [language.lang.locale+'Body', [Validators.required]]
});
}
...
get localeFormArray() {
return (<FormArray>this.form.get('translatable')).controls;
}
}
Here's a Sample StackBlitz for your ref.