Search

#### Docs

- Guide
  - Overview
  - Setup
  - Learning Angular
  - Architecture
  - Displaying Data
  - User Input
  - Forms
  - Dependency Injection
  - Template Syntax
- Tutorial
  - Introduction
  - 0. The Starter App
  - 1. The Hero Editor
  - 2. Master/Detail
  - 3. Multiple Components
  - 4. Services
  - 5. Routing
  - 6. HTTP
- Advanced
  - Attribute Directives
  - Component Styles
  - Deployment
  - Hierarchical Injectors
  - HTTP Client
  - Lifecycle Hooks
  - Pipes
  - Router
  - Security
  - Structural Directives
  - Testing

#### Components

- Components Gallery

#### Resources

- Cheat Sheet
- Glossary
- FAQ
- Tools
- Community and Support

#### Reference

- Videos
- API Documentation

new_releases We're currently in the progress of migrating this site from Angular version 5.3.1 to 7.0.0. Package versions might be out-of-date or inconsistent! Visit the repo for more info.

# Forms 6.0

<?code-excerpt path-base=”examples/ng/doc/forms”?> Forms are the mainstay of business apps. You use forms to log in, submit a help request, place an order, book a flight, schedule a meeting, and perform countless other data-entry tasks.

In developing a form, it’s important to create a data-entry experience that guides the user efficiently and effectively through the workflow.

Developing forms requires design skills (which are out of scope for this page), as well as framework support for two-way data binding, change tracking, validation, and error handling, which you’ll learn about on this page.

This page shows you how to build a simple form from scratch. Along the way you’ll learn how to:

- Build an Angular form with a component and template.
- Use `ngModel` to create two-way data bindings for reading and writing input-control values.
- Track state changes and the validity of form controls.
- Provide visual feedback using special CSS classes that track the state of the controls.
- Display validation errors to users and enable/disable form controls.
- Share information across HTML elements using template reference variables.

You can run the live example (view source) in Plunker and download the code from there.

## Template-driven forms

You can build forms by writing templates in the Angular template syntax with the form-specific directives and techniques described in this page.

You can also use a reactive (or model-driven) approach to build forms. However, this page focuses on template-driven forms.

You can build almost any form with an Angular template—login forms, contact forms, and pretty much any business form. You 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.

Angular makes the process easy by handling many of the repetitive, boilerplate tasks you’d otherwise wrestle with yourself.

You’ll learn to build a template-driven form that looks like this:

The Hero Employment Agency uses this form to maintain personal information about heroes. Every hero needs a job. It’s the company mission to match the right hero with the right crisis.

Two of the three fields on this form are required. Following material design guidelines, required fields have an asterisk (*).

If you delete the hero name, the form displays a validation error in an attention-grabbing style:

Note that the Submit button is disabled, and the input control changes from green to red.

You’ll build this form in small steps:

1. Create the `Hero` model class.
2. Create the component that controls the form.
3. Create a template with the initial form layout.
4. Bind data properties to each form control using the ngModel two-way data-binding syntax.
5. Add an ngControl directive to each form-input control.
6. Add custom CSS to provide visual feedback.
7. Show and hide validation-error messages.
8. Handle form submission with ngSubmit.
9. Disable the form’s Submit button until the form is valid.

## Setup

Follow the setup instructions to create a new project named `forms`.

### Add angular_forms

<?code-excerpt path-base=”examples/ng/doc”?>

The Angular forms functionality is in the angular_forms library, which comes in its own package. Add the package to the pubspec dependencies:

<?code-excerpt “quickstart/pubspec.yaml” diff-with=”forms/pubspec.yaml” from=”dependencies” to=”angular_forms”?>

    --- quickstart/pubspec.yaml
    +++ forms/pubspec.yaml
    @@ -8,2 +8,3 @@
     dependencies:
    -  angular: ^7.0.2
    +  angular: ^6.0.1
    +  angular_forms: ^3.0.0

<?code-excerpt path-base=”examples/ng/doc/forms”?>

## Create a model

As users enter form data, you’ll capture their changes and update an instance of a model. You can’t lay out the form until you know what the model looks like.

A model can be as simple as a “property bag” that holds facts about a thing of importance for the app. That describes well the `Hero` class with its three required fields (`id`, `name`, `power`) and one optional field (`alterEgo`).

In the `lib` directory, create the following file with the given content:

<?code-excerpt “lib/src/hero.dart” title linenums?>

      class Hero {
        int id;
        String name, power, alterEgo;

        Hero(this.id, this.name, this.power, [this.alterEgo]);

        String toString() => '$id: $name ($alterEgo). Super power: $power';
      }

It’s an anemic model with few requirements and no behavior, good enough for the demo.

The `alterEgo` is optional, so the constructor lets you omit it; note the brackets in `[this.alterEgo]`.

You can create a new hero like this:

<?code-excerpt “lib/src/hero_form_component.dart” region=”SkyDog”?>

      var myHero =
          Hero(42, 'SkyDog', 'Fetch any object at any distance', 'Leslie Rollover');
      print('My hero is ${myHero.name}.'); // "My hero is SkyDog."

## Create a basic form

An Angular form has two parts: an HTML-based template and a component class to handle data and user interactions programmatically. Begin with the class because it states, in brief, what the hero editor can do.

### Create a form component

Create the following file with the given content:

<?code-excerpt “lib/src/hero_form_component.dart (v1)” plaster=”none” title?>

      import 'package:angular/angular.dart';
      import 'package:angular_forms/angular_forms.dart';

      import 'hero.dart';

      const List<String> _powers = [
        'Really Smart',
        'Super Flexible',
        'Super Hot',
        'Weather Changer'
      ];

      @Component(
        selector: 'hero-form',
        templateUrl: 'hero_form_component.html',
        directives: [coreDirectives, formDirectives],
      )
      class HeroFormComponent {
        Hero model = Hero(18, 'Dr IQ', _powers[0], 'Chuck Overstreet');
        bool submitted = false;

        List<String> get powers => _powers;

        void onSubmit() => submitted = true;
      }

There’s nothing special about this component, nothing form-specific, nothing to distinguish it from any component you’ve written before.

Understanding this component requires only the Angular concepts covered in previous pages.

- The code imports the main Angular library and the `Hero` model you just created.
- The `@Component` selector value of `hero-form` means you can drop this form in a parent template with a `<hero-form>` element.
- The `templateUrl` property points to a separate file (which you’ll create shortly) for the template HTML.

- You defined mock data for `model` and `powers`.

  Down the road, you can inject a data service to get and save real data or perhaps expose these properties as inputs and outputs (see Input and output properties in the Template Syntax page) for binding to a parent component. This is not a concern now and these future changes won’t affect the form.

### Revise the app component

`AppComponent` is the app’s root component. It will host the `HeroFormComponent`.

Replace the contents of the starter app version with the following:

<?code-excerpt “lib/app_component.dart” title?>

      import 'package:angular/angular.dart';

      import 'src/hero_form_component.dart';

      @Component(
        selector: 'my-app',
        template: '<hero-form></hero-form>',
        directives: [HeroFormComponent],
      )
      class AppComponent {}

### Create an initial form template

Create the template file with the following contents:

<?code-excerpt “lib/src/hero_form_component_1.html (start)” plaster=”none” title?>

      <div class="container">
        <h1>Hero Form</h1>
        <form>
          <div class="form-group">
            <label for="name">Name&nbsp;*</label>
            <input type="text" class="form-control" id="name" required>
          </div>
          <div class="form-group">
            <label for="alterEgo">Alter Ego</label>
            <input type="text" class="form-control" id="alterEgo">
          </div>
          <div class="row">
            <div class="col-auto">
              <button type="submit" class="btn btn-primary">Submit</button>
            </div>
            <small class="col text-right">*&nbsp;Required</small>
          </div>
        </form>
      </div>

The language is simply HTML5. You’re presenting two of the `Hero` fields, `name` and `alterEgo`, and opening them up for user input in input boxes.

The Name `<input>` control has the HTML5 `required` attribute; the Alter Ego `<input>` control does not because `alterEgo` is optional.

You added a Submit button at the bottom with some classes on it for styling.

You’re not using Angular yet. There are no bindings or extra directives, just layout.

In template driven forms, if you’ve imported the `angular_forms` library, you don’t have to do anything to the `<form>` tag in order to make use of the library capabilities. Continue on to see how this works.

open_in_browser Refresh the browser. You’ll see a simple, unstyled form.

### Style the form

The general CSS classes `container` and `btn` come from Bootstrap. Bootstrap also has form-specific classes including `form-control` and `form-group`. Together, these give the form a little style.

Angular makes no use of Bootstrap classes or the styles of any external library. Angular apps can use any CSS library or none at all.

Add Bootstrap styles by inserting the following link to the `<head>` of `index.html`:

<?code-excerpt “web/index.html (bootstrap)” title?>

      <link rel="stylesheet"
            href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css"
            integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M"
            crossorigin="anonymous">

open_in_browser Refresh the browser. You’ll see a form with style!

## Add powers with *ngFor

The hero must choose one superpower from a fixed list of agency-approved powers. You maintain that list internally (in `HeroFormComponent`).

You’ll add a `select` to the form and bind the options to the `powers` list using `ngFor`, a technique seen previously in the Displaying Data page.

Add the following HTML immediately below the Alter Ego group:

<?code-excerpt “lib/src/hero_form_component_1.html (powers)” title?>

      <div class="form-group">
        <label for="power">Hero Power&nbsp;*</label>
        <select class="form-control" id="power" required>
          <option *ngFor="let p of powers" [value]="p">{{p}}</option>
        </select>
      </div>

This code repeats the `<option>` tag for each power in the list of powers. The `p` template input variable is a different power in each iteration; you display its name using the interpolation syntax.

## Two-way data binding with ngModel

open_in_browser Running the app now is a bit disappointing.

You don’t see hero data because you’re not binding to the `Hero` yet. You know how to do that from earlier pages. Displaying Data teaches property binding. User Input shows how to listen for DOM events with an event binding and how to update a component property with the displayed value.

Now you need to display, listen, and extract at the same time.

You could use the techniques you already know, but instead you’ll use the new `[(ngModel)]` syntax, which makes binding the form to the model easy.

Find the `<input>` tag for Name and update it like this:

<?code-excerpt “lib/src/hero_form_component_2.html (name)” title?>

      <!-- TODO: remove the next diagnostic line -->
      <mark>{{model.name}}</mark><hr>
      <div class="form-group">
        <label for="name">Name&nbsp;*</label>
        <input type="text" class="form-control" id="name" required
               [(ngModel)]="model.name"
               ngControl="name">
      </div>

You added a diagnostic interpolation before the form-group so you can see what you’re doing. You left yourself a note to throw it away when you’re done.

Focus on the binding syntax: `[(ngModel)]="..."`.

open_in_browser Run the app now and type in the Name input, adding and deleting characters. You’ll see the characters appear and disappear from the diagnostic text. At some point it might look like this:

The diagnostic is evidence that values really are flowing from the input to the model and back again.

That’s two-way data binding. For more information, see Two-way binding with NgModel on the the Template Syntax page.

Notice that you also added an `ngControl` directive to the `<input>` tag and set it to “name”, which makes sense for the hero’s name. Any unique value will do, but using a descriptive name is helpful. Defining an `ngControl` directive is a requirement when using `[(ngModel)]` in combination with a form.

Internally, Angular creates `NgFormControl` instances and registers them with an `NgForm` directive that Angular attached to the `<form>` tag. Each `NgFormControl` is registered under the name you assigned to the `ngControl` directive. You’ll read more about `NgForm` later in this guide.

Add similar `[(ngModel)]` bindings and `ngControl` directives to Alter Ego and Hero Power.

Replace the diagnostic binding expression with `model`. This way you can confirm that two-way data binding works for the entire hero model.

After revision, the core of the form should look like this:

<?code-excerpt “lib/src/hero_form_component_3.html (controls)” title?>

      <!-- TODO: remove the next diagnostic line -->
      <mark>{{model}}</mark><hr>
      <div class="form-group">
        <label for="name">Name&nbsp;*</label>
        <input type="text" class="form-control" id="name" required
               [(ngModel)]="model.name"
               ngControl="name">
      </div>
      <div class="form-group">
        <label for="alterEgo">Alter Ego</label>
        <input type="text" class="form-control" id="alterEgo"
               [(ngModel)]="model.alterEgo"
               ngControl="alterEgo">
      </div>
      <div class="form-group">
        <label for="power">Hero Power&nbsp;*</label>
        <select class="form-control" id="power" required
                [(ngModel)]="model.power"
                ngControl="power">
          <option *ngFor="let p of powers" [value]="p">{{p}}</option>
        </select>
      </div>

- Each input element has an `id` property that is used by the `label` element’s `for` attribute to match the label to its input control.
- Each input element has a `ngControl` directive that is required by Angular forms to register the control with the form.

If you run the app now and change every hero model property, the form might display like this:

The diagnostic near the top of the form confirms that all of your changes are reflected in the model.

Delete the diagnostic binding from the template since it has served its purpose.

## Give visual feedback based on control state

Using CSS and class bindings, you can change a form control’s appearance to reflect its state.

### Track control state

An Angular form control can tell you if the user touched the control, if the value changed, or if the value became invalid.

Each control (NgControl) in an Angular form tracks its own state and makes the state available for inspection through the following field members:

- `dirty` and `pristine` indicate whether the control’s value has changed.
- `touched` and `untouched` indicate whether the control has been visited.
- `valid` reflects the control value’s validity.

### Style controls

The `valid` control property is the most interesting, because you want to send a strong visual signal when a control value is invalid. To create such visual feedback, you’ll use the Bootstrap custom-forms classes `is-valid` and `is-invalid`.

Add a template reference variable called `name` to the Name `<input>` tag. Use `name` and class bindings to conditionally assign the appropriate form validity class.

Temporarily add another template reference variable named `spy` to the Name `<input>` tag and use it to display the input’s CSS classes.

<?code-excerpt “lib/src/hero_form_component_4.html (name)” title?>

      <input type="text" class="form-control" id="name" required
             [(ngModel)]="model.name"
             #name="ngForm"
             #spy
             [class.is-valid]="name.valid"
             [class.is-invalid]="!name.valid"
             ngControl="name">
      <!-- TODO: remove the next diagnostic line -->
      {{spy.className}}

#### Template reference variables

The `spy` template reference variable gets bound to the `<input>` DOM element, whereas the `name` variable (through the `#name="ngForm"` syntax) gets bound to the NgModel associated with the input element.

Why “ngForm”? A Directive’s exportAs property tells Angular how to link the reference variable to the directive. You set `name` to “ngForm” because the ngModel directive’s `exportAs` property is “ngForm”.

open_in_browser Refresh the browser, and follow these steps:

1. Look at the Name input.
   - It has a green border.
   - Its has the classes `form-control` and `is-valid`.
2. Change the name by adding some characters. The classes remain the same.
3. Delete the name.
   - The input box border turns red.
   - The `is-invalid` class replaces `is-valid`.

Delete the `#spy` template reference variable and the diagnostic that uses it.

As an alternative to class bindings, you can use an NgClass directive to style a control. First, add the following method to set a control’s state-dependent CSS class names:

<?code-excerpt “lib/src/hero_form_component.dart (setCssValidityClass)” title?>

      Map<String, bool> setCssValidityClass(NgControl control) {
        final validityClass = control.valid == true ? 'is-valid' : 'is-invalid';
        return {validityClass: true};
      }

Use the map value returned by this method to bind to the NgClass directive — read more about this directive and its alternatives in the template syntax page.

<?code-excerpt “lib/src/hero_form_component.html (power)” title?>

      <select class="form-control" id="power" required
              [(ngModel)]="model.power"
              #power="ngForm"
              [ngClass]="setCssValidityClass(power)"
              ngControl="power">
        <option *ngFor="let p of powers" [value]="p">{{p}}</option>
      </select>

## Show and hide validation error messages

You can improve the form. The Name input is required, and clearing it turns the box outline red. That says something is wrong but the user doesn’t know what is wrong or what to do about it. Leverage the control’s state to reveal a helpful message.

### Use the valid and pristine states

When the user deletes the name, the form should look like this:

To achieve this effect, add the following `<div>` immediately after the Name `<input>`:

<?code-excerpt “lib/src/hero_form_component.html (hidden error message)” title?>

      <div [hidden]="name.valid || name.pristine" class="invalid-feedback">
        Name is required
      </div>

open_in_browser Refresh the browser and delete the Name input. The error message is displayed.

You control visibility of the error message by setting the hidden attribute of the `<div>` based on the state of the `name` control.

In this example, you hide the message when the control is valid or pristine — “pristine” means the user hasn’t changed the value since it was displayed in this form.

#### User experience is the developer’s choice

Some developers want the message to display at all times. If you ignore the `pristine` state, you would hide the message only when the value is valid. If you arrive in this component with a new (blank) hero or an invalid hero, you’ll see the error message immediately, before you’ve done anything.

Some developers want the message to display only when the user makes an invalid change. Hiding the message while the control is “pristine” achieves that goal. You’ll see the significance of this choice when you add a Clear button to the form.

The hero Alter Ego is optional so you can leave that be.

Hero Power selection is required. You can add the same kind of error message to the `<select>` if you want, but it’s not imperative because the selection box already constrains the power to valid values.

## Add a Clear button

Add a `clear()` method to the component class:

<?code-excerpt “lib/src/hero_form_component.dart (clear)” title?>

      void clear() {
        model.name = '';
        model.power = _powers[0];
        model.alterEgo = '';
      }

Add a Clear button with a `click` event binding, right after the Submit button:

<?code-excerpt “lib/src/hero_form_component_4.html (Clear button)” title?>

      <button (click)="clear()" type="button" class="btn">
        Clear
      </button>

open_in_browser Refresh the browser. Click the Clear button. The text fields go blank, and if you’ve changed the power, it reverts to its default value.

## Submit the form with ngSubmit

The user should be able to submit this form after filling it in. The Submit button at the bottom of the form does nothing on its own, but it will trigger a form submit because of its type (`type="submit"`).

A form submit is useless at the moment. To make it useful, assign form component’s `onSubmit()` method to the form’s `ngSubmit` event binding:

<?code-excerpt “lib/src/hero_form_component.html (ngSubmit)”?>

      <form (ngSubmit)="onSubmit()" #heroForm="ngForm">

Note the template reference variable `#heroForm`. As was explained earlier, the variable `heroForm` gets bound to the `NgForm` directive that governs the form as a whole.

#### The `NgForm` directive

Angular automatically creates and attaches an NgForm directive to the `<form>` tag.

The `NgForm` directive supplements the `form` element with additional features. It holds the controls you created for the elements with `ngModel` and `ngControl` directives, and monitors their properties, including their validity.

You’ll bind the form’s overall validity via the `heroForm` variable to the button’s `disabled` property:

<?code-excerpt “lib/src/hero_form_component.html” region=”Submit-button”?>

      <button [disabled]="!heroForm.form.valid" type="submit" class="btn btn-primary">
        Submit
      </button>

open_in_browser Refresh the browser. You’ll find that the button is enabled—although it doesn’t do anything useful yet.

Now if you delete the Name, you violate the “required” rule, which is duly noted in the error message. The Submit button is also disabled.

Not impressed? Think about it for a moment. What would you have to do to wire the button’s enable/disabled state to the form’s validity without Angular’s help?

For you, it was as simple as this:

1. Define a template reference variable on the (enhanced) form element.
2. Refer to that variable in a button many lines away.

## Display the model (optional)

Submitting the form has no visual effect at the moment.

As can be expected for a demo. Jazzing up the demo won’t teach you anything new about forms. But this is an opportunity to exercise some of your newly won binding skills. If you aren’t interested, skip to this page’s summary.

As a visual effect, you can hide the data entry area and display something else.

Wrap the form in a `<div>` and bind its `hidden` property to the `HeroFormComponent.submitted` property.

<?code-excerpt “lib/src/hero_form_component.html (excerpt)” region=”edit-div” title?>

      <div [hidden]="submitted">
        <h1>Hero Form</h1>
        <form (ngSubmit)="onSubmit()" #heroForm="ngForm">
          <!-- ··· -->
        </form>
      </div>

The form is visible from the start because the `submitted` property is false until you submit the form, as this fragment from the `HeroFormComponent` shows:

<?code-excerpt “lib/src/hero_form_component.dart (submitted)” plaster=”none” title?>

      bool submitted = false;

      void onSubmit() => submitted = true;

Now add the following HTML below the `<div>` wrapper you just wrote:

<?code-excerpt “lib/src/hero_form_component.html (submitted)” title?>

      <div [hidden]="!submitted">
        <h1>Hero data</h1>

        <table class="table">
          <tr>
            <th>Name</th>
            <td>{{model.name}}</td>
          </tr>
          <tr>
            <th>Alter Ego</th>
            <td>{{model.alterEgo}}</td>
          </tr>
          <tr>
            <th>Power</th>
            <td>{{model.power}}</td>
          </tr>
        </table>

        <button (click)="submitted=false" class="btn btn-primary">Edit</button>
      </div>

open_in_browser Refresh the browser, and submit the form. The `submitted` flag becomes true and the form disappears. You’ll see the hero model values (read-only) displayed in a table.

The view includes an Edit button whose click event binding clears the `submitted` flag. When you click the Edit button, the table disappears and the editable form reappears.

## Summary

Angular forms provide support for data modification, validation, and more. In this page, you learned how to use the following features:

- An HTML form template, and a form component class with an `@Component` annotation.
- Form submission, handled through an `ngSubmit` event binding.
- Template reference variables, such as `heroForm` and `name`.
- Two-way data bindings (`[(ngModel)]`).
- `NgControl` directives for validation and form-element change tracking.
- The `valid` property of input controls (accessed through template reference variables), for checking control validity and showing/hiding error messages.
- NgForm.form validity to set the Submit button’s enabled state.
- Custom CSS classes to provide visual feedback to users about control state.

The final project folder structure should look like this:

- angular_forms
  - lib
    - app_component.dart
    - src
      - hero.dart
      - hero_form_component.{dart,html}
  - web
    - index.html
    - main.dart
    - styles.css
  - pubspec.yaml

Here’s the code for the final version of the app: