From Builder using Angular 2 and Bootstrap
Published on November 15, 2016
Hola, We use forms everywhere. 90% of web applications uses forms. In today’s post, we will build an Angular 2 component which takes input as a JSON
object and generate Twitter Bootstrap form based on it.
Our goal is to generate a bootstrap form based on JSON
we pass.
Let’s suppose if we have a JSON as below.
[
{
name: 'email',
label: 'Email',
},
{
name: 'first_name',
label: 'First Name',
multi: true,
},
{
type: 'radio',
name: 'radio',
label: 'Radio',
opts: [
{ label: 'Option 1', value: 'opt_1' },
{ label: 'Option 2', value: 'opt_2' },
],
},
{
type: 'check',
name: 'opt',
opts: [
{ name: 'opt_1', label: 'Option 1' },
{ name: 'opt_2', label: 'Option 2' },
],
},
{
type: 'select',
name: 'select_1',
label: 'Select',
opts: [
{ label: 'Option 1', value: 'opt_1' },
{ label: 'Option 2', value: 'opt_2' },
],
},
];
It should generate a bootstrap form for us.
Ok, Step 1 is we need to create bootstrap form controls. We will build only basic form controls like input,textarea,radio button, checkbox and select in this example.
input
import { Component, Input } from '@angular/core';
// text,email,tel,textarea,password,
@Component({
selector: 'text-box',
template: `
<div class="form-group">
<label>{{ prop.label }}</label>
<input
*ngIf="!prop.multi"
type="{{ prop.type }}"
class="form-control"
[id]="prop.name"
[name]="prop.name"
[(ngModel)]="model[prop.name]"
/>
<textarea
*ngIf="prop.multi"
class="form-control"
rows="5"
[id]="prop.name"
[name]="prop.name"
[(ngModel)]="model[prop.name]"
></textarea>
</div>
`,
})
export class TextBoxComponent {
@Input() prop: any = {};
@Input() model: any;
constructor() {}
}
Here, we have both input
,textarea
controls in it. If we pass multi:true
in our JSON object it will show text area otherwise it will show a text input.
For text input, we also passing type. So we can generate all text input type like email,tel,color,so on..
In the TextBoxComponent
class it take prop
and model
as inputs. prop
is for JSON object. model
is for input model. The user entered value will be stored on this.
All remaining components have pretty much same structure.
Radio button
import { Component, Input } from '@angular/core';
// Radio buttons
@Component({
selector: 'radio-button',
template: `
<div class="form-group">
<label>{{ prop.label }}</label>
<div class="radio" *ngFor="let opt of prop.opts">
<label
><input
type="radio"
[(ngModel)]="model[prop.name]"
[name]="prop.name"
[value]="opt.value"
/>{{ opt.label }}</label
>
</div>
</div>
`,
})
export class RadioButtonComponent {
@Input() prop: any = {};
@Input() model: any;
constructor() {}
}
Select
import { Component, Input } from '@angular/core';
// Select control
@Component({
selector: 'select-box',
template: `
<div class="form-group">
<label for="sel1">{{ prop.label }}</label>
<select class="form-control" [(ngModel)]="model[prop.name]" [name]="prop.name">
<option *ngFor="let opt of prop.opts" [value]="opt.value">{{ opt.label }}</option>
</select>
</div>
`,
})
export class SelectBoxComponent {
@Input() prop: any = {};
@Input() model: any;
constructor() {}
}
Checkbox
import { Component, Input } from '@angular/core';
// checkbox control
@Component({
selector: 'check-box',
template: `
<div class="form-group">
<label>{{ prop.label }}</label>
<div class="checkbox" *ngFor="let opt of prop.opts">
<label><input type="checkbox" [(ngModel)]="model[opt.name]" />{{ opt.label }}</label>
</div>
</div>
`,
})
export class CheckBoxComponent {
@Input() prop: any = {};
@Input() model: any;
constructor() {}
}
Ok, We are done with all low-level component creation. Now, let’s create ControlBuilderComponent
and FormBuilderComponent
.
FormBuilderComponent
import { Component, Input } from '@angular/core';
@Component({
selector: 'form-builder',
template: `
<form>
<control-builder
*ngFor="let prop of formJson"
[prop]="prop"
[model]="model"
></control-builder>
<button type="submit" class="btn btn-default">Submit</button>
</form>
`,
})
export class FormBuilderComponent {
@Input() formJson: any = {};
@Input() model: any;
constructor() {}
}
Form Builder is TopLevel component take inputs formJson
and model
. It’s basically a wrapper with <form>
tag.
formJson
is the JSON format of the form and model
is the data model that we have been using in all our controllers.
In this FormBuilderComponent
we are calling our ControlBuilderComponent
which will generate components for form.
ControlBuilderComponent
import { Component, Input } from '@angular/core';
@Component({
selector: 'control-builder',
template: `
<div [ngSwitch]="prop.type">
<check-box *ngSwitchCase="'check'" [prop]="prop" [model]="model"></check-box>
<radio-button *ngSwitchCase="'radio'" [prop]="prop" [model]="model"></radio-button>
<select-box *ngSwitchCase="'select'" [prop]="prop" [model]="model"></select-box>
<text-box *ngSwitchDefault [prop]="prop" [model]="model"></text-box>
</div>
`,
})
export class ControlBuilderComponent {
@Input() prop: any = {};
@Input() model: any;
constructor() {}
}
Based on type
it will choose our low-level components that we created earlier.
Now, let’s call our form builder from AppComponent
.
import { Component, Input } from '@angular/core';
@Component({
selector: 'my-app',
template: `
{{ model | json }}
<div class="container">
<h1>Form Builder</h1>
<form>
<form-builder [formJson]="ctrls" [model]="model"></form-builder>
</form>
</div>
`,
})
export class AppComponent {
public model: any = {};
public fname: string;
public ctrls: any = [
{
name: 'email',
label: 'Email',
},
{
name: 'first_name',
label: 'First Name',
multi: true,
},
{
type: 'radio',
name: 'radio',
label: 'Radio',
opts: [
{ label: 'Option 1', value: 'opt_1' },
{ label: 'Option 2', value: 'opt_2' },
],
},
{
type: 'check',
name: 'opt',
opts: [
{ name: 'opt_1', label: 'Option 1' },
{ name: 'opt_2', label: 'Option 2' },
],
},
{
type: 'select',
name: 'select_1',
label: 'Select',
opts: [
{ label: 'Option 1', value: 'opt_1' },
{ label: 'Option 2', value: 'opt_2' },
],
},
];
consturctor() {}
}
Try the demo or view the source code here