include ../_util-fns :marked We’ve all used a form to log in, 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 to 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 .l-main-section :marked ## Template-driven forms Many of us will build forms by writing templates in the Angular template syntax 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 form. 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, boilerplate tasks we'd otherwise wrestle with ourselves. We'll discuss and learn to build a template-driven form that looks like this: 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 :marked We'll customize the colors and location of the "required" bar with standard CSS. :marked We'll build this form in 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. Change the form's display after submission. :marked ## Setup Create a new project folder (`angular2_forms`) and create 3 files: `pubspec.yaml`, `web/index.html`, and `web/main.dart`. (These files should be familiar from the [QuickStart](../quickstart.html).) Put these contents in the files: +makeTabs('forms/dart/pubspec.yaml, forms/dart/web/index.html, forms/dart/web/main.dart', ',initial,', 'pubspec.yaml, web/index.html, web/main.dart') .l-sub-section :marked Note the `platform_directives` entry in `pubspec.yaml`. It imports core directives and, more importantly for this chapter, **form directives**. :marked So that the code can run, let's create a stub for the `` component. Create a new directory called `lib`. In it, put a file called `hero_form_component.dart` with the following code: +makeExample('forms/dart/lib/hero_form_component_initial.dart', null, 'lib/hero_form_component.dart') :marked The app should now run, but it won't do anything interesting. Let's add some data. ## Create the Hero model class As users enter form data, we'll capture their changes and update an instance of a model. We can't lay out 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`). In the `lib` directory, add a file called `hero.dart` with the following code: +makeExample('forms/dart/lib/hero.dart', 'all', 'lib/hero.dart') :marked It's an anemic model with few requirements and no behavior. Perfect for our demo. The `alterEgo` is optional, so the constructor lets us omit it: note the `[]` in `[this.alterEgo]`. We can create a new hero like this: +makeExample('forms/dart/lib/hero.dart', 'newhero')(format=".") :marked .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. Edit `hero_form_component.dart`, replacing all of its contents with the following code: +makeExample('forms/dart/lib/hero_form_component.dart', null, 'lib/hero_form_component.dart') :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 covered in previous chapters. 1. The code imports a standard set of symbols from the Angular library. 1. The `@Component` selector value of "hero-form" means we can drop this form in a parent template with a `` tag. 1. The `templateUrl` property points to a separate file for template HTML called `hero_form_component.html`. 1. We defined dummy data for `model` and `powers`, as befits a demo. Down the road, we can inject a data service to get and save real data or perhaps expose these properties as inputs and outputs for binding to a parent component. None of this concerns us now, and these future changes won't affect our form. 1. We threw in a `diagnostic` property to return a string describing our model. It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later. Why isn't the template inline in the component file? Inline templates can be nice when they are short, but most form templates aren't short. Dart files generally aren't the best place to write (or read) large stretches of HTML, and few editors are much help with files that have a mix of HTML and code. It's also nice to have short files with a clear and obvious purpose. We made a good choice to put the HTML template elsewhere. Let's write it. .l-main-section :marked ## Create an initial HTML form template Create a new file under `lib` called `hero_form_component.html`, and put the following template code in it: +makeExample('forms/dart/lib/hero_form_component_initial.html', null, 'lib/hero_form_component.html') :marked That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and opening them up for user input in input boxes. The Name `` control has the HTML5 `required` attribute; the Alter Ego `` control does not because `alterEgo` is optional. We've got a Submit button at the bottom with some classes on it. **We are not using Angular yet**. There are no bindings. No extra directives. Just layout. The `container`,`form-group`, `form-control`, and `btn` classes are [Bootstrap](http://getbootstrap.com/) CSS. Purely cosmetic. We're using Bootstrap to gussy up our form. Hey, what's a form without a little style! .callout.is-important header Angular forms do not require a style library :marked Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or the styles of any external library. Angular apps can use any CSS library ... or none at all. :marked Let's add the stylesheet. 1. Download the Bootstrap stylesheet from https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css, and put it in the `web` directory. 2. Edit `web/index.html`, adding a link to `bootstrap.min.css`: - var stylePattern = { otl: /(<link rel.*$)/gm }; +makeExample('forms/dart/web/index.html', 'bootstrap-and-script', 'web/index.html (excerpt)', stylePattern)(format=".") [PENDING: runnable now? Remind about pub get? remind them to look in the browser console] .l-main-section :marked ## Add powers with ***ngFor** Our hero must 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 used before in [Displaying Data](./displaying-data.html). Add the following HTML *immediately below* the Alter Ego group. +makeExample('forms/dart/lib/hero_form_component_ngmodel_ngfor.html', 'powers', 'lib/hero_form_component.html (excerpt)')(format=".") :marked This code repeats the `