5 lines
49 KiB
JSON
5 lines
49 KiB
JSON
{
|
||
"id": "guide/forms",
|
||
"title": "Building a template-driven form",
|
||
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/guide/forms.md?message=docs%3A%20describe%20your%20change...\" aria-label=\"Suggest Edits\" title=\"Suggest Edits\"><i class=\"material-icons\" aria-hidden=\"true\" role=\"img\">mode_edit</i></a>\n</div>\n\n\n<div class=\"content\">\n <h1 id=\"building-a-template-driven-form\">Building a template-driven form<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#building-a-template-driven-form\"><i class=\"material-icons\">link</i></a></h1>\n<a id=\"template-driven\"></a>\n<p>This tutorial shows you how to create a template-driven form whose control elements are bound to data properties, with input validation to maintain data integrity and styling to improve the user experience.</p>\n<p>Template-driven forms use <a href=\"guide/architecture-components#data-binding\" title=\"Intro to 2-way data binding\">two-way data binding</a> to update the data model in the component as changes are made in the template and vice versa.</p>\n<div class=\"alert is-helpful\">\n<p>Angular supports two design approaches for interactive forms. You can build forms by writing templates using Angular <a href=\"guide/glossary#template\" title=\"Definition of template terms\">template syntax and directives</a> with the form-specific directives and techniques described in this tutorial, or you can use a reactive (or model-driven) approach to build forms.</p>\n<p>Template-driven forms are suitable for small or simple forms, while reactive forms are more scalable and suitable for complex forms.\nFor a comparison of the two approaches, see <a href=\"guide/forms-overview\" title=\"Overview of Angular forms.\">Introduction to Forms</a></p>\n</div>\n<p>You can build almost any kind of form with an Angular template—login forms, contact forms, and pretty much any business form.\nYou can lay out the controls creatively and bind them to the data in your object model.\nYou can specify validation rules and display validation errors,\nconditionally enable or disable specific controls, trigger built-in visual feedback, and much more.</p>\n<p>This tutorial shows you how to build a form from scratch, using a simplified sample form like the one from the <a href=\"tutorial\" title=\"Tour of Heroes\">Tour of Heroes tutorial</a> to illustrate the techniques.</p>\n<div class=\"alert is-helpful\">\n<p> Run or download the example app: <live-example></live-example>.</p>\n</div>\n<h2 id=\"objectives\">Objectives<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#objectives\"><i class=\"material-icons\">link</i></a></h2>\n<p>This tutorial teaches you how to do the following:</p>\n<ul>\n<li>Build an Angular form with a component and template.</li>\n<li>Use <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code> to create two-way data bindings for reading and writing input-control values.</li>\n<li>Provide visual feedback using special CSS classes that track the state of the controls.</li>\n<li>Display validation errors to users and enable or disable form controls based on the form status.</li>\n<li>Share information across HTML elements using <a href=\"guide/template-reference-variables\">template reference variables</a>.</li>\n</ul>\n<h2 id=\"prerequisites\">Prerequisites<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#prerequisites\"><i class=\"material-icons\">link</i></a></h2>\n<p>Before going further into template-driven forms, you should have a basic understanding of the following.</p>\n<ul>\n<li><a href=\"https://www.typescriptlang.org/\" title=\"The TypeScript language\">TypeScript</a> and HTML5 programming.</li>\n<li>Angular app-design fundamentals, as described in <a href=\"guide/architecture\" title=\"Introduction to Angular concepts.\">Angular Concepts</a>.</li>\n<li>The basics of <a href=\"guide/template-syntax\" title=\"Template syntax guide\">Angular template syntax</a>.</li>\n<li>The form-design concepts that are presented in <a href=\"guide/forms-overview\" title=\"Overview of Angular forms.\">Introduction to Forms</a>.</li>\n</ul>\n<a id=\"intro\"></a>\n<h2 id=\"build-a-template-driven-form\">Build a template-driven form<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#build-a-template-driven-form\"><i class=\"material-icons\">link</i></a></h2>\n<p>Template-driven forms rely on directives defined in the <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code>.</p>\n<ul>\n<li>\n<p>The <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">NgModel</a></code> directive reconciles value changes in the attached form element with changes in the data model, allowing you to respond to user input with input validation and error handling.</p>\n</li>\n<li>\n<p>The <code><a href=\"api/forms/NgForm\" class=\"code-anchor\">NgForm</a></code> directive creates a top-level <code><a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a></code> instance and binds it to a <code><form></code> element to track aggregated form value and validation status.\nAs soon as you import <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code>, this directive becomes active by default on all <code><form></code> tags. You don't need to add a special selector.</p>\n</li>\n<li>\n<p>The <code><a href=\"api/forms/NgModelGroup\" class=\"code-anchor\">NgModelGroup</a></code> directive creates and binds a <code><a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a></code> instance to a DOM element.</p>\n</li>\n</ul>\n<h3 id=\"the-sample-application\">The sample application<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#the-sample-application\"><i class=\"material-icons\">link</i></a></h3>\n<p>The sample form in this guide is used by the <em>Hero Employment Agency</em> to maintain personal information about heroes.\nEvery hero needs a job. This form helps the agency match the right hero with the right crisis.</p>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/forms/hero-form-1.png\" alt=\"Clean Form\" width=\"479\" height=\"339\">\n</div>\n<p>The form highlights some design features that make it easier to use. For instance, the two required fields have a green bar on the left to make them easy to spot. These fields have initial values, so the form is valid and the <strong>Submit</strong> button is enabled.</p>\n<p>As you work with this form, you will learn how to include validation logic, how to customize the presentation with standard CSS, and how to handle error conditions to ensure valid input.\nIf the user deletes the hero name, for example, the form becomes invalid. The app detects the changed status, and displays a validation error in an attention-grabbing style.\nIn addition, the <strong>Submit</strong> button is disabled, and the \"required\" bar to the left of the input control changes from green to red.</p>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/forms/hero-form-2.png\" alt=\"Invalid, Name Required\" width=\"465\" height=\"402\">\n</div>\n<h3 id=\"step-overview\">Step overview<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#step-overview\"><i class=\"material-icons\">link</i></a></h3>\n<p>In the course of this tutorial, you bind a sample form to data and handle user input using the following steps.</p>\n<ol>\n<li>\n<p>Build the basic form.</p>\n<ul>\n<li>Define a sample data model.</li>\n<li>Include required infrastructure such as the <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code>.</li>\n</ul>\n</li>\n<li>\n<p>Bind form controls to data properties using the <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code> directive and two-way data-binding syntax.</p>\n<ul>\n<li>Examine how <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code> reports control states using CSS classes.</li>\n<li>Name controls to make them accessible to <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code>.</li>\n</ul>\n</li>\n<li>\n<p>Track input validity and control status using <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code>.</p>\n<ul>\n<li>Add custom CSS to provide visual feedback on the status.</li>\n<li>Show and hide validation-error messages.</li>\n</ul>\n</li>\n<li>Respond to a native HTML button-click event by adding to the model data.</li>\n<li>\n<p>Handle form submission using the <a href=\"api/forms/NgForm#properties\"><code>ngSubmit</code></a> output property of the form.</p>\n<ul>\n<li>Disable the <strong>Submit</strong> button until the form is valid.</li>\n<li>After submit, swap out the finished form for different content on the page.</li>\n</ul>\n</li>\n</ol>\n<a id=\"step1\"></a>\n<h2 id=\"build-the-form\">Build the form<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#build-the-form\"><i class=\"material-icons\">link</i></a></h2>\n<p>You can recreate the sample application from the code provided here, or you can examine or download the <live-example></live-example>.</p>\n<ol>\n<li>\n<p>The provided sample application creates the <code>Hero</code> class which defines the data model reflected in the form.</p>\n<code-example path=\"forms/src/app/hero.ts\" header=\"src/app/hero.ts\">\nexport class Hero {\n\n constructor(\n public id: number,\n public name: string,\n public power: string,\n public alterEgo?: string\n ) { }\n\n}\n\n\n</code-example>\n</li>\n<li>\n<p>The form layout and details are defined in the <code>HeroFormComponent</code> class.</p>\n<p> <code-example path=\"forms/src/app/hero-form/hero-form.component.ts\" header=\"src/app/hero-form/hero-form.component.ts (v1)\" region=\"v1\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a> } from '@angular/core';\n\nimport { Hero } from '../hero';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-hero-form',\n templateUrl: './hero-form.component.html',\n styleUrls: ['./hero-form.component.css']\n})\nexport class HeroFormComponent {\n\n powers = ['Really Smart', 'Super Flexible',\n 'Super Hot', 'Weather Changer'];\n\n model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet');\n\n submitted = false;\n\n onSubmit() { this.submitted = true; }\n\n // TODO: Remove this when we're done\n get diagnostic() { return JSON.stringify(this.model); }\n}\n\n\n</code-example></p>\n<p> The component's <code>selector</code> value of \"app-hero-form\" means you can drop this form in a parent\ntemplate using the <code><app-hero-form></code> tag.</p>\n</li>\n<li>\n<p>The following code creates a new hero instance, so that the initial form can show an example hero.</p>\n<code-example path=\"forms/src/app/hero-form/hero-form.component.ts\" region=\"SkyDog\">\nconst myHero = new Hero(42, 'SkyDog',\n 'Fetch any object at any distance',\n 'Leslie Rollover');\nconsole.log('My hero is called ' + myHero.name); // \"My hero is called SkyDog\"\n\n</code-example>\n<p>This demo uses dummy data for <code>model</code> and <code>powers</code>. In a real app, you would inject a data service to get and save real data, or expose these properties as inputs and outputs.</p>\n</li>\n<li>\n<p>The application enables the Forms feature and registers the created form component.</p>\n<code-example path=\"forms/src/app/app.module.ts\" header=\"src/app/app.module.ts\">\nimport { <a href=\"api/core/NgModule\" class=\"code-anchor\">NgModule</a> } from '@angular/core';\nimport { <a href=\"api/platform-browser/BrowserModule\" class=\"code-anchor\">BrowserModule</a> } from '@angular/platform-browser';\nimport { <a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a> } from '@angular/forms';\n\nimport { AppComponent } from './app.component';\nimport { HeroFormComponent } from './hero-form/hero-form.component';\n\n@<a href=\"api/core/NgModule\" class=\"code-anchor\">NgModule</a>({\n imports: [\n <a href=\"api/platform-browser/BrowserModule\" class=\"code-anchor\">BrowserModule</a>,\n <a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a>\n ],\n declarations: [\n AppComponent,\n HeroFormComponent\n ],\n providers: [],\n bootstrap: [ AppComponent ]\n})\nexport class AppModule { }\n\n\n</code-example>\n</li>\n<li>\n<p>The form is displayed in the application layout defined by the root component's template.</p>\n<code-example path=\"forms/src/app/app.component.html\" header=\"src/app/app.component.html\">\n<app-hero-form></app-hero-form>\n\n\n</code-example>\n<p>The initial template defines the layout for a form with two form groups and a submit button.\nThe form groups correspond to two properties of the Hero data model, name and alterEgo. Each group has a label and a box for user input.</p>\n<ul>\n<li>The <strong>Name</strong> <code><input></code> control element has the HTML5 <code>required</code> attribute.</li>\n<li>The <strong>Alter Ego</strong> <code><input></code> control element does not because <code>alterEgo</code> is optional.</li>\n</ul>\n<p>The <strong>Submit</strong> button has some classes on it for styling.\nAt this point, the form layout is all plain HTML5, with no bindings or directives.</p>\n</li>\n<li>\n<p>The sample form uses some style classes from <a href=\"https://getbootstrap.com/css/\">Twitter Bootstrap</a>: <code>container</code>, <code>form-group</code>, <code>form-control</code>, and <code>btn</code>.\nTo use these styles, the app's style sheet imports the library.</p>\n<code-example path=\"forms/src/styles.1.css\" header=\"src/styles.css\">\n@import url('https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css');\n\n\n</code-example>\n</li>\n<li>\n<p>The form makes the hero applicant choose one superpower from a fixed list of agency-approved powers.\nThe predefined list of <code>powers</code> is part of the data model, maintained internally in <code>HeroFormComponent</code>.\nThe Angular <a href=\"api/common/NgForOf\" title=\"API reference\">NgForOf directive</a> iterates over the data values to populate the <code><select></code> element.</p>\n<code-example path=\"forms/src/app/hero-form/hero-form.component.html\" header=\"src/app/hero-form/hero-form.component.html (powers)\" region=\"powers\">\n<div class=\"form-group\">\n <label for=\"power\">Hero Power</label>\n <select class=\"form-control\" id=\"power\" required>\n <option *<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let pow of powers\" [value]=\"pow\">{{pow}}</option>\n </select>\n</div>\n\n\n</code-example>\n</li>\n</ol>\n<p>If you run the app right now, you see the list of powers in the selection control. The input elements are not yet bound to data values or events, so they are still blank and have no behavior.</p>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/forms/hero-form-3.png\" alt=\"Early form with no binding\" width=\"473\" height=\"294\">\n</div>\n<a id=\"ngModel\"></a>\n<h2 id=\"bind-input-controls-to-data-properties\">Bind input controls to data properties<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#bind-input-controls-to-data-properties\"><i class=\"material-icons\">link</i></a></h2>\n<p>The next step is to bind the input controls to the corresponding <code>Hero</code> properties with two-way data binding, so that they respond to user input by updating the data model, and also respond to programmatic changes in the data by updating the display.</p>\n<p>The <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code> directive declared in the <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code> lets you bind controls in your template-driven form to properties in your data model.\nWhen you include the directive using the syntax for two-way data binding, <code>[(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]</code>, Angular can track the value and user interaction of the control and keep the view synced with the model.</p>\n<ol>\n<li>\n<p>Edit the template file <code>hero-form.component.html</code>.</p>\n</li>\n<li>\n<p>Find the <code><input></code> tag next to the <strong>Name</strong> label.</p>\n</li>\n<li>\n<p>Add the <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code> directive, using two-way data binding syntax <code>[(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"...\"</code>.</p>\n</li>\n</ol>\n<code-example path=\"forms/src/app/hero-form/hero-form.component.html\" header=\"src/app/hero-form/hero-form.component.html (excerpt)\" region=\"ngModelName-1\">\n<input type=\"text\" class=\"form-control\" id=\"name\"\n required\n [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"model.name\" name=\"name\">\nTODO: remove this: {{model.name}}\n\n</code-example>\n<div class=\"alert is-helpful\">\n<p>This example has a temporary diagnostic interpolation after each input tag, <code>{{model.name}}</code>, to show the current data value of the corresponding property.\nThe note reminds you to remove the diagnostic lines when you have finished observing the two-way data binding at work.</p>\n</div>\n<a id=\"ngForm\"></a>\n<h3 id=\"access-the-overall-form-status\">Access the overall form status<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#access-the-overall-form-status\"><i class=\"material-icons\">link</i></a></h3>\n<p>When you imported the <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code> in your component, Angular automatically created and attached an <a href=\"api/forms/NgForm\" title=\"API reference for NgForm\">NgForm</a> directive to the <code><form></code> tag in the template (because <code><a href=\"api/forms/NgForm\" class=\"code-anchor\">NgForm</a></code> has the selector <code>form</code> that matches <code><form></code> elements).</p>\n<p>To get access to the <code><a href=\"api/forms/NgForm\" class=\"code-anchor\">NgForm</a></code> and the overall form status, declare a <a href=\"guide/template-reference-variables\">template reference variable</a>.</p>\n<ol>\n<li>\n<p>Edit the template file <code>hero-form.component.html</code>.</p>\n</li>\n<li>\n<p>Update the <code><form></code> tag with a template reference variable, <code>#heroForm</code>, and set its value as follows.</p>\n<code-example path=\"forms/src/app/hero-form/hero-form.component.html\" header=\"src/app/hero-form/hero-form.component.html (excerpt)\" region=\"template-variable\">\n<form #heroForm=\"<a href=\"api/forms/NgForm\" class=\"code-anchor\">ngForm</a>\">\n\n</code-example>\n<p>The <code>heroForm</code> template variable is now a reference to the <code><a href=\"api/forms/NgForm\" class=\"code-anchor\">NgForm</a></code> directive instance that governs the form as a whole.</p>\n</li>\n<li>\n<p>Run the app.</p>\n</li>\n<li>\n<p>Start typing in the <strong>Name</strong> input box.</p>\n<p>As you add and delete characters, you can see them appear and disappear from the data model.\nFor example:</p>\n <div class=\"lightbox\">\n <img src=\"generated/images/guide/forms/ng-model-in-action.png\" alt=\"ngModel in action\" width=\"500\" height=\"74\">\n </div>\n<p>The diagnostic line that shows interpolated values demonstrates that values are really flowing from the input box to the model and back again.</p>\n</li>\n</ol>\n<h3 id=\"naming-control-elements\">Naming control elements<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#naming-control-elements\"><i class=\"material-icons\">link</i></a></h3>\n<p>When you use <code>[(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]</code> on an element, you must define a <code>name</code> attribute for that element.\nAngular uses the assigned name to register the element with the <code><a href=\"api/forms/NgForm\" class=\"code-anchor\">NgForm</a></code> directive attached to the parent <code><form></code> element.</p>\n<p>The example added a <code>name</code> attribute to the <code><input></code> element and set it to \"name\",\nwhich makes sense for the hero's name.\nAny unique value will do, but using a descriptive name is helpful.</p>\n<ol>\n<li>\n<p>Add similar <code>[(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]</code> bindings and <code>name</code> attributes to <strong>Alter Ego</strong> and <strong>Hero Power</strong>.</p>\n</li>\n<li>\n<p>You can now remove the diagnostic messages that show interpolated values.</p>\n</li>\n<li>\n<p>To confirm that two-way data binding works for the entire hero model, add a new binding at the top to the component's <code>diagnostic</code> property.</p>\n</li>\n</ol>\n<p>After these revisions, the form template should look like the following:</p>\n<code-example path=\"forms/src/app/hero-form/hero-form.component.html\" header=\"src/app/hero-form/hero-form.component.html (excerpt)\" region=\"ngModel-2\">\n{{diagnostic}}\n<div class=\"form-group\">\n <label for=\"name\">Name</label>\n <input type=\"text\" class=\"form-control\" id=\"name\"\n required\n [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"model.name\" name=\"name\">\n</div>\n\n<div class=\"form-group\">\n <label for=\"alterEgo\">Alter Ego</label>\n <input type=\"text\" class=\"form-control\" id=\"alterEgo\"\n [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"model.alterEgo\" name=\"alterEgo\">\n</div>\n\n<div class=\"form-group\">\n <label for=\"power\">Hero Power</label>\n <select class=\"form-control\" id=\"power\"\n required\n [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"model.power\" name=\"power\">\n <option *<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let pow of powers\" [value]=\"pow\">{{pow}}</option>\n </select>\n</div>\n\n\n</code-example>\n<ul>\n<li>\n<p>Notice that each <code><input></code> element has an <code>id</code> property. This is used by the <code><label></code> element's <code>for</code> attribute to match the label to its input control. This is a <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label\">standard HTML feature</a>.</p>\n</li>\n<li>\n<p>Each <code><input></code> element also has the required <code>name</code> property that Angular uses to register the control with the form.</p>\n</li>\n</ul>\n<p>If you run the app now and change every hero model property, the form might display like this:</p>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/forms/ng-model-in-action-2.png\" alt=\"ngModel in action\" width=\"515\" height=\"377\">\n</div>\n<p>The diagnostic near the top of the form confirms that all of your changes are reflected in the model.</p>\n<ol start=\"4\">\n<li>When you have observed the effects, you can delete the <code>{{diagnostic}}</code> binding.</li>\n</ol>\n<h2 id=\"track-control-states\">Track control states<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#track-control-states\"><i class=\"material-icons\">link</i></a></h2>\n<p>The <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">NgModel</a></code> directive on a control tracks the state of that control.\nIt tells you if the user touched the control, if the value changed, or if the value became invalid.\nAngular sets special CSS classes on the control element to reflect the state, as shown in the following table.</p>\n<table>\n <tbody><tr>\n <th>\n State\n </th>\n <th>\n Class if true\n </th>\n <th>\n Class if false\n </th>\n </tr>\n <tr>\n <td>\n The control has been visited.\n </td>\n <td>\n <code>ng-touched</code>\n </td>\n <td>\n <code>ng-untouched</code>\n </td>\n </tr>\n <tr>\n <td>\n The control's value has changed.\n </td>\n <td>\n <code>ng-dirty</code>\n </td>\n <td>\n <code>ng-pristine</code>\n </td>\n </tr>\n <tr>\n <td>\n The control's value is valid.\n </td>\n <td>\n <code>ng-valid</code>\n </td>\n <td>\n <code>ng-invalid</code>\n </td>\n </tr>\n</tbody></table>\n<p>You use these CSS classes to define the styles for your control based on its status.</p>\n<h3 id=\"observe-control-states\">Observe control states<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#observe-control-states\"><i class=\"material-icons\">link</i></a></h3>\n<p>To see how the classes are added and removed by the framework, open the browser's developer tools and inspect the <code><input></code> element that represents the hero name.</p>\n<ol>\n<li>\n<p>Using your browser's developer tools, find the <code><input></code> element that corresponds to the <strong>Name</strong> input box.\nYou can see that the element has multiple CSS classes in addition to \"form-control\".</p>\n</li>\n<li>\n<p>When you first bring it up, the classes indicate that it has a valid value, that the value has not been changed since initialization or reset, and that the control has not been visited since initialization or reset.</p>\n<code-example>\n<input ... class=\"form-control ng-untouched ng-pristine ng-valid\" ...>\n</code-example>\n</li>\n<li>\n<p>Take the following actions on the <strong>Name</strong> <code><input></code> box, and observe which classes appear.</p>\n<ul>\n<li>Look but don't touch. The classes indicate that it is untouched, pristine, and valid.</li>\n<li>Click inside the name box, then click outside it. The control has now been visited, and the element has the <code>ng-touched</code> class instead of the <code>ng-untouched</code> class.</li>\n<li>Add slashes to the end of the name. It is now touched and dirty.</li>\n<li>Erase the name. This makes the value invalid, so the <code>ng-invalid</code> class replaces the <code>ng-valid</code> class.</li>\n</ul>\n</li>\n</ol>\n<h3 id=\"create-visual-feedback-for-states\">Create visual feedback for states<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#create-visual-feedback-for-states\"><i class=\"material-icons\">link</i></a></h3>\n<p>The <code>ng-valid</code>/<code>ng-invalid</code> pair is particularly interesting, because you want to send a\nstrong visual signal when the values are invalid.\nYou also want to mark required fields.</p>\n<p>You can mark required fields and invalid data at the same time with a colored bar\non the left of the input box:</p>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/forms/validity-required-indicator.png\" alt=\"Invalid Form\" width=\"600\" height=\"171\">\n</div>\n<p>To change the appearance in this way, take the following steps.</p>\n<ol>\n<li>\n<p>Add definitions for the <code>ng-*</code> CSS classes.</p>\n</li>\n<li>\n<p>Add these class definitions to a new <code>forms.css</code> file.</p>\n</li>\n<li>\n<p>Add the new file to the project as a sibling to <code>index.html</code>:</p>\n<code-example path=\"forms/src/assets/forms.css\" header=\"src/assets/forms.css\">\n.ng-valid[required], .ng-valid.required {\n border-left: 5px solid #42A948; /* green */\n}\n\n.ng-invalid:not(form) {\n border-left: 5px solid #a94442; /* red */\n}\n\n</code-example>\n</li>\n<li>\n<p>In the <code>index.html</code> file, update the <code><head></code> tag to include the new style sheet.</p>\n<code-example path=\"forms/src/index.html\" header=\"src/index.html (styles)\" region=\"styles\">\n<link rel=\"stylesheet\" href=\"assets/forms.css\">\n\n</code-example>\n</li>\n</ol>\n<h3 id=\"show-and-hide-validation-error-messages\">Show and hide validation error messages<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#show-and-hide-validation-error-messages\"><i class=\"material-icons\">link</i></a></h3>\n<p>The <strong>Name</strong> input box is required and clearing it turns the bar red.\nThat indicates that something is wrong, but the user doesn't know what is wrong or what to do about it.\nYou can provide a helpful message by checking for and responding to the control's state.</p>\n<p>When the user deletes the name, the form should look like this:</p>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/forms/name-required-error.png\" alt=\"Name required\" width=\"400\" height=\"108\">\n</div>\n<p>The <strong>Hero Power</strong> select box is also required, but it doesn't need this kind of error handling because the selection box already constrains the selection to valid values.</p>\n<p>To define and show an error message when appropriate, take the following steps.</p>\n<ol>\n<li>\n<p>Extend the <code><input></code> tag with a template reference variable that you can use to access the input box's Angular control from within the template. In the example, the variable is <code>#name=\"<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>\"</code>.</p>\n<div class=\"alert is-helpful\">\n<p> The template reference variable (<code>#name</code>) is set to <code>\"<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>\"</code> because that is the value of the <a href=\"api/core/Directive#exportAs\"><code>NgModel.exportAs</code></a> property. This property tells Angular how to link a reference variable to a directive.</p>\n</div>\n</li>\n<li>\n<p>Add a <code><div></code> that contains a suitable error message.</p>\n</li>\n<li>\n<p>Show or hide the error message by binding properties of the <code>name</code>\ncontrol to the message <code><div></code> element's <code>hidden</code> property.</p>\n<p> <code-example path=\"forms/src/app/hero-form/hero-form.component.html\" header=\"src/app/hero-form/hero-form.component.html (hidden-error-msg)\" region=\"hidden-error-msg\">\n<div [hidden]=\"name.valid || name.pristine\"\n class=\"alert alert-danger\">\n\n</code-example></p>\n</li>\n<li>\n<p>Add a conditional error message to the <em>name</em> input box, as in the following example.</p>\n<code-example path=\"forms/src/app/hero-form/hero-form.component.html\" header=\"src/app/hero-form/hero-form.component.html (excerpt)\" region=\"name-with-error-msg\">\n<label for=\"name\">Name</label>\n<input type=\"text\" class=\"form-control\" id=\"name\"\n required\n [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"model.name\" name=\"name\"\n #name=\"<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>\">\n<div [hidden]=\"name.valid || name.pristine\"\n class=\"alert alert-danger\">\n Name is required\n</div>\n\n</code-example>\n</li>\n</ol>\n<div class=\"callout is-helpful\">\n<header>Illustrating the \"pristine\" state</header>\n<p>In this example, you hide the message when the control is either valid or <em>pristine</em>.\nPristine means the user hasn't changed the value since it was displayed in this form.\nIf you ignore the <code>pristine</code> state, you would hide the message only when the value is valid.\nIf you arrive in this component with a new (blank) hero or an invalid hero,\nyou'll see the error message immediately, before you've done anything.</p>\n<p>You might want the message to display only when the user makes an invalid change.\nHiding the message while the control is in the <code>pristine</code> state achieves that goal.\nYou'll see the significance of this choice when you add a new hero to the form in the next step.</p>\n</div>\n<h2 id=\"add-a-new-hero\">Add a new hero<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#add-a-new-hero\"><i class=\"material-icons\">link</i></a></h2>\n<p>This exercise shows how you can respond to a native HTML button-click event by adding to the model data.\nTo let form users add a new hero, you will add a <strong>New Hero</strong> button that responds to a click event.</p>\n<ol>\n<li>\n<p>In the template, place a \"New Hero\" <code><button></code> element at the bottom of the form.</p>\n</li>\n<li>\n<p>In the component file, add the hero-creation method to the hero data model.</p>\n<code-example path=\"forms/src/app/hero-form/hero-form.component.ts\" region=\"new-hero\" header=\"src/app/hero-form/hero-form.component.ts (New Hero method)\">\nnewHero() {\n this.model = new Hero(42, '', '');\n}\n\n</code-example>\n</li>\n<li>\n<p>Bind the button's click event to a hero-creation method, <code>newHero()</code>.</p>\n<code-example path=\"forms/src/app/hero-form/hero-form.component.html\" region=\"new-hero-button-no-reset\" header=\"src/app/hero-form/hero-form.component.html (New Hero button)\">\n<button type=\"button\" class=\"btn btn-default\" (click)=\"newHero()\">New Hero</button>\n\n</code-example>\n</li>\n<li>\n<p>Run the application again and click the <strong>New Hero</strong> button.</p>\n<p>The form clears, and the <em>required</em> bars to the left of the input box are red, indicating invalid <code>name</code> and <code>power</code> properties.\nNotice that the error messages are hidden. This is because the form is pristine; you haven't changed anything yet.</p>\n</li>\n<li>\n<p>Enter a name and click <strong>New Hero</strong> again.</p>\n<p>Now the app displays a <em>Name is required</em> error message, because the input box is no longer pristine.\nThe form remembers that you entered a name before clicking <strong>New Hero</strong>.</p>\n</li>\n<li>\n<p>To restore the pristine state of the form controls, clear all of the flags imperatively by calling the form's <code>reset()</code> method after calling the <code>newHero()</code> method.</p>\n<code-example path=\"forms/src/app/hero-form/hero-form.component.html\" region=\"new-hero-button-form-reset\" header=\"src/app/hero-form/hero-form.component.html (Reset the form)\">\n<button type=\"button\" class=\"btn btn-default\" (click)=\"newHero(); heroForm.reset()\">New Hero</button>\n\n</code-example>\n<p>Now clicking <strong>New Hero</strong> resets both the form and its control flags.</p>\n</li>\n</ol>\n<div class=\"alert is-helpful\">\n<p>See the <a href=\"guide/user-input\">User Input</a> guide for more information about listening for DOM events with an event binding and updating a corresponding component property.</p>\n</div>\n<h2 id=\"submit-the-form-with-ngsubmit\">Submit the form with <em>ngSubmit</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#submit-the-form-with-ngsubmit\"><i class=\"material-icons\">link</i></a></h2>\n<p>The user should be able to submit this form after filling it in.\nThe <strong>Submit</strong> button at the bottom of the form does nothing on its own, but it does\ntrigger a form-submit event because of its type (<code>type=\"submit\"</code>).\nTo respond to this event, take the following steps.</p>\n<ol>\n<li>\n<p>Bind the form's <a href=\"api/forms/NgForm#properties\"><code>ngSubmit</code></a> event property to the hero-form component's <code>onSubmit()</code> method.</p>\n<code-example path=\"forms/src/app/hero-form/hero-form.component.html\" header=\"src/app/hero-form/hero-form.component.html (ngSubmit)\" region=\"ngSubmit\">\n<form (ngSubmit)=\"onSubmit()\" #heroForm=\"<a href=\"api/forms/NgForm\" class=\"code-anchor\">ngForm</a>\">\n\n</code-example>\n</li>\n<li>\n<p>Use the template reference variable, <code>#heroForm</code> to access the form that contains the <strong>Submit</strong> button and create an event binding.\nYou will bind the form property that indicates its overall validity to the <strong>Submit</strong> button's <code>disabled</code> property.</p>\n<p> <code-example path=\"forms/src/app/hero-form/hero-form.component.html\" header=\"src/app/hero-form/hero-form.component.html (submit-button)\" region=\"submit-button\">\n<button type=\"submit\" class=\"btn btn-success\" [disabled]=\"!heroForm.form.valid\">Submit</button>\n\n</code-example></p>\n</li>\n<li>\n<p>Run the application now. Notice that the button is enabled—although\nit doesn't do anything useful yet.</p>\n</li>\n<li>\n<p>Delete the <strong>Name</strong> value. This violates the \"required\" rule, so it displays the error message—and notice that it also disables the <strong>Submit</strong> button.</p>\n</li>\n</ol>\n<p> You didn't have to explicitly wire the button's enabled state to the form's validity.\nThe <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code> did this automatically when you defined a template reference variable on the enhanced form element, then referred to that variable in the button control.</p>\n<h3 id=\"respond-to-form-submission\">Respond to form submission<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#respond-to-form-submission\"><i class=\"material-icons\">link</i></a></h3>\n<p>To show a response to form submission, you can hide the data entry area and display something else in its place.</p>\n<ol>\n<li>\n<p>Wrap the entire form in a <code><div></code> and bind\nits <code>hidden</code> property to the <code>HeroFormComponent.submitted</code> property.</p>\n<p> <code-example path=\"forms/src/app/hero-form/hero-form.component.html\" header=\"src/app/hero-form/hero-form.component.html (excerpt)\" region=\"edit-div\">\n<div [hidden]=\"submitted\">\n <h1>Hero <a href=\"api/forms/Form\" class=\"code-anchor\">Form</a></h1>\n <form (ngSubmit)=\"onSubmit()\" #heroForm=\"<a href=\"api/forms/NgForm\" class=\"code-anchor\">ngForm</a>\">\n\n <!-- ... all of the form ... -->\n\n </form>\n</div>\n\n</code-example></p>\n<ul>\n<li>\n<p>The main form is visible from the start because the <code>submitted</code> property is false until you submit the form, as this fragment from the <code>HeroFormComponent</code> shows:</p>\n<p> <code-example path=\"forms/src/app/hero-form/hero-form.component.ts\" header=\"src/app/hero-form/hero-form.component.ts (submitted)\" region=\"submitted\">\nsubmitted = false;\n\nonSubmit() { this.submitted = true; }\n\n</code-example></p>\n</li>\n<li>\n<p>When you click the <strong>Submit</strong> button, the <code>submitted</code> flag becomes true and the form disappears.</p>\n</li>\n</ul>\n</li>\n<li>\n<p>To show something else while the form is in the submitted state, add the following HTML below the new <code><div></code> wrapper.</p>\n<p> <code-example path=\"forms/src/app/hero-form/hero-form.component.html\" header=\"src/app/hero-form/hero-form.component.html (excerpt)\" region=\"submitted\">\n<div [hidden]=\"!submitted\">\n <h2>You submitted the following:</h2>\n <div class=\"row\">\n <div class=\"col-xs-3\">Name</div>\n <div class=\"col-xs-9\">{{ model.name }}</div>\n </div>\n <div class=\"row\">\n <div class=\"col-xs-3\">Alter Ego</div>\n <div class=\"col-xs-9\">{{ model.alterEgo }}</div>\n </div>\n <div class=\"row\">\n <div class=\"col-xs-3\">Power</div>\n <div class=\"col-xs-9\">{{ model.power }}</div>\n </div>\n <br>\n <button class=\"btn btn-primary\" (click)=\"submitted=false\">Edit</button>\n</div>\n\n</code-example></p>\n<p> This <code><div></code>, which shows a read-only hero with interpolation bindings, appears only while the component is in the submitted state.</p>\n<p> The alternative display includes an <em>Edit</em> button whose click event is bound to an expression\nthat clears the <code>submitted</code> flag.</p>\n</li>\n<li>\n<p>Click the <em>Edit</em> button to switch the display back to the editable form.</p>\n</li>\n</ol>\n<h2 id=\"summary\">Summary<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/forms#summary\"><i class=\"material-icons\">link</i></a></h2>\n<p>The Angular form discussed in this page takes advantage of the following\nframework features to provide support for data modification, validation, and more.</p>\n<ul>\n<li>An Angular HTML form template.</li>\n<li>A form component class with a <code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a></code> decorator.</li>\n<li>Handling form submission by binding to the <code><a href=\"api/forms/NgForm#ngSubmit\" class=\"code-anchor\">NgForm.ngSubmit</a></code> event property.</li>\n<li>Template-reference variables such as <code>#heroForm</code> and <code>#name</code>.</li>\n<li><code>[(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]</code> syntax for two-way data binding.</li>\n<li>The use of <code>name</code> attributes for validation and form-element change tracking.</li>\n<li>The reference variable’s <code>valid</code> property on input controls to check if a control is valid and show or hide error messages.</li>\n<li>Controlling the <strong>Submit</strong> button's enabled state by binding to <code><a href=\"api/forms/NgForm\" class=\"code-anchor\">NgForm</a></code> validity.</li>\n<li>Custom CSS classes that provide visual feedback to users about invalid controls.</li>\n</ul>\n<p>Here’s the code for the final version of the application:</p>\n<code-tabs>\n\n <code-pane header=\"hero-form/hero-form.component.ts\" path=\"forms/src/app/hero-form/hero-form.component.ts\" region=\"final\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a> } from '@angular/core';\n\nimport { Hero } from '../hero';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-hero-form',\n templateUrl: './hero-form.component.html',\n styleUrls: ['./hero-form.component.css']\n})\nexport class HeroFormComponent {\n\n powers = ['Really Smart', 'Super Flexible',\n 'Super Hot', 'Weather Changer'];\n\n model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet');\n\n submitted = false;\n\n onSubmit() { this.submitted = true; }\n\n newHero() {\n this.model = new Hero(42, '', '');\n }\n}\n\n\n</code-pane>\n\n <code-pane header=\"hero-form/hero-form.component.html\" path=\"forms/src/app/hero-form/hero-form.component.html\" region=\"final\">\n<div class=\"container\">\n <div [hidden]=\"submitted\">\n <h1>Hero <a href=\"api/forms/Form\" class=\"code-anchor\">Form</a></h1>\n <form (ngSubmit)=\"onSubmit()\" #heroForm=\"<a href=\"api/forms/NgForm\" class=\"code-anchor\">ngForm</a>\">\n <div class=\"form-group\">\n <label for=\"name\">Name</label>\n <input type=\"text\" class=\"form-control\" id=\"name\"\n required\n [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"model.name\" name=\"name\"\n #name=\"<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>\">\n <div [hidden]=\"name.valid || name.pristine\"\n class=\"alert alert-danger\">\n Name is required\n </div>\n </div>\n\n <div class=\"form-group\">\n <label for=\"alterEgo\">Alter Ego</label>\n <input type=\"text\" class=\"form-control\" id=\"alterEgo\"\n [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"model.alterEgo\" name=\"alterEgo\">\n </div>\n\n <div class=\"form-group\">\n <label for=\"power\">Hero Power</label>\n <select class=\"form-control\" id=\"power\"\n required\n [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"model.power\" name=\"power\"\n #power=\"<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>\">\n <option *<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let pow of powers\" [value]=\"pow\">{{pow}}</option>\n </select>\n <div [hidden]=\"power.valid || power.pristine\" class=\"alert alert-danger\">\n Power is required\n </div>\n </div>\n\n <button type=\"submit\" class=\"btn btn-success\" [disabled]=\"!heroForm.form.valid\">Submit</button>\n <button type=\"button\" class=\"btn btn-default\" (click)=\"newHero(); heroForm.reset()\">New Hero</button>\n </form>\n </div>\n\n <div [hidden]=\"!submitted\">\n <h2>You submitted the following:</h2>\n <div class=\"row\">\n <div class=\"col-xs-3\">Name</div>\n <div class=\"col-xs-9\">{{ model.name }}</div>\n </div>\n <div class=\"row\">\n <div class=\"col-xs-3\">Alter Ego</div>\n <div class=\"col-xs-9\">{{ model.alterEgo }}</div>\n </div>\n <div class=\"row\">\n <div class=\"col-xs-3\">Power</div>\n <div class=\"col-xs-9\">{{ model.power }}</div>\n </div>\n <br>\n <button class=\"btn btn-primary\" (click)=\"submitted=false\">Edit</button>\n </div>\n</div>\n\n</code-pane>\n\n <code-pane header=\"hero.ts\" path=\"forms/src/app/hero.ts\">\nexport class Hero {\n\n constructor(\n public id: number,\n public name: string,\n public power: string,\n public alterEgo?: string\n ) { }\n\n}\n\n\n</code-pane>\n\n <code-pane header=\"app.module.ts\" path=\"forms/src/app/app.module.ts\">\nimport { <a href=\"api/core/NgModule\" class=\"code-anchor\">NgModule</a> } from '@angular/core';\nimport { <a href=\"api/platform-browser/BrowserModule\" class=\"code-anchor\">BrowserModule</a> } from '@angular/platform-browser';\nimport { <a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a> } from '@angular/forms';\n\nimport { AppComponent } from './app.component';\nimport { HeroFormComponent } from './hero-form/hero-form.component';\n\n@<a href=\"api/core/NgModule\" class=\"code-anchor\">NgModule</a>({\n imports: [\n <a href=\"api/platform-browser/BrowserModule\" class=\"code-anchor\">BrowserModule</a>,\n <a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a>\n ],\n declarations: [\n AppComponent,\n HeroFormComponent\n ],\n providers: [],\n bootstrap: [ AppComponent ]\n})\nexport class AppModule { }\n\n\n</code-pane>\n\n <code-pane header=\"app.component.html\" path=\"forms/src/app/app.component.html\">\n<app-hero-form></app-hero-form>\n\n\n</code-pane>\n\n <code-pane header=\"app.component.ts\" path=\"forms/src/app/app.component.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a> } from '@angular/core';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-root',\n templateUrl: './app.component.html',\n styleUrls: ['./app.component.css']\n})\nexport class AppComponent { }\n\n\n</code-pane>\n\n <code-pane header=\"main.ts\" path=\"forms/src/main.ts\">\nimport { <a href=\"api/core/enableProdMode\" class=\"code-anchor\">enableProdMode</a> } from '@angular/core';\nimport { <a href=\"api/platform-browser-dynamic/platformBrowserDynamic\" class=\"code-anchor\">platformBrowserDynamic</a> } from '@angular/platform-browser-dynamic';\n\nimport { AppModule } from './app/app.module';\nimport { environment } from './environments/environment';\n\nif (environment.production) {\n <a href=\"api/core/enableProdMode\" class=\"code-anchor\">enableProdMode</a>();\n}\n\n<a href=\"api/platform-browser-dynamic/platformBrowserDynamic\" class=\"code-anchor\">platformBrowserDynamic</a>().bootstrapModule(AppModule);\n\n\n</code-pane>\n\n <code-pane header=\"forms.css\" path=\"forms/src/assets/forms.css\">\n.ng-valid[required], .ng-valid.required {\n border-left: 5px solid #42A948; /* green */\n}\n\n.ng-invalid:not(form) {\n border-left: 5px solid #a94442; /* red */\n}\n\n</code-pane>\n\n</code-tabs>\n\n \n</div>\n\n<!-- links to this doc:\n - guide/architecture-components\n - guide/built-in-directives\n - guide/example-apps-list\n - guide/form-validation\n - guide/forms-overview\n - guide/glossary\n - guide/npm-packages\n - guide/reactive-forms\n-->\n<!-- links from this doc:\n - api/common/NgForOf\n - api/core/Component\n - api/core/Directive#exportAs\n - api/core/NgModule\n - api/core/enableProdMode\n - api/forms/Form\n - api/forms/FormGroup\n - api/forms/FormsModule\n - api/forms/NgForm\n - api/forms/NgForm#ngSubmit\n - api/forms/NgForm#properties\n - api/forms/NgModel\n - api/forms/NgModelGroup\n - api/platform-browser-dynamic/platformBrowserDynamic\n - api/platform-browser/BrowserModule\n - guide/architecture\n - guide/architecture-components#data-binding\n - guide/forms#access-the-overall-form-status\n - guide/forms#add-a-new-hero\n - guide/forms#bind-input-controls-to-data-properties\n - guide/forms#build-a-template-driven-form\n - guide/forms#build-the-form\n - guide/forms#building-a-template-driven-form\n - guide/forms#create-visual-feedback-for-states\n - guide/forms#naming-control-elements\n - guide/forms#objectives\n - guide/forms#observe-control-states\n - guide/forms#prerequisites\n - guide/forms#respond-to-form-submission\n - guide/forms#show-and-hide-validation-error-messages\n - guide/forms#step-overview\n - guide/forms#submit-the-form-with-ngsubmit\n - guide/forms#summary\n - guide/forms#the-sample-application\n - guide/forms#track-control-states\n - guide/forms-overview\n - guide/glossary#template\n - guide/template-reference-variables\n - guide/template-syntax\n - guide/user-input\n - tutorial\n - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label\n - https://getbootstrap.com/css/\n - https://github.com/angular/angular/edit/master/aio/content/guide/forms.md?message=docs%3A%20describe%20your%20change...\n - https://www.typescriptlang.org/\n-->"
|
||
} |