diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json index ed05038e70..cb2d533147 100644 --- a/public/docs/ts/latest/guide/_data.json +++ b/public/docs/ts/latest/guide/_data.json @@ -28,6 +28,11 @@ "title": "Template Syntax", "intro": "How to write templates that display data and consume user events with the help of data binding." }, + + "forms": { + "title": "Angular 2 Forms", + "intro": "Learn about the different approaches we can take when building forms and see examples of them in action." + }, "dependency-injection": { "title": "Dependency Injection", diff --git a/public/docs/ts/latest/guide/forms.jade b/public/docs/ts/latest/guide/forms.jade index f87192b595..22286dd88c 100644 --- a/public/docs/ts/latest/guide/forms.jade +++ b/public/docs/ts/latest/guide/forms.jade @@ -1,9 +1,464 @@ include ../../../../_includes/_util-fns -:markdown - # Forms - It's coming soon! - .l-main-section -:markdown - ## What's not to love? \ No newline at end of file + :markdown + Forms play an important role in Web applications whether it’s collecting data or allowing data to be modified or deleted. We’ve all used a form to login to an application, submit a help request to a website, manipulate business data and more. While creating custom forms in HTML is a relatively straightforward process, the complexity increases when a form requires data binding, event handling, validation rules and error messages. + + Angular 2 provides several key features that can be used to build any type of form your application may need whether it’s a large enterprise line of business form or a small form used to log a user into an application. Throughout this chapter we’ll learn about the different approaches we can take when building forms and see examples of them in action. + + The overall learning goals of this chapter include: + + - Learn how to build an Angular 2 form component and template. + - Learn data binding syntax that can be used to minimize the amount of code you write when building forms. + - Learn about key Angular 2 directives that can be used in forms. + - Learn how to display errors to users and enable/disable form controls. + - Learn what template local variables are and how they can be used. + - Learn about CSS classes that Angular 2 adds to form controls and understand how they can be used to provide visual feedback to users. + + Let’s get started by taking a look at the process we can follow to create template-driven forms in Angular 2. + + ## Introduction to Template-Driven Forms + + We can use template-driven forms to create login forms, contact forms and custom line of business forms in our Angular 2 applications. We can create any type of form layout, bind data to form controls, display validation errors, disable specific form controls when a form is invalid, provide visual feedback to users, plus more. In scenarios where we need to capture data from end users or allow them to modify existing data, template-driven forms provide a robust option that can be created quickly and easily using Angular 2 features. + + Here’s an example of a simple template-driven form in action. We’ll discuss the form throughout this chapter and learn how to build it. + + figure.image-display + img(src="/resources/images/devguide/forms/tdf-1.png" alt="Clean Form") + + :markdown + Here’s the same form displaying a validation error and providing additional visual feedback to the end user: + + figure.image-display + img(src="/resources/images/devguide/forms/tdf-2.png" alt="Invalid, Name Required") + + :markdown + If the user doesn’t satisfy all of the validation requirements for the form, the submit button will automatically be disabled and the left portion of the input control that has an error will change from green to red. The colors used, location of the colors and more can be customized using standard CSS. Required controls have a red left-border to make them easy to visually identify for end users: + + figure.image-display + img(src="/resources/images/devguide/forms/tdf-3.png" alt="Invalid Form") + + :markdown + What features does Angular 2 provide that we can use to create this type of template-driven form? We’ll answer this question and others by walking through the following steps: + + 1. Create an HTML form template + 1. Create a model class + 1. Create a form component + 1. Add the **ng-submit** directive to the form + 1. Add the **ng-control** directive to each form input control + 1. Add the **ng-model** directive to each form input control + 1. Disable the form’s submit button until the form is valid + 1. Add custom CSS to provide visual feedback + 1. Show and hide validation error messages + + The following sections provide a more detailed look at these steps and the code that we’ll need to write to make it all happen. Let’s start by looking at the initial form template. + + ### Create an HTML Form Template + + We can use a standard HTML form with the Angular template-driven approach. An example of a form template named **template-form.component.html** is shown next. The HTML content includes the form element and associated inputs as well as a section after the form that’s used to display data submitted by the end user. + + code-example(format="linenums" language="html"). + <div class="container"> + <div [hidden]="submitted"> + <h1>Template Driven Form</h1> + <form> + <div class="form-group"> + <label for="name">Name</label> + <input type="text" class="form-control" required> + </div> + <div class="form-group"> + <label for="alterEgo">Alter Ego</label> + <input type="text" class="form-control" required> + </div> + <div class="form-group"> + <label for="power">Hero Power</label> + <select class="form-control" required> + <option *ng-for="#p of powers" [value]="p">{{p}}</option> + </select> + </div> + <button type="submit" class="btn btn-default">Submit</button> + </form> + </div> + <div [hidden]="!submitted"> + <h2>You submitted the following:</h2> + <div class="row"> + <div class="col-md-2">Name</div> + <div class="col-md-10 pull-left">{{ model.name }}</div> + </div> + <div class="row"> + <div class="col-md-2">Alter Ego</div> + <div class="col-md-10 pull-left"> + {{ model.alterEgo }} + </div> + </div> + <div class="row"> + <div class="col-md-2">Power</div> + <div class="col-md-10 pull-left"> + {{ model.power }} + </div> + </div> + <br /> + <button class="btn btn-default" (click)="submitted=false">Edit</button> + </div> + </div> + + :markdown + The form captures Name, Alter Ego and Power values and makes all three of the inputs required by using the **required** attribute. The select control in the form iterates through an array of powers and displays them as select options using the Angular 2 **ng-for** directive. + + The application switches between the form view and the data display view by toggling a **submitted** property that we’ll discuss later in this chapter. The **submitted** property is bound to the **hidden** property of the div containers that wrap the form section and data display section. + + Now that the template for the form is in place, we can move on to discussing the model object that is bound to the form. + + ## Create a Model Class + + As users interacts with the form we’ll capture the data they enter or modify in instances of a “model” class. A model class is simply a class that holds application data. In this example **Hero** is the model class and it has **id**, **name**, **power**, and **alterEgo** properties. + + Here’s the complete code for the Hero model (hero.ts): + + ``` + export class Hero { + + constructor( + public id?: number, + public name?: string, + public power?: string, + public alterEgo?: string + ) { } + + } + ``` + The TypeScript compiler generates a public field for each **public** constructor parameter and assigns the parameter’s value to that field automatically. For example, TypeScript generates an **alterEgo** field to match the **public alterEgo** constructor parameter and sets the alterEgo field to the optional value of the fourth argument. This is a convenient way to initialize an object through the constructor with minimal code. + + Let’s create a form component that uses this **Hero** model class. + + ## Create a Form component + + The HTML form template shown earlier is placed directly in an Angular component using the **View** annotation’s **template** property. Alternatively, we can create a separate file and link it to the component using the **View** annotation’s **templateUrl** property. Which approach is better? There’s no “right” answer since it’s very subjective, but in cases where a template contains a lot of HTML content, having a separate template file can be helpful and minimize the overall size of the component. + + In this example we’ll link the template to a component named **TemplateFormComponent (template-form.component.ts)** using the **templateUrl** property of **View** annotation. The complete code for **TemplateFormComponent** is shown next: + ``` + import {Component, View, NgFor, FORM_DIRECTIVES} from 'angular2/angular2'; + + import { Hero } from './hero'; + + @Component({ + selector: 'template-driven-form', + templateUrl: 'app/template-form.component.html', + directives: [FORM_DIRECTIVES, NgFor] + }) + export class TemplateFormComponent { + + + model: Hero; + powers: string[]; + submitted: boolean = false; + + constructor() { + this.model = new Hero(18,'Dr IQ', 'Really Smart', 'Chuck Overstreet'); + + this.powers = ['Really Smart', 'Super Flexible', + 'Super Hot', 'Weather Changer']; + } + + onSubmit() { + this.submitted = true; + } + + } + ``` + We can see that there’s nothing unique about this component even though we’re using it to create a form. Many of the Angular 2 concepts we’ve already learned apply. Here are few of the key features shown in the component: + + 1. We import **NgFor, Component, View** and **FORM_DIRECTIVES** as well as the the **Hero** model class. Ng + 1. We add the **Component** selector value of “template-driven-form”. We also define the form template **(template-form.component.html)** using the **templateUrl** property and all of the directives we’ll use in the form template using the **directives** property. + 1. The **TemplateFormComponent** class **model, powers** and **submitted** properties defined. + 1. The constructor initializes the model and powers properties with values. + + We’ve now linked the form template to the form component and integrated the **Hero** model class into the component. The next step is to integrate Angular 2 directives into the form. + + ## Add the ng-submit Directive to the Form + + We’ll now shift our attention back to the form template **(template-form.component.html)** created earlier. Although the form is linked to the component, it won’t do much at this point aside from showing the different form controls. Angular 2 directives have to be added into the form so that we can bind the Hero model and perform other tasks such as validation. + + To start, we can add the **ng-submit** event to the **form** element and hook it to the **onSubmit()** function shown earlier in the **TemplateFormComponent class**: + ``` +