Dynamic Forms - Ts - COOKBOOK
Dynamic Forms - Ts - COOKBOOK
Forms ts COOKBOOK
DYNAMIC FORMS
We can't always justify the cost and time to build handcrafted forms, especially if
we'll need a great number of them, they're similar to each other, and they change
frequently to meet rapidly changing business and regulatory requirements.
It may be more economical to create the forms dynamically, based on metadata that
describe the business object model.
In our example we use a dynamic form to build an online application experience for
heroes seeking employment. The agency is constantly tinkering with the application
process. We can create the forms on the ��y without changing our application code.
Table of contents
Bootstrap
Question Model
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 1/11
11/20/2016 Dynamic Forms ts COOKBOOK
Form Component
Questionnaire Metadata
Dynamic Template
Bootstrap
We start by creating an NgModule called AppModule .
9. @NgModule({
10. imports: [ BrowserModule, ReactiveFormsModule ],
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 2/11
11/20/2016 Dynamic Forms ts COOKBOOK
Question Model
The next step is to de��ne an object model that can describe all scenarios needed by
the form functionality. The hero application process involves a form with a lot of
questions. The "question" is the most fundamental object in the model.
app/question-base.ts
9. constructor(options: {
10. value?: T,
11. key?: string,
12. label?: string,
13. required?: boolean,
14. order?: number,
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 3/11
11/20/2016 Dynamic Forms ts COOKBOOK
that the form will be bound to speci��c question types and render the appropriate
controls dynamically.
TextboxQuestion supports multiple html5 types like text, email, url etc via the
type property.
app/question-textbox.ts
constructor(options: {} = {}) {
super(options);
this.type = options['type'] || '';
}
}
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 4/11
11/20/2016 Dynamic Forms ts COOKBOOK
app/question-dropdown.ts
constructor(options: {} = {}) {
super(options);
this.options = options['options'] || [];
}
}
app/question-control.service.ts
@Injectable()
export class QuestionControlService {
constructor() { }
toFormGroup(questions: QuestionBase<any>[] ) {
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 5/11
11/20/2016 Dynamic Forms ts COOKBOOK
questions.forEach(question => {
group[question.key] = question.required ? new
FormControl(question.value || '', Validators.required)
: new
FormControl(question.value || '');
});
return new FormGroup(group);
}
}
DynamicFormComponent is the entry point and the main container for the form.
1. <div>
2. <form (ngSubmit)="onSubmit()" [formGroup]="form">
3.
8. <div class="form-row">
9. <button type="submit" [disabled]="!form.valid">Save</button>
10. </div>
11. </form>
12.
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 6/11
11/20/2016 Dynamic Forms ts COOKBOOK
1. <div [formGroup]="form">
2. <label [attr.for]="question.key">{{question.label}}</label>
3.
4. <div [ngSwitch]="question.controlType">
5.
6. <input *ngSwitchCase="'textbox'"
[formControlName]="question.key"
7. [id]="question.key" [type]="question.type">
8.
13. </div>
14.
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 7/11
11/20/2016 Dynamic Forms ts COOKBOOK
Notice this component can present any type of question in our model. We only have
two types of questions at this point but we can imagine many more. The ngSwitch
determines which type of question to display.
Questionnaire data
DynamicFormComponent expects the list of questions in the form of an array
The set of questions we have de��ned for the job application is returned from the
QuestionService . In a real app we'd retrieve these questions from storage.
The key point is that we control the hero job application questions entirely through
the objects returned from QuestionService . Questionnaire maintenance is a
simple matter of adding, updating, and removing objects from the questions
array.
app/question.service.ts
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 8/11
11/20/2016 Dynamic Forms ts COOKBOOK
7. @Injectable()
8. export class QuestionService {
9.
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 9/11
11/20/2016 Dynamic Forms ts COOKBOOK
45. }
46. }
app.component.ts
5. @Component({
6. selector: 'my-app',
7. template: `
8. <div>
9. <h2>Job Application for Heroes</h2>
10. <dynamic-form [questions]="questions"></dynamic-form>
11. </div>
12. `,
13. providers: [QuestionService]
14. })
15. export class AppComponent {
16. questions: any[];
17.
Dynamic Template
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 10/11
11/20/2016 Dynamic Forms ts COOKBOOK
Although in this example we're modelling a job application for heroes, there are no
references to any speci��c hero question outside the objects returned by
QuestionService .
This is very important since it allows us to repurpose the components for any type
of survey as long as it's compatible with our question object model. The key is the
dynamic data binding of metadata used to render the form without making any
hardcoded assumptions about speci��c questions. In addition to control metadata,
we are also adding validation dynamically.
The Save button is disabled until the form is in a valid state. When the form is valid,
we can click Save and the app renders the current form values as JSON. This proves
that any user input is bound back to the data model. Saving and retrieving the data
is an exercise for another time.
Back to top
https://angular.io/docs/ts/latest/cookbook/dynamicform.html 11/11