| 
									
										
										
										
											2017-05-26 21:28:06 +02:00
										 |  |  | # Dynamic Forms
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 22:10:32 +02:00
										 |  |  | {@a top} | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | Building handcrafted forms can be costly and time-consuming, | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | especially if you need a great number of them, they're similar to each other, and they change frequently | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | to meet rapidly changing business and regulatory requirements. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | It may be more economical to create the forms dynamically, based on | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | metadata that describes the business object model. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | This cookbook shows you how to use `formGroup` to dynamically | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | render a simple form with different control types and validation. | 
					
						
							|  |  |  | It's a primitive start. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience. | 
					
						
							|  |  |  | All such greatness has humble beginnings. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | The example in this cookbook is a dynamic form to build an | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | online application experience for heroes seeking employment. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | The agency is constantly tinkering with the application process. | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | You can create the forms on the fly *without changing the application code*. | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | {@a toc} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  | See the <live-example name="dynamic-form"></live-example>. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | {@a bootstrap} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Bootstrap
 | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | Start by creating an `NgModule` called `AppModule`. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | This cookbook uses [reactive forms](guide/reactive-forms). | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | Reactive forms belongs to a different `NgModule` called `ReactiveFormsModule`, | 
					
						
							|  |  |  | so in order to access any reactive forms directives, you have to import | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | `ReactiveFormsModule` from the `@angular/forms` library. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | Bootstrap the `AppModule` in `main.ts`. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | <code-tabs> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  |   <code-pane title="app.module.ts" path="dynamic-form/src/app/app.module.ts"> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  |   </code-pane> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  |   <code-pane title="main.ts" path="dynamic-form/src/main.ts"> | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   </code-pane> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </code-tabs> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | {@a object-model} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | ## Question model
 | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The next step is to define an object model that can describe all scenarios needed by the form functionality. | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | The hero application process involves a form with a lot of questions. | 
					
						
							|  |  |  | The _question_ is the most fundamental object in the model. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | The following `QuestionBase` is a fundamental question class. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  | <code-example path="dynamic-form/src/app/question-base.ts" title="src/app/question-base.ts"> | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | </code-example> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | From this base you can derive two new classes in `TextboxQuestion` and `DropdownQuestion` | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | that represent textbox and dropdown questions. | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | The idea is that the form will be bound to specific question types and render the | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | appropriate controls dynamically. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | `TextboxQuestion` supports multiple HTML5 types such as text, email, and url | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | via the `type` property. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  | <code-example path="dynamic-form/src/app/question-textbox.ts" title="src/app/question-textbox.ts" linenums="false"> | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | </code-example> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | `DropdownQuestion` presents a list of choices in a select box. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  | <code-example path="dynamic-form/src/app/question-dropdown.ts" title="src/app/question-dropdown.ts" linenums="false"> | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | </code-example> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | Next is `QuestionControlService`, a simple service for transforming the questions to a `FormGroup`. | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | In a nutshell, the form group consumes the metadata from the question model and | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | allows you to specify default values and validation rules. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  | <code-example path="dynamic-form/src/app/question-control.service.ts" title="src/app/question-control.service.ts" linenums="false"> | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | </code-example> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | {@a form-component} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Question form components
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | Now that you have defined the complete model you are ready | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | to create components to represent the dynamic form. | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | `DynamicFormComponent` is the entry point and the main container for the form. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | <code-tabs> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  |   <code-pane title="dynamic-form.component.html" path="dynamic-form/src/app/dynamic-form.component.html"> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  |   </code-pane> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  |   <code-pane title="dynamic-form.component.ts" path="dynamic-form/src/app/dynamic-form.component.ts"> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  |   </code-pane> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </code-tabs> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-10 10:45:05 +01:00
										 |  |  | It presents a list of questions, each bound to a `<app-question>` component element. | 
					
						
							|  |  |  | The `<app-question>` tag matches the `DynamicFormQuestionComponent`, | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | the component responsible for rendering the details of each _individual_ | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | question based on values in the data-bound question object. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | <code-tabs> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  |   <code-pane title="dynamic-form-question.component.html" path="dynamic-form/src/app/dynamic-form-question.component.html"> | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   </code-pane> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  |   <code-pane title="dynamic-form-question.component.ts" path="dynamic-form/src/app/dynamic-form-question.component.ts"> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  |   </code-pane> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | </code-tabs> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | Notice this component can present any type of question in your model. | 
					
						
							|  |  |  | You only have two types of questions at this point but you can imagine many more. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | The `ngSwitch` determines which type of question to display. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | In both components  you're relying on Angular's **formGroup** to connect the template HTML to the | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | underlying control objects, populated from the question model with display and validation rules. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | `formControlName` and `formGroup` are directives defined in | 
					
						
							|  |  |  | `ReactiveFormsModule`. The templates can access these directives | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | directly since you imported `ReactiveFormsModule` from `AppModule`. | 
					
						
							|  |  |  | {@a questionnaire-data} | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | ## Questionnaire data
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | `DynamicFormComponent` expects the list of questions in the form of an array bound to `@Input() questions`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  The set of questions you've defined for the job application is returned from the `QuestionService`. | 
					
						
							|  |  |  |  In a real app you'd retrieve these questions from storage. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  |  The key point is that you control the hero job application questions | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  |  entirely through the objects returned from `QuestionService`. | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  |  Questionnaire maintenance is a simple matter of adding, updating, | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  |  and removing objects from the `questions` array. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  | <code-example path="dynamic-form/src/app/question.service.ts" title="src/app/question.service.ts"> | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | </code-example> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | Finally, display an instance of the form in the `AppComponent` shell. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  | <code-example path="dynamic-form/src/app/app.component.ts" title="app.component.ts"> | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | </code-example> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | {@a dynamic-template} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Dynamic Template
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | Although in this example you're modelling a job application for heroes, there are | 
					
						
							| 
									
										
										
										
											2017-04-12 21:53:18 +02:00
										 |  |  | no references to any specific hero question | 
					
						
							|  |  |  | outside the objects returned by `QuestionService`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This is very important since it allows you to repurpose the components for any type of survey | 
					
						
							|  |  |  | as long as it's compatible with the *question* object model. | 
					
						
							|  |  |  | The key is the dynamic data binding of metadata used to render the form | 
					
						
							|  |  |  | without making any hardcoded assumptions about specific questions. | 
					
						
							|  |  |  | In addition to control metadata, you are also adding validation dynamically. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The *Save* button is disabled until the form is in a valid state. | 
					
						
							|  |  |  | When the form is valid, you can click *Save* and the app renders the current form values as JSON. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | This proves that any user input is bound back to the data model. | 
					
						
							|  |  |  | Saving and retrieving the data is an exercise for another time. | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | The final form looks like this: | 
					
						
							| 
									
										
										
										
											2017-03-30 20:04:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-09 23:53:32 +01:00
										 |  |  | <figure> | 
					
						
							|  |  |  |   <img src="generated/images/guide/dynamic-form/dynamic-form.png" alt="Dynamic-Form"> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | </figure> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | [Back to top](guide/dynamic-form#top) |