parent
d33a381a6c
commit
4084a725fd
@ -1,5 +1,5 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import {bootstrap, Component} from 'angular2/angular2'
|
import {Component} from 'angular2/core';
|
||||||
import {HeroFormComponent} from './hero-form.component'
|
import {HeroFormComponent} from './hero-form.component'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -7,6 +7,4 @@ import {HeroFormComponent} from './hero-form.component'
|
|||||||
template: '<hero-form></hero-form>',
|
template: '<hero-form></hero-form>',
|
||||||
directives: [HeroFormComponent]
|
directives: [HeroFormComponent]
|
||||||
})
|
})
|
||||||
class AppComponent { }
|
export class AppComponent { }
|
||||||
|
|
||||||
bootstrap(AppComponent);
|
|
5
public/docs/_examples/forms/ts/app/boot.ts
Normal file
5
public/docs/_examples/forms/ts/app/boot.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// #docregion
|
||||||
|
import {bootstrap} from 'angular2/platform/browser';
|
||||||
|
import {AppComponent} from './app.component';
|
||||||
|
|
||||||
|
bootstrap(AppComponent);
|
@ -4,16 +4,16 @@
|
|||||||
<!-- #docregion edit-div -->
|
<!-- #docregion edit-div -->
|
||||||
<div [hidden]="submitted">
|
<div [hidden]="submitted">
|
||||||
<h1>Hero Form</h1>
|
<h1>Hero Form</h1>
|
||||||
<!-- #docregion ng-submit -->
|
<!-- #docregion ngSubmit -->
|
||||||
<form (ng-submit)="onSubmit()" #hf="form">
|
<form (ngSubmit)="onSubmit()" #heroForm="ngForm">
|
||||||
|
<!-- #enddocregion ngSubmit -->
|
||||||
<!-- #enddocregion edit-div -->
|
<!-- #enddocregion edit-div -->
|
||||||
<!-- #enddocregion ng-submit -->
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
<!-- #docregion name-with-error-msg -->
|
<!-- #docregion name-with-error-msg -->
|
||||||
<input type="text" class="form-control" required
|
<input type="text" class="form-control" required
|
||||||
[(ng-model)]="model.name"
|
[(ngModel)]="model.name"
|
||||||
ng-control="name" #name="form" >
|
ngControl="name" #name="ngForm" >
|
||||||
<div [hidden]="name.valid" class="alert alert-danger">
|
<div [hidden]="name.valid" class="alert alert-danger">
|
||||||
Name is required
|
Name is required
|
||||||
</div>
|
</div>
|
||||||
@ -23,16 +23,16 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="alterEgo">Alter Ego</label>
|
<label for="alterEgo">Alter Ego</label>
|
||||||
<input type="text" class="form-control"
|
<input type="text" class="form-control"
|
||||||
[(ng-model)]="model.alterEgo"
|
[(ngModel)]="model.alterEgo"
|
||||||
ng-control="alterEgo" >
|
ngControl="alterEgo" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="power">Hero Power</label>
|
<label for="power">Hero Power</label>
|
||||||
<select class="form-control" required
|
<select class="form-control" required
|
||||||
[(ng-model)]="model.power"
|
[(ngModel)]="model.power"
|
||||||
ng-control="power" #power="form" >
|
ngControl="power" #power="ngForm" >
|
||||||
<option *ng-for="#p of powers" [value]="p">{{p}}</option>
|
<option *ngFor="#p of powers" [value]="p">{{p}}</option>
|
||||||
</select>
|
</select>
|
||||||
<div [hidden]="power.valid" class="alert alert-danger">
|
<div [hidden]="power.valid" class="alert alert-danger">
|
||||||
Power is required
|
Power is required
|
||||||
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
<!-- #docregion submit-button -->
|
<!-- #docregion submit-button -->
|
||||||
<button type="submit" class="btn btn-default"
|
<button type="submit" class="btn btn-default"
|
||||||
[disabled]="!hf.form.valid">Submit</button>
|
[disabled]="!heroForm.form.valid">Submit</button>
|
||||||
<!-- #enddocregion submit-button -->
|
<!-- #enddocregion submit-button -->
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -110,7 +110,7 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="power">Hero Power</label>
|
<label for="power">Hero Power</label>
|
||||||
<select class="form-control" required>
|
<select class="form-control" required>
|
||||||
<option *ng-for="#p of powers" [value]="p">{{p}}</option>
|
<option *ngFor="#p of powers" [value]="p">{{p}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -128,29 +128,29 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Hero Form</h1>
|
<h1>Hero Form</h1>
|
||||||
<form>
|
<form>
|
||||||
<!-- #docregion ng-model-2-->
|
<!-- #docregion ngModel-2-->
|
||||||
{{diagnostic}}
|
{{diagnostic}}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
<input type="text" class="form-control" required
|
<input type="text" class="form-control" required
|
||||||
[(ng-model)]="model.name" >
|
[(ngModel)]="model.name" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="alterEgo">Alter Ego</label>
|
<label for="alterEgo">Alter Ego</label>
|
||||||
<input type="text" class="form-control"
|
<input type="text" class="form-control"
|
||||||
[(ng-model)]="model.alterEgo">
|
[(ngModel)]="model.alterEgo">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="power">Hero Power</label>
|
<label for="power">Hero Power</label>
|
||||||
<select class="form-control" required
|
<select class="form-control" required
|
||||||
[(ng-model)]="model.power" >
|
[(ngModel)]="model.power" >
|
||||||
<option *ng-for="#p of powers" [value]="p">{{p}}</option>
|
<option *ngFor="#p of powers" [value]="p">{{p}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- #enddocregion ng-model-2-->
|
<!-- #enddocregion ngModel-2-->
|
||||||
<button type="submit" class="btn btn-default">Submit</button>
|
<button type="submit" class="btn btn-default">Submit</button>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
@ -159,37 +159,37 @@
|
|||||||
|
|
||||||
<!-- EXTRA MATERIAL FOR DOCUMENTATION -->
|
<!-- EXTRA MATERIAL FOR DOCUMENTATION -->
|
||||||
<hr>
|
<hr>
|
||||||
<!-- #docregion ng-model-1-->
|
<!-- #docregion ngModel-1-->
|
||||||
<input type="text" class="form-control" required
|
<input type="text" class="form-control" required
|
||||||
[(ng-model)]="model.name" >
|
[(ngModel)]="model.name" >
|
||||||
TODO: remove this: {{model.name}}
|
TODO: remove this: {{model.name}}
|
||||||
<!-- #enddocregion ng-model-1-->
|
<!-- #enddocregion ngModel-1-->
|
||||||
<hr>
|
<hr>
|
||||||
<!-- #docregion ng-model-3-->
|
<!-- #docregion ngModel-3-->
|
||||||
<input type="text" class="form-control" required
|
<input type="text" class="form-control" required
|
||||||
[ng-model]="model.name"
|
[ngModel]="model.name"
|
||||||
(ng-model-change)="model.name = $event" >
|
(ngModelChange)="model.name = $event" >
|
||||||
TODO: remove this: {{model.name}}
|
TODO: remove this: {{model.name}}
|
||||||
<!-- #enddocregion ng-model-3-->
|
<!-- #enddocregion ngModel-3-->
|
||||||
<hr>
|
<hr>
|
||||||
<form>
|
<form>
|
||||||
<!-- #docregion ng-control-1 -->
|
<!-- #docregion ngControl-1 -->
|
||||||
<input type="text" class="form-control" required
|
<input type="text" class="form-control" required
|
||||||
[(ng-model)]="model.name"
|
[(ngModel)]="model.name"
|
||||||
ng-control="name" >
|
ngControl="name" >
|
||||||
<!-- #enddocregion ng-control-1 -->
|
<!-- #enddocregion ngControl-1 -->
|
||||||
<hr>
|
<hr>
|
||||||
<!-- #docregion ng-control-2 -->
|
<!-- #docregion ngControl-2 -->
|
||||||
<input type="text" class="form-control" required
|
<input type="text" class="form-control" required
|
||||||
[(ng-model)]="model.name"
|
[(ngModel)]="model.name"
|
||||||
ng-control="name" #spy >
|
ngControl="name" #spy >
|
||||||
<br>TODO: remove this: {{spy.className}}
|
<br>TODO: remove this: {{spy.className}}
|
||||||
<!-- #enddocregion ng-control-2 -->
|
<!-- #enddocregion ngControl-2 -->
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<hr>
|
<hr>
|
||||||
Name via form.controls = {{showFormControls(hf)}}
|
Name via form.controls = {{showFormControls(heroForm)}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
@ -1,8 +1,8 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion
|
// #docregion
|
||||||
// #docregion first, final
|
// #docregion first, final
|
||||||
import {Component} from 'angular2/angular2';
|
import {Component} from 'angular2/core';
|
||||||
|
import {NgForm} from 'angular2/common';
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -32,10 +32,10 @@ export class HeroFormComponent {
|
|||||||
|
|
||||||
// Reveal in html:
|
// Reveal in html:
|
||||||
// AlterEgo via form.controls = {{showFormControls(hf)}}
|
// AlterEgo via form.controls = {{showFormControls(hf)}}
|
||||||
showFormControls(form){
|
showFormControls(form:NgForm){
|
||||||
return form.controls.alterEgo &&
|
return form.controls['alterEgo'] &&
|
||||||
// #docregion form-controls
|
// #docregion form-controls
|
||||||
form.controls.name.value; // Dr. IQ
|
form.controls['name'].value; // Dr. IQ
|
||||||
// #enddocregion form-controls
|
// #enddocregion form-controls
|
||||||
}
|
}
|
||||||
/////////////////////////////
|
/////////////////////////////
|
@ -5,19 +5,19 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>Hero Form</title>
|
<title>Hero Form</title>
|
||||||
<!-- #docregion bootstrap -->
|
<!-- #docregion bootstrap -->
|
||||||
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
|
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
|
||||||
<!-- #enddocregion bootstrap -->
|
<!-- #enddocregion bootstrap -->
|
||||||
<!-- #docregion styles -->
|
<!-- #docregion styles -->
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
<!-- #enddocregion styles -->
|
<!-- #enddocregion styles -->
|
||||||
|
|
||||||
<script src="../node_modules/systemjs/dist/system.src.js"></script>
|
<script src="/node_modules/systemjs/dist/system.src.js"></script>
|
||||||
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
|
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
|
||||||
<script>
|
<script>
|
||||||
System.config({
|
System.config({
|
||||||
packages: {'app': {defaultExtension: 'js'}}
|
packages: {'app': {defaultExtension: 'js'}}
|
||||||
});
|
});
|
||||||
System.import('app/app');
|
System.import('app/boot');
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
@ -4,19 +4,12 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"tsc": "tsc -p src -w",
|
"tsc": "tsc",
|
||||||
"start": "live-server --open=src"
|
"tsc:w": "tsc -w",
|
||||||
|
"lite": "lite-server",
|
||||||
|
"both": "concurrent \"npm run tsc:w\" \"npm run lite\" "
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC"
|
||||||
"dependencies": {
|
|
||||||
"angular2": "2.0.0-alpha.44",
|
|
||||||
"bootstrap": "^3.3.5",
|
|
||||||
"systemjs": "0.19.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"live-server": "^0.8.1",
|
|
||||||
"typescript": "^1.6.2"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ES5",
|
|
||||||
"module": "commonjs",
|
|
||||||
"sourceMap": true,
|
|
||||||
"emitDecoratorMetadata": true,
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"removeComments": false,
|
|
||||||
"noImplicitAny": false
|
|
||||||
}
|
|
||||||
}
|
|
16
public/docs/_examples/forms/ts/tsconfig.json
Normal file
16
public/docs/_examples/forms/ts/tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES5",
|
||||||
|
"module": "system",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"sourceMap": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"removeComments": false,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"suppressImplicitAnyIndexErrors": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
@ -15,13 +15,14 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"angular2": "^2.0.0-alpha.51",
|
"angular2": "2.0.0-alpha.52",
|
||||||
"systemjs": "0.19.6",
|
"systemjs": "0.19.6",
|
||||||
"es6-promise": "^3.0.2",
|
"es6-promise": "^3.0.2",
|
||||||
"es6-shim": "^0.33.3",
|
"es6-shim": "^0.33.3",
|
||||||
"reflect-metadata": "0.1.2",
|
"reflect-metadata": "0.1.2",
|
||||||
"rxjs": "5.0.0-alpha.14",
|
"rxjs": "5.0.0-alpha.14",
|
||||||
"zone.js": "0.5.8"
|
"zone.js": "0.5.8",
|
||||||
|
"bootstrap": "^3.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^1.0.0",
|
"concurrently": "^1.0.0",
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
include ../../../../_includes/_util-fns
|
include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
<!-- http://plnkr.co/edit/wg154K -->
|
|
||||||
:marked
|
:marked
|
||||||
We’ve all used a form to login, submit a help request, place an order, book a flight,
|
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.
|
schedule a meeting and perform countless other data entry tasks.
|
||||||
@ -20,17 +19,17 @@ include ../../../../_includes/_util-fns
|
|||||||
|
|
||||||
- How to build an Angular form with a component and template
|
- How to build an Angular form with a component and template
|
||||||
|
|
||||||
- The `ng-model` two-way data binding syntax for reading and writing values to input controls
|
- The `ngModel` two-way data binding syntax for reading and writing values to input controls
|
||||||
|
|
||||||
- The `ng-control` directive to track the change state and validity of form controls
|
- The `ngControl` directive to track the change state and validity of form controls
|
||||||
|
|
||||||
- The special CSS classes that `ng-control` adds to form controls and how we can use them to provide strong visual feedback
|
- 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 display validation errors to users and enable/disable form controls
|
||||||
|
|
||||||
- How to share information across controls with template local variables
|
- How to share information across controls with template local variables
|
||||||
|
|
||||||
[Live Example](/resources/live-examples/forms/ts/src/plnkr.html)
|
[Live Example](/resources/live-examples/forms/ts/plnkr.html)
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Template-Driven Forms
|
## Template-Driven Forms
|
||||||
@ -51,7 +50,7 @@ include ../../../../_includes/_util-fns
|
|||||||
We'll discuss and learn to build the following template-driven form:
|
We'll discuss and learn to build the following template-driven form:
|
||||||
|
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src="/resources/images/devguide/forms/hf-1.png" width="400px" alt="Clean Form")
|
img(src="/resources/images/devguide/forms/heroForm-1.png" width="400px" alt="Clean Form")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Here at the *Hero Employment Agency* we use this form to maintain personal information about the
|
Here at the *Hero Employment Agency* we use this form to maintain personal information about the
|
||||||
@ -62,7 +61,7 @@ figure.image-display
|
|||||||
If we delete the hero name, the form displays a validation error in an attention grabbing style:
|
If we delete the hero name, the form displays a validation error in an attention grabbing style:
|
||||||
|
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src="/resources/images/devguide/forms/hf-2.png" width="400px" alt="Invalid, Name Required")
|
img(src="/resources/images/devguide/forms/heroForm-2.png" width="400px" alt="Invalid, Name Required")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Note that the submit button is disabled and the "required" bar to the left of the input control changed from green to red.
|
Note that the submit button is disabled and the "required" bar to the left of the input control changed from green to red.
|
||||||
@ -76,11 +75,11 @@ figure.image-display
|
|||||||
1. Create the `Hero` model class
|
1. Create the `Hero` model class
|
||||||
1. Create the component that controls the form
|
1. Create the component that controls the form
|
||||||
1. Create a template with the initial form layout
|
1. Create a template with the initial form layout
|
||||||
1. Add the **ng-model** directive to each form input control
|
1. Add the **ngModel** directive to each form input control
|
||||||
1. Add the **ng-control** 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. Add custom CSS to provide visual feedback
|
||||||
1. Show and hide validation error messages
|
1. Show and hide validation error messages
|
||||||
1. Handle form submission with **ng-submit**
|
1. Handle form submission with **ngSubmit**
|
||||||
1. Disable the form’s submit button until the form is valid
|
1. Disable the form’s submit button until the form is valid
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
@ -98,7 +97,7 @@ figure.image-display
|
|||||||
|
|
||||||
Create a new file in the app folder called `hero.ts` and give it the following class definition:
|
Create a new file in the app folder called `hero.ts` and give it the following class definition:
|
||||||
|
|
||||||
+makeExample('forms/ts/src/app/hero.ts', null, 'app/hero.ts')
|
+makeExample('forms/ts/app/hero.ts', null, 'app/hero.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
It's an anemic model with few requirements and no behavior. Perfect for our demo.
|
It's an anemic model with few requirements and no behavior. Perfect for our demo.
|
||||||
@ -109,10 +108,11 @@ figure.image-display
|
|||||||
The `alterEgo` is optional and the constructor lets us omit it; note the (?) in `alterEgo?`.
|
The `alterEgo` is optional and the constructor lets us omit it; note the (?) in `alterEgo?`.
|
||||||
|
|
||||||
We can create a new hero like this:
|
We can create a new hero like this:
|
||||||
```
|
code-example(format="").
|
||||||
let myHero = new Hero(42, 'SkyDog', 'Fetch any object at any distance', 'Leslie Rollover');
|
let 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"
|
console.log('My hero is called ' + myHero.name); // "My hero is called SkyDog"
|
||||||
```
|
:marked
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
@ -124,7 +124,7 @@ figure.image-display
|
|||||||
|
|
||||||
Create a new file called `hero-form.component.ts` and give it the following definition:
|
Create a new file called `hero-form.component.ts` and give it the following definition:
|
||||||
|
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.ts', 'first', 'app/hero-form.component.ts')
|
+makeExample('forms/ts/app/hero-form.component.ts', 'first', 'app/hero-form.component.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
There’s nothing special about this component, nothing form-specific, nothing to distinguish it from any component we've written before.
|
There’s nothing special about this component, nothing form-specific, nothing to distinguish it from any component we've written before.
|
||||||
@ -155,16 +155,16 @@ figure.image-display
|
|||||||
|
|
||||||
We made a good choice to put the HTML template elsewhere.
|
We made a good choice to put the HTML template elsewhere.
|
||||||
We'll write that template in a moment. Before we do, we'll take a step back
|
We'll write that template in a moment. Before we do, we'll take a step back
|
||||||
and revise the `app.ts` to make use of our new `HeroFormComponent`.
|
and revise the `app.component.ts` to make use of our new `HeroFormComponent`.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Revise the *app.ts*
|
## Revise the *app.component.ts*
|
||||||
|
|
||||||
`app.ts` is the application's root component. It will host our new `HeroFormComponent`.
|
`app.component.ts` is the application's root component. It will host our new `HeroFormComponent`.
|
||||||
|
|
||||||
Replace the contents of the "QuickStart" version with the following:
|
Replace the contents of the "QuickStart" version with the following:
|
||||||
+makeExample('forms/ts/src/app/app.ts', null, 'app/app.ts')
|
+makeExample('forms/ts/app/app.component.ts', null, 'app/app.component.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
@ -184,7 +184,7 @@ figure.image-display
|
|||||||
|
|
||||||
Create a new template file called `hero-form.component.html` and give it the following definition:
|
Create a new template file called `hero-form.component.html` and give it the following definition:
|
||||||
|
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'start', 'app/hero-form.component.html')
|
+makeExample('forms/ts/app/hero-form.component.html', 'start', 'app/hero-form.component.html')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and
|
That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and
|
||||||
@ -213,15 +213,15 @@ figure.image-display
|
|||||||
Let's add the stylesheet.
|
Let's add the stylesheet.
|
||||||
|
|
||||||
ol
|
ol
|
||||||
li Open a terminal window and enter the command:
|
li Open a terminal window in the application root folder and enter the command:
|
||||||
code-example(language="html" escape="html").
|
code-example(language="html" escape="html").
|
||||||
npm install bootstrap --save
|
npm install bootstrap --save
|
||||||
li Open <code>index.html</code> and add the following link to the <code><head></code>.
|
li Open <code>index.html</code> and add the following link to the <code><head></code>.
|
||||||
+makeExample('forms/ts/src/index.html', 'bootstrap')(format=".")
|
+makeExample('forms/ts/index.html', 'bootstrap')(format=".")
|
||||||
:marked
|
:marked
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Add Powers with ***ng-for**
|
## Add Powers with ***ngFor**
|
||||||
Our hero may choose one super power from a fixed list of Agency-approved powers.
|
Our hero may choose one super power from a fixed list of Agency-approved powers.
|
||||||
We maintain that list internally (in `HeroFormComponent`).
|
We maintain that list internally (in `HeroFormComponent`).
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ ol
|
|||||||
a technique we might have seen before in the [Displaying Data](./displaying-data.html) chapter.
|
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.
|
Add the following HTML *immediately below* the *Alter Ego* group.
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'powers', 'app/hero-form.component.html (excerpt)')
|
+makeExample('forms/ts/app/hero-form.component.html', 'powers', 'app/hero-form.component.html (excerpt)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We are repeating the `<options>` tag for each power in the list of Powers.
|
We are repeating the `<options>` tag for each power in the list of Powers.
|
||||||
@ -239,11 +239,11 @@ ol
|
|||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Two-way data binding with ***ng-model**
|
## Two-way data binding with ***ngModel**
|
||||||
Running the app right now would be disappointing.
|
Running the app right now would be disappointing.
|
||||||
|
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src="/resources/images/devguide/forms/hf-3.png" width="400px" alt="Early form with no binding")
|
img(src="/resources/images/devguide/forms/heroForm-3.png" width="400px" alt="Early form with no binding")
|
||||||
:marked
|
:marked
|
||||||
We don't see hero data because we are not binding to the `Hero` yet.
|
We don't see hero data because we are not binding to the `Hero` yet.
|
||||||
We know how to do that from earlier chapters.
|
We know how to do that from earlier chapters.
|
||||||
@ -259,7 +259,7 @@ figure.image-display
|
|||||||
|
|
||||||
Find the `<input>` tag for the "Name" and update it like this
|
Find the `<input>` tag for the "Name" and update it like this
|
||||||
|
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-1')
|
+makeExample('forms/ts/app/hero-form.component.html', 'ngModel-1','app/hero-form.component.html (excerpt)')(format=".")
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
@ -268,42 +268,42 @@ figure.image-display
|
|||||||
We left ourselves a note to throw it way when we're done.
|
We left ourselves a note to throw it way when we're done.
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Focus on the binding syntax: `[(ng-model)]="..."`.
|
Focus on the binding syntax: `[(ngModel)]="..."`.
|
||||||
|
|
||||||
If we ran the app right now and started typing in the *Name* input box,
|
If we ran the app right now and started typing in the *Name* input box,
|
||||||
adding and deleting characters, we'd see them appearing and disappearing
|
adding and deleting characters, we'd see them appearing and disappearing
|
||||||
from the interpolated text.
|
from the interpolated text.
|
||||||
At some point it might look like this.
|
At some point it might look like this.
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src="/resources/images/devguide/forms/ng-model-in-action.png" width="400px" alt="ng-model in action")
|
img(src="/resources/images/devguide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action")
|
||||||
:marked
|
:marked
|
||||||
The diagnostic is evidence that we really are flowing values from the input box to the model and
|
The diagnostic is evidence that we really are flowing values from the input box to the model and
|
||||||
back again. **That's two-way data binding!**
|
back again. **That's two-way data binding!**
|
||||||
|
|
||||||
Let's add similar `[(ng-model)]` bindings to *Alter Ego* and *Hero Power*.
|
Let's add similar `[(ngModel)]` bindings to *Alter Ego* and *Hero Power*.
|
||||||
We'll ditch the input box binding message
|
We'll ditch the input box binding message
|
||||||
and add a new binding at the top to the component's `diagnostic` property.
|
and add a new binding at the top to the component's `diagnostic` property.
|
||||||
Then we can confirm that two-way data binding works *for the entire Hero model*.
|
Then we can confirm that two-way data binding works *for the entire Hero model*.
|
||||||
|
|
||||||
After revision the core of our form should have three `[(ng-model)]` bindings that
|
After revision the core of our form should have three `[(ngModel)]` bindings that
|
||||||
look much like this:
|
look much like this:
|
||||||
|
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-2', 'app/hero-form.component.html (excerpt)')
|
+makeExample('forms/ts/app/hero-form.component.html', 'ngModel-2', 'app/hero-form.component.html (excerpt)')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
If we ran the app right now and changed every Hero model property, the form might display like this:
|
If we ran the app right now and changed every Hero model property, the form might display like this:
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src="/resources/images/devguide/forms/ng-model-in-action-2.png" width="400px" alt="ng-model in super action")
|
img(src="/resources/images/devguide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in super action")
|
||||||
:marked
|
:marked
|
||||||
The diagnostic near the top of the form
|
The diagnostic near the top of the form
|
||||||
confirms that all of our changes are reflected in the model.
|
confirms that all of our changes are reflected in the model.
|
||||||
|
|
||||||
** We're done with the diagnostic binding. Delete it now.**
|
**Delete** the `{{diagnostic}}` binding at the top as it has served its purpose.
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
### Inside [(ng-model)]
|
### Inside [(ngModel)]
|
||||||
*This section is an optional deep dive into [(ng-model)]. Not interested? Skip ahead!*
|
*This section is an optional deep dive into [(ngModel)]. Not interested? Skip ahead!*
|
||||||
|
|
||||||
The punctuation in the binding syntax, <span style="font-family:courier"><b>[()]</b></span>, is a good clue to what's going on.
|
The punctuation in the binding syntax, <span style="font-family:courier"><b>[()]</b></span>, is a good clue to what's going on.
|
||||||
|
|
||||||
@ -320,23 +320,23 @@ figure.image-display
|
|||||||
|
|
||||||
In fact, we can break the `NgModel` binding into its two separate modes
|
In fact, we can break the `NgModel` binding into its two separate modes
|
||||||
as we do in this re-write of the "Name" `<input>` binding:
|
as we do in this re-write of the "Name" `<input>` binding:
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-3')
|
+makeExample('forms/ts/app/hero-form.component.html', 'ngModel-3','app/hero-form.component.html (excerpt)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
<br>The Property Binding should feel familiar. The Event Binding might seem strange.
|
<br>The Property Binding should feel familiar. The Event Binding might seem strange.
|
||||||
|
|
||||||
The `ng-model-change` is not an `<input>` element event.
|
The `ngModelChange` is not an `<input>` element event.
|
||||||
It is actually an event property of the `NgModel` directive.
|
It is actually an event property of the `NgModel` directive.
|
||||||
When Angular sees a binding target in the form <span style="font-family:courier">[(abc)]</span>,
|
When Angular sees a binding target in the form <span style="font-family:courier">[(abc)]</span>,
|
||||||
it expects the `abc` directive to have an `abc` input property and an `abc-change` output property.
|
it expects the `abc` directive to have an `abc` input property and an `abc-change` output property.
|
||||||
|
|
||||||
The other oddity is the template expression, `model.name = $event`.
|
The other oddity is the template expression, `model.name = $event`.
|
||||||
We're used to seeing an `$event` object coming from a DOM event.
|
We're used to seeing an `$event` object coming from a DOM event.
|
||||||
The `ng-model-change` property doesn't produce a DOM event; it's an Angular `EventEmitter`
|
The `ngModelChange` property doesn't produce a DOM event; it's an Angular `EventEmitter`
|
||||||
property that returns the input box value when it fires — which is precisely what
|
property that returns the input box value when it fires — which is precisely what
|
||||||
we should assign to the model's `name' property.
|
we should assign to the model's `name' property.
|
||||||
|
|
||||||
Nice to know but is it practical? We almost always prefer `[(ng-model)]`.
|
Nice to know but is it practical? We almost always prefer `[(ngModel)]`.
|
||||||
We might split the binding if we had to do something special in
|
We might split the binding if we had to do something special in
|
||||||
the event handling such as debounce or throttle the key strokes.
|
the event handling such as debounce or throttle the key strokes.
|
||||||
|
|
||||||
@ -345,7 +345,7 @@ figure.image-display
|
|||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Track change-state and validity with **ng-control**
|
## Track change-state and validity with **ngControl**
|
||||||
|
|
||||||
A form isn't just about data binding. We'd also like to know the state of the controls on our form.
|
A form isn't just about data binding. We'd also like to know the state of the controls on our form.
|
||||||
The `NgControl` directive keeps track of control state for us.
|
The `NgControl` directive keeps track of control state for us.
|
||||||
@ -365,18 +365,18 @@ figure.image-display
|
|||||||
control and make messages appear or disappear.
|
control and make messages appear or disappear.
|
||||||
|
|
||||||
We'll explore those effects soon. Right now
|
We'll explore those effects soon. Right now
|
||||||
we should **add `ng-control`to all three form controls**,
|
we should **add `ngControl`to all three form controls**,
|
||||||
starting with the *Name* input box
|
starting with the *Name* input box
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-control-1', 'app/hero-form.component.html (excerpt)')
|
+makeExample('forms/ts/app/hero-form.component.html', 'ngControl-1', 'app/hero-form.component.html (excerpt)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
Be sure to assign a unique name to each `ng-control` directive.
|
Be sure to assign a unique name to each `ngControl` directive.
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
Angular registers controls under their `ng-control` names
|
Angular registers controls under their `ngControl` names
|
||||||
with the `NgForm`.
|
with the `NgForm`.
|
||||||
We didn't add the `NgForm` directive explicitly but it's here
|
We didn't add the `NgForm` directive explicitly but it's here
|
||||||
and we'll talk about it [later in this chapter](#ng-form).
|
and we'll talk about it [later in this chapter](#ngForm).
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
@ -406,7 +406,7 @@ table
|
|||||||
Let's add a temporary [local template variable](./template-syntax.html#local-vars) named **spy**
|
Let's add a temporary [local template variable](./template-syntax.html#local-vars) named **spy**
|
||||||
to the "Name" `<input>` tag and use the spy to display those classes.
|
to the "Name" `<input>` tag and use the spy to display those classes.
|
||||||
|
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-control-2')
|
+makeExample('forms/ts/app/hero-form.component.html', 'ngControl-2','app/hero-form.component.html (excerpt)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Now run the app and focus on the *Name* input box.
|
Now run the app and focus on the *Name* input box.
|
||||||
@ -438,12 +438,12 @@ figure.image-display
|
|||||||
We achieve this effect by adding two styles to a new `styles.css` file
|
We achieve this effect by adding two styles to a new `styles.css` file
|
||||||
that we add to our project as a sibling to `index.html`.
|
that we add to our project as a sibling to `index.html`.
|
||||||
|
|
||||||
+makeExample('forms/ts/src/styles.css',null,'styles.css')
|
+makeExample('forms/ts/styles.css',null,'styles.css')(format=".")
|
||||||
:marked
|
:marked
|
||||||
These styles select for the two Angular validity classes and the HTML 5 "required" attribute.
|
These styles select for the two Angular validity classes and the HTML 5 "required" attribute.
|
||||||
|
|
||||||
We update the `<head>` of the `index.html` to include this style sheet.
|
We update the `<head>` of the `index.html` to include this style sheet.
|
||||||
+makeExample('forms/ts/src/index.html', 'styles', 'index.html (excerpt)')(format=".")
|
+makeExample('forms/ts/index.html', 'styles', 'index.html (excerpt)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
## Show and Hide Validation Error messages
|
## Show and Hide Validation Error messages
|
||||||
|
|
||||||
@ -464,39 +464,36 @@ figure.image-display
|
|||||||
|
|
||||||
Here's how we do it for the *name* input box:
|
Here's how we do it for the *name* input box:
|
||||||
-var stylePattern = { otl: /(#name="form")|(.*div.*$)|(Name is required)/gm };
|
-var stylePattern = { otl: /(#name="form")|(.*div.*$)|(Name is required)/gm };
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html',
|
+makeExample('forms/ts/app/hero-form.component.html',
|
||||||
'name-with-error-msg',
|
'name-with-error-msg',
|
||||||
'app/hero-form.component.html (excerpt)',
|
'app/hero-form.component.html (excerpt)',
|
||||||
stylePattern)
|
stylePattern)
|
||||||
:marked
|
:marked
|
||||||
We initialized the template local variable with the word "form" (`#name="form"`)
|
When we added the `ngControl` directive, we bound it to the the model's `name` property.
|
||||||
|
|
||||||
Angular recognizes that syntax and sets the `name` variable
|
Here we initialize a template local variable (`name`) with the value "ngForm" (`#name="ngForm"`).
|
||||||
to the `Control` object identified by the `ng-control` directive which,
|
Angular recognizes that syntax and re-sets the `name` local template variable to the
|
||||||
not coincidentally, we called "name".
|
`ngControl` directive instance.
|
||||||
|
In other words, the `name` local template variable becomes a handle on the `ngControl` object
|
||||||
|
for this input box.
|
||||||
|
|
||||||
We bind the `Control` object's `valid` property to the element's `hidden` property.
|
Now we can control visibility of the "name" error message by binding the message `<div>` element's `hidden` property
|
||||||
While the control is valid, the message is hidden;
|
to the `ngControl` object's `valid` property. The message is hidden while the control is valid;
|
||||||
if it becomes invalid, the message is revealed.
|
the message is revealed when the control becomes invalid.
|
||||||
<a id="ng-form"></a>
|
<a id="ngForm"></a>
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
### The NgForm directive
|
### The NgForm directive
|
||||||
Recall from the previous section that `ng-control` registered this input box with the
|
We just set a template local variable with the value of an `NgForm` directive.
|
||||||
`NgForm` directive as "name".
|
Why did that work? We didn't add the **[`NgForm`](../api/core/NgForm-class.html) directive** explicitly.
|
||||||
|
|
||||||
We didn't add the **[`NgForm`](../api/core/NgForm-class.html) directive** explicitly.
|
|
||||||
Angular added it surreptiously, wrapping it around the `<form>` element
|
Angular added it surreptiously, wrapping it around the `<form>` element
|
||||||
|
|
||||||
The `NgForm` directive supplements the `form` element with additional features.
|
The `NgForm` directive supplements the `form` element with additional features.
|
||||||
It collects `Controls` (elements identified by an `ng-control` directive)
|
It collects `Controls` (elements identified by an `ngControl` directive)
|
||||||
and monitors their properties including their validity.
|
and monitors their properties including their validity.
|
||||||
It has its own `valid` property which is true only if every contained
|
It also has its own `valid` property which is true only if every contained
|
||||||
control is valid.
|
control is valid.
|
||||||
|
|
||||||
In this example, we are pulling the "name" control out of its `controls` collection
|
|
||||||
and assigning it to the template local variable so that we can
|
|
||||||
access the control's properties — such as the control's own `valid` property.
|
|
||||||
:marked
|
:marked
|
||||||
The Hero *Alter Ego* is optional so we can leave that be.
|
The Hero *Alter Ego* is optional so we can leave that be.
|
||||||
|
|
||||||
@ -507,35 +504,32 @@ figure.image-display
|
|||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Submit the form with **ng-submit**
|
## Submit the form with **ngSubmit**
|
||||||
The user should be able to submit this form after filling it in.
|
The user should be able to submit this form after filling it in.
|
||||||
The Submit button at the bottom of the form
|
The Submit button at the bottom of the form
|
||||||
does nothing on its own but it will
|
does nothing on its own but it will
|
||||||
trigger a form submit because of its type (`type="submit"`).
|
trigger a form submit because of its type (`type="submit"`).
|
||||||
|
|
||||||
A "form submit" is meaningless at the moment.
|
A "form submit" is useless at the moment.
|
||||||
To make it meaningful, we'll update the `<form>` tag with another Angular directive, `NgSubmit`,
|
To make it useful, we'll update the `<form>` tag with another Angular directive, `NgSubmit`,
|
||||||
and bind it to our `HeroFormComponent.submit()` method with an EventBinding
|
and bind it to the `HeroFormComponent.submit()` method with an event binding
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-submit')(format=".")
|
+makeExample('forms/ts/app/hero-form.component.html', 'ngSubmit')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We slipped in something extra there at the end! We defined a
|
We slipped in something extra there at the end! We defined a
|
||||||
template local variable, **`#hf`**, and initialized it with the value, "form".
|
template local variable, **`#heroForm`**, and initialized it with the value, "ngForm".
|
||||||
|
|
||||||
The variable `hf` is now a handle to the `NgForm` as we [discussed earlier](#ng-form)
|
The variable `heroForm` is now a handle to the `NgForm` directive that we [discussed earlier](#ngForm)
|
||||||
with respect to `ng-control` although this time we have a reference to the form
|
This time `heroForm` remains a reference to the form as a whole.
|
||||||
rather than a control.
|
|
||||||
|
|
||||||
We'll bind the Form's over-all validity via
|
Later in the template we bind the button's `disabled` property to the form's over-all validity via
|
||||||
the `hf` variable to the button's `disabled` property
|
the `heroForm` variable. Here's that bit of markup:
|
||||||
using an Event Binding. Here's the code:
|
+makeExample('forms/ts/app/hero-form.component.html', 'submit-button')
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'submit-button')
|
|
||||||
:marked
|
:marked
|
||||||
If we run the application now, we find that the button is enabled.
|
Re-run the application. The form opens in a valid state and the button is enabled.
|
||||||
It doesn't do anything useful yet but it's alive.
|
|
||||||
|
|
||||||
Now if we delete the *Name*, we violate the "required" rule which
|
Now delete the *Name*. We violate the "name required" rule which
|
||||||
is duely noted in our error message. The Submit button is also disabled.
|
is duely noted in our error message as before. And now the Submit button is also disabled.
|
||||||
|
|
||||||
Not impressed? Think about it for a moment. What would we have to do to
|
Not impressed? Think about it for a moment. What would we have to do to
|
||||||
wire the button's enable/disabled state to the form's validity without Angular's help?
|
wire the button's enable/disabled state to the form's validity without Angular's help?
|
||||||
@ -563,14 +557,14 @@ figure.image-display
|
|||||||
Start by wrapping the form in a `<div>` and bind
|
Start by wrapping the form in a `<div>` and bind
|
||||||
its `hidden` property to the `HeroFormComponent.submitted` property.
|
its `hidden` property to the `HeroFormComponent.submitted` property.
|
||||||
|
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'edit-div', 'app/hero-form.component.html (excerpt)')
|
+makeExample('forms/ts/app/hero-form.component.html', 'edit-div', 'app/hero-form.component.html (excerpt)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The main form is visible from the start because the
|
The main form is visible from the start because the
|
||||||
the `submitted` property is false until we submit the form,
|
the `submitted` property is false until we submit the form,
|
||||||
as this fragment from the `HeroFormComponent` reminds us:
|
as this fragment from the `HeroFormComponent` reminds us:
|
||||||
|
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.ts', 'submitted')
|
+makeExample('forms/ts/app/hero-form.component.ts', 'submitted')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
When we click the Submit button, the `submitted` flag becomes true and the form disappears
|
When we click the Submit button, the `submitted` flag becomes true and the form disappears
|
||||||
@ -578,7 +572,7 @@ figure.image-display
|
|||||||
|
|
||||||
Now we need to show something else while the form is in the submitted state.
|
Now we need to show something else while the form is in the submitted state.
|
||||||
Add the following block of HTML below the `<div>` wrapper we just wrote:
|
Add the following block of HTML below the `<div>` wrapper we just wrote:
|
||||||
+makeExample('forms/ts/src/app/hero-form.component.html', 'submitted', 'app/hero-form.component.html (excerpt)')
|
+makeExample('forms/ts/app/hero-form.component.html', 'submitted', 'app/hero-form.component.html (excerpt)')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
There's our hero again, displayed read-only with interpolation bindings.
|
There's our hero again, displayed read-only with interpolation bindings.
|
||||||
@ -599,43 +593,45 @@ figure.image-display
|
|||||||
|
|
||||||
- An Angular HTML form template.
|
- An Angular HTML form template.
|
||||||
- A form component class with a `Component` decorator.
|
- A form component class with a `Component` decorator.
|
||||||
- The `ng-submit` directive for handling the form submission.
|
- The `ngSubmit` directive for handling the form submission.
|
||||||
- Template local variables such as `#hf`, `#name`, `#alter-ego` and `#power`.
|
- Template local variables such as `#heroForm`, `#name`, `#alter-ego` and `#power`.
|
||||||
- The `ng-model` directive for two-way data binding.
|
- The `ngModel` directive for two-way data binding.
|
||||||
- The `ng-control` for validation and form element change tracking.
|
- The `ngControl` for validation and form element change tracking.
|
||||||
- The local variable’s `valid` property on input controls to check if a control is valid and show/hide error messages.
|
- The local variable’s `valid` property on input controls to check if a control is valid and show/hide error messages.
|
||||||
- Property Binding to disable the submit button when the form is invalid.
|
- Controlling the submit button's enabled state by binding to `NgForm` validity.
|
||||||
- Custom CSS classes that provide visual feedback to users about required invalid controls.
|
- Custom CSS classes that provide visual feedback to users about invalid controls.
|
||||||
|
|
||||||
Here’s the final version of the application:
|
Our final project folder structure should look like this:
|
||||||
|
code-example(format="").
|
||||||
|
angular2-forms
|
||||||
|
├── node_modules
|
||||||
|
├── app
|
||||||
|
| ├── app.component.ts
|
||||||
|
| ├── boot.ts
|
||||||
|
| ├── hero.ts
|
||||||
|
| ├── hero-form.component.html
|
||||||
|
| └── hero-form.component.ts
|
||||||
|
├── index.html
|
||||||
|
├── styles.css
|
||||||
|
├── tsconfig.json
|
||||||
|
└── package.json
|
||||||
|
:marked
|
||||||
|
Here’s the final version of the source:
|
||||||
|
|
||||||
+makeTabs(
|
+makeTabs(
|
||||||
`forms/ts/src/app/hero-form.component.html,
|
`forms/ts/app/hero-form.component.ts,
|
||||||
forms/ts/src/app/hero-form.component.ts,
|
forms/ts/app/hero-form.component.html,
|
||||||
forms/ts/src/app/hero.ts,
|
forms/ts/app/hero.ts,
|
||||||
forms/ts/src/app/app.ts,
|
forms/ts/app/app.component.ts,
|
||||||
forms/ts/src/index.html,
|
forms/ts/app/boot.ts,
|
||||||
forms/ts/src/styles.css`,
|
forms/ts/index.html,
|
||||||
'final, final,,,,',
|
forms/ts/styles.css`,
|
||||||
`hero-form.component.html,
|
'final, final,,,,,',
|
||||||
hero-form.component.ts,
|
`hero-form.component.ts,
|
||||||
|
hero-form.component.html,
|
||||||
hero.ts,
|
hero.ts,
|
||||||
app.ts,
|
app.component.ts,
|
||||||
|
boot.ts,
|
||||||
index.html,
|
index.html,
|
||||||
styles.css`)
|
styles.css`)
|
||||||
:marked
|
:marked
|
||||||
Our final project folder structure should look like this:
|
|
||||||
```
|
|
||||||
angular2-forms
|
|
||||||
├── node_modules
|
|
||||||
├── src
|
|
||||||
│ ├── app
|
|
||||||
│ | ├── app.ts
|
|
||||||
│ | ├── hero.ts
|
|
||||||
│ | ├── hero-form.component.html
|
|
||||||
│ | └── hero-form.component.ts
|
|
||||||
│ ├── index.html
|
|
||||||
│ ├── styles.css
|
|
||||||
│ └── tsconfig.json
|
|
||||||
└── package.json
|
|
||||||
```
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 23 KiB |
Binary file not shown.
Before Width: | Height: | Size: 22 KiB |
Loading…
x
Reference in New Issue
Block a user