include ../_util-fns :marked We’ve all used a form to login, submit a help request, place an order, book a flight, schedule a meeting and perform countless other data entry tasks. Forms are the mainstay of business applications. Any seasoned web developer can slap together an HTML form with all the right tags. It's more challenging to create a cohesive data entry experience that guides the user efficiently and effectively through the workflow behind the form. *That* takes design skills that are, to be frank, well out of scope for this chapter. It also takes framework support for **two-way data binding, change tracking, validation, and error handling** ... which we shall cover in this chapter on Angular forms. We will build a simple form from scratch, one step at a time. Along the way we'll learn - How to build an Angular form with a component and template - The `ngModel` two-way data binding syntax for reading and writing values to input controls - The `ngControl` directive to track the change state and validity of form controls - The special CSS classes that `ngControl` adds to form controls and how we can use them to provide strong visual feedback - How to display validation errors to users and enable/disable form controls - How to share information across controls with template local variables [Live Example](/resources/live-examples/forms/js/plnkr.html) .l-main-section :marked ## Template-Driven Forms Many of us will build forms by writing templates in the Angular [template syntax](./template-syntax.html) with the form-specific directives and techniques described in this chapter. .l-sub-section :marked That's not the only way to create a form but it's the way we'll cover in this chapter. :marked We can build almost any form we need with an Angular template — login forms, contact forms ... pretty much any business forms. We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors, conditionally enable or disable specific controls, trigger built-in visual feedback, and much more. It will be pretty easy because Angular handles many of the repetitive, boiler plate tasks we'd otherwise wrestle with ourselves. We'll discuss and learn to build the following template-driven form: figure.image-display img(src="/resources/images/devguide/forms/hero-form-1.png" width="400px" alt="Clean Form") :marked Here at the *Hero Employment Agency* we use this form to maintain personal information about the heroes in our stable. Every hero needs a job. It's our company mission to match the right hero with the right crisis! Two of the three fields on this form are required. Required fields have a green bar on the left to make them easy to spot. If we delete the hero name, the form displays a validation error in an attention grabbing style: figure.image-display img(src="/resources/images/devguide/forms/hero-form-2.png" width="400px" alt="Invalid, Name Required") :marked Note that the submit button is disabled and the "required" bar to the left of the input control changed from green to red. .l-sub-section p We'll' customize the colors and location of the "required" bar with standard CSS. :marked We will build this form in the following sequence of small steps 1. Create the `Hero` model class 1. Create the component that controls the form 1. Create a template with the initial form layout 1. Add the **ngModel** directive to each form input control 1. Add the **ngControl** directive to each form input control 1. Add custom CSS to provide visual feedback 1. Show and hide validation error messages 1. Handle form submission with **ngSubmit** 1. Disable the form’s submit button until the form is valid :marked ## Setup Create a new project folder (`angular2-forms`) and follow the steps in the [QuickStart](../quickstart.html). ## Create the Hero Model Class As users enter form data, we capture their changes and update an instance of a model. We can't layout the form until we know what the model looks like. A model can be as simple as a "property bag" that holds facts about a thing of application importance. That describes well our `Hero` class with its three required fields (`id`, `name`, `power`) and one optional field (`alterEgo`). Create a new file in the app folder called `hero.js` and give it the following constructor: +makeExample('forms/js/app/hero.js', null, 'app/hero.js') :marked It's an anemic model with few requirements and no behavior. Perfect for our demo. The `alterEgo` is optional and the constructor lets us omit it by being the last argument. We can create a new hero like this: code-example(format=""). var myHero = new Hero(42, 'SkyDog', 'Fetch any object at any distance', 'Leslie Rollover'); console.log('My hero is called ' + myHero.name); // "My hero is called SkyDog" :marked We update the `
` of the `index.html` to include this javascript file. +makeExample('forms/js/index.html', 'scripts-hero', 'index.html (excerpt)')(format=".") .l-main-section :marked ## Create a Form component An Angular form has two parts: an HTML-based template and a code-based Component to handle data and user interactions. We begin with the Component because it states, in brief, what the Hero editor can do. Create a new file called `hero-form.component.js` and give it the following definition: +makeExample('forms/js/app/hero-form.component.js', 'first', 'app/hero-form.component.js') :marked There’s nothing special about this component, nothing form-specific, nothing to distinguish it from any component we've written before. Understanding this component requires only the Angular 2 concepts we’ve learned in previous chapters 1. We use the `ng.core` object from the Angular library as we usually do. 1. The `Component()` selector value of "hero-form" means we can drop this form in a parent template with a `index.html
and add the following link to the <head>
.
+makeExample('forms/js/index.html', 'bootstrap')(format=".")
:marked
.l-main-section
:marked
## Add Powers with ***ngFor**
Our hero may choose one super power from a fixed list of Agency-approved powers.
We maintain that list internally (in `HeroFormComponent`).
We'll add a `select` to our
form and bind the options to the `powers` list using `NgFor`,
a technique we might have seen before in the [Displaying Data](./displaying-data.html) chapter.
Add the following HTML *immediately below* the *Alter Ego* group.
+makeExample('forms/js/app/hero-form.component.html', 'powers', 'app/hero-form.component.html (excerpt)')(format=".")
:marked
We are repeating the `