parent
dc1c054927
commit
31051d29f0
|
@ -0,0 +1,27 @@
|
||||||
|
<p>
|
||||||
|
<click-me></click-me>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<click-me2></click-me2>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4>Give me some keys!</h4>
|
||||||
|
<div><key-up1></key-up1></div>
|
||||||
|
|
||||||
|
<h4>keyup loop-back component</h4>
|
||||||
|
<div><loop-back></loop-back></div>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<h4>Give me some more keys!</h4>
|
||||||
|
<div><key-up2></key-up2></div>
|
||||||
|
|
||||||
|
<h4>Type away! Press [enter] when done.</h4>
|
||||||
|
<div><key-up3></key-up3></div>
|
||||||
|
|
||||||
|
<h4>Type away! Press [enter] or click elsewhere when done.</h4>
|
||||||
|
<div><key-up4></key-up4></div>
|
||||||
|
|
||||||
|
<h4>Little Tour of Heroes</h4>
|
||||||
|
<p><i>Add a new hero</i></p>
|
||||||
|
<div><little-tour></little-tour></div>
|
|
@ -0,0 +1,26 @@
|
||||||
|
// #docregion
|
||||||
|
import {Component} from 'angular2/core';
|
||||||
|
|
||||||
|
import {ClickMeComponent} from './click-me.component';
|
||||||
|
import {ClickMeComponent2} from './click-me2.component';
|
||||||
|
|
||||||
|
import {LoopbackComponent} from './loop-back.component';
|
||||||
|
|
||||||
|
import {KeyUpComponent_v1,
|
||||||
|
KeyUpComponent_v2,
|
||||||
|
KeyUpComponent_v3,
|
||||||
|
KeyUpComponent_v4} from './keyup.components';
|
||||||
|
|
||||||
|
import {LittleTourComponent} from './little-tour.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-app',
|
||||||
|
templateUrl: 'app/app.component.html',
|
||||||
|
directives: [
|
||||||
|
ClickMeComponent, ClickMeComponent2,
|
||||||
|
LoopbackComponent,
|
||||||
|
KeyUpComponent_v1, KeyUpComponent_v2, KeyUpComponent_v3, KeyUpComponent_v4,
|
||||||
|
LittleTourComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AppComponent { }
|
|
@ -0,0 +1,4 @@
|
||||||
|
import {bootstrap} from 'angular2/platform/browser';
|
||||||
|
import {AppComponent} from './app.component';
|
||||||
|
|
||||||
|
bootstrap(AppComponent);
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* FOR DOCS ... MUST MATCH ClickMeComponent template
|
||||||
|
// #docregion click-me-button
|
||||||
|
<button (click)="onClickMe()">Click me!</button>
|
||||||
|
// #enddocregion click-me-button
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #docregion
|
||||||
|
import {Component} from 'angular2/core';
|
||||||
|
|
||||||
|
// #docregion click-me-component
|
||||||
|
@Component({
|
||||||
|
selector: 'click-me',
|
||||||
|
template: `
|
||||||
|
<button (click)="onClickMe()">Click me!</button>
|
||||||
|
{{clickMessage}}`
|
||||||
|
})
|
||||||
|
export class ClickMeComponent {
|
||||||
|
clickMessage = '';
|
||||||
|
|
||||||
|
onClickMe(){
|
||||||
|
this.clickMessage ='You are my hero!';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #enddocregion click-me-component
|
|
@ -0,0 +1,18 @@
|
||||||
|
// #docregion
|
||||||
|
import {Component} from 'angular2/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'click-me2',
|
||||||
|
template: `
|
||||||
|
<button (click)="onClickMe2($event)">No! .. Click me!</button>
|
||||||
|
{{clickMessage}}`
|
||||||
|
})
|
||||||
|
export class ClickMeComponent2 {
|
||||||
|
clickMessage = '';
|
||||||
|
clicks = 1;
|
||||||
|
|
||||||
|
onClickMe2(event:any){
|
||||||
|
let evtMsg = event ? ' Event target is '+ event.target.tagName : '';
|
||||||
|
this.clickMessage = (`Click #${this.clicks++}. ${evtMsg}`)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
// #docplaster
|
||||||
|
// #docregion
|
||||||
|
import {Component} from 'angular2/core';
|
||||||
|
|
||||||
|
// #docregion key-up-component-1
|
||||||
|
@Component({
|
||||||
|
selector: 'key-up1',
|
||||||
|
// #docregion key-up-component-1-template
|
||||||
|
template: `
|
||||||
|
<input (keyup)="onKey($event)">
|
||||||
|
<p>{{values}}</p>
|
||||||
|
`
|
||||||
|
// #enddocregion key-up-component-1-template
|
||||||
|
})
|
||||||
|
// #docregion key-up-component-1-class, key-up-component-1-class-no-type
|
||||||
|
export class KeyUpComponent_v1 {
|
||||||
|
values='';
|
||||||
|
|
||||||
|
// #enddocregion key-up-component-1-class, key-up-component-1-class-no-type
|
||||||
|
/*
|
||||||
|
// #docregion key-up-component-1-class-no-type
|
||||||
|
// without strong typing
|
||||||
|
onKey(event:any) {
|
||||||
|
this.values += event.target.value + ' | ';
|
||||||
|
}
|
||||||
|
// #enddocregion key-up-component-1-class-no-type
|
||||||
|
*/
|
||||||
|
// #docregion key-up-component-1-class
|
||||||
|
// with strong typing
|
||||||
|
onKey(event:KeyboardEvent) {
|
||||||
|
this.values += (<HTMLInputElement>event.target).value + ' | ';
|
||||||
|
}
|
||||||
|
// #docregion key-up-component-1-class-no-type
|
||||||
|
}
|
||||||
|
// #enddocregion key-up-component-1,key-up-component-1-class, key-up-component-1-class-no-type
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
|
||||||
|
// #docregion key-up-component-2
|
||||||
|
@Component({
|
||||||
|
selector: 'key-up2',
|
||||||
|
template: `
|
||||||
|
<input #box (keyup)="onKey(box.value)">
|
||||||
|
<p>{{values}}</p>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class KeyUpComponent_v2 {
|
||||||
|
values='';
|
||||||
|
onKey(value:string) {
|
||||||
|
this.values += value + ' | ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #enddocregion key-up-component-2
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
|
||||||
|
// #docregion key-up-component-3
|
||||||
|
@Component({
|
||||||
|
selector: 'key-up3',
|
||||||
|
template: `
|
||||||
|
<input #box (keyup.enter)="values=box.value">
|
||||||
|
<p>{{values}}</p>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class KeyUpComponent_v3 {
|
||||||
|
values='';
|
||||||
|
}
|
||||||
|
// #enddocregion key-up-component-3
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
|
||||||
|
// #docregion key-up-component-4
|
||||||
|
@Component({
|
||||||
|
selector: 'key-up4',
|
||||||
|
template: `
|
||||||
|
<input #box
|
||||||
|
(keyup.enter)="values=box.value"
|
||||||
|
(blur)="values=box.value">
|
||||||
|
|
||||||
|
<p>{{values}}</p>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class KeyUpComponent_v4 {
|
||||||
|
values='';
|
||||||
|
}
|
||||||
|
// #enddocregion key-up-component-4
|
|
@ -0,0 +1,25 @@
|
||||||
|
// #docregion
|
||||||
|
import {Component} from 'angular2/core';
|
||||||
|
|
||||||
|
// #docregion little-tour
|
||||||
|
@Component({
|
||||||
|
selector: 'little-tour',
|
||||||
|
template: `
|
||||||
|
<input #newHero
|
||||||
|
(keyup.enter)="addHero(newHero.value)"
|
||||||
|
(blur)="addHero(newHero.value); newHero.value='' ">
|
||||||
|
|
||||||
|
<button (click)=addHero(newHero.value)>Add</button>
|
||||||
|
|
||||||
|
<ul><li *ngFor="#hero of heroes">{{hero}}</li></ul>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class LittleTourComponent {
|
||||||
|
heroes=['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
|
||||||
|
addHero(newHero:string) {
|
||||||
|
if (newHero) {
|
||||||
|
this.heroes.push(newHero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #enddocregion little-tour
|
|
@ -0,0 +1,12 @@
|
||||||
|
// #docregion
|
||||||
|
import {Component} from 'angular2/core';
|
||||||
|
// #docregion loop-back-component
|
||||||
|
@Component({
|
||||||
|
selector: 'loop-back',
|
||||||
|
template:`
|
||||||
|
<input #box (keyup)="0">
|
||||||
|
<p>{{box.value}}</p>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class LoopbackComponent { }
|
||||||
|
// #enddocregion loop-back-component
|
|
@ -3,8 +3,8 @@
|
||||||
<head>
|
<head>
|
||||||
<title>User Input</title>
|
<title>User Input</title>
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
<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'}}
|
||||||
|
@ -15,8 +15,6 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<my-app>Loading...</my-app>
|
<my-app>Loading...</my-app>
|
||||||
<hr>
|
|
||||||
<little-tour>Loading...</little-tour>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"description": "User Input",
|
||||||
|
"files": [
|
||||||
|
"!**/*.d.ts",
|
||||||
|
"!**/*.js"
|
||||||
|
],
|
||||||
|
"tags": ["input"]
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
<!-- #docregion click-me-button -->
|
|
||||||
<button (click)="onClickMe()">Click me!</button>
|
|
||||||
<!-- #enddocregion click-me-button -->
|
|
||||||
|
|
||||||
<h4>keyup loop-back component</h4>
|
|
||||||
<loop-back></loop-back>
|
|
||||||
|
|
||||||
<key-up></key-up>
|
|
||||||
|
|
||||||
<key-up2></key-up2>
|
|
||||||
|
|
||||||
<key-up3></key-up3>
|
|
||||||
|
|
||||||
<key-up4></key-up4>
|
|
|
@ -1,147 +0,0 @@
|
||||||
// #docplaster
|
|
||||||
|
|
||||||
// imports formatted for dev guide only
|
|
||||||
// #docregion little-tour-of-heroes-app
|
|
||||||
import {bootstrap, Component, CORE_DIRECTIVES} from 'angular2/angular2';
|
|
||||||
|
|
||||||
// #enddocregion little-tour-of-heroes-app
|
|
||||||
|
|
||||||
|
|
||||||
// #docregion click-me-component
|
|
||||||
@Component({
|
|
||||||
selector: 'click-me',
|
|
||||||
template: '<button (click)="onClickMe()">Click me</button>'
|
|
||||||
})
|
|
||||||
class ClickMeComponent {
|
|
||||||
onClickMe(){
|
|
||||||
alert('You are my hero!')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// #enddocregion click-me-component
|
|
||||||
|
|
||||||
// #docregion loop-back-component
|
|
||||||
@Component({
|
|
||||||
selector: 'loop-back',
|
|
||||||
template: '<input #box (keyup)="0"> <p>{{box.value}}</p>'
|
|
||||||
})
|
|
||||||
class LoopbackComponent {
|
|
||||||
}
|
|
||||||
// #enddocregion loop-back-component
|
|
||||||
|
|
||||||
// #docregion key-up-component
|
|
||||||
@Component({
|
|
||||||
selector: 'key-up',
|
|
||||||
template: `
|
|
||||||
<h4>Give me some keys!</h4>
|
|
||||||
<div><input (keyup)="onKey($event)"></div>
|
|
||||||
<div>{{values}}</div>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
class KeyUpComponent {
|
|
||||||
values='';
|
|
||||||
onKey(event) {
|
|
||||||
this.values += event.target.value + ' | ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// #enddocregion key-up-component
|
|
||||||
|
|
||||||
// #docregion key-up2-component
|
|
||||||
@Component({
|
|
||||||
selector: 'key-up2',
|
|
||||||
template: `
|
|
||||||
<h4>Give me some more keys!</h4>
|
|
||||||
<div><input #box (keyup)="onKey(box.value)"></div>
|
|
||||||
<div>{{values}}</div>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
class KeyUpComponentV2 {
|
|
||||||
values='';
|
|
||||||
onKey(value) {
|
|
||||||
this.values += value + ' | ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// #enddocregion key-up2-component
|
|
||||||
|
|
||||||
|
|
||||||
// #docregion key-up3-component
|
|
||||||
@Component({
|
|
||||||
selector: 'key-up3',
|
|
||||||
template: `
|
|
||||||
<h4>Type away! Press [enter] when done.</h4>
|
|
||||||
<div><input #box (keyup.enter)="values=box.value"></div>
|
|
||||||
<div>{{values}}</div>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
class KeyUpComponentV3 {
|
|
||||||
values='';
|
|
||||||
}
|
|
||||||
// #enddocregion key-up3-component
|
|
||||||
|
|
||||||
|
|
||||||
// #docregion key-up4-component
|
|
||||||
@Component({
|
|
||||||
selector: 'key-up4',
|
|
||||||
template: `
|
|
||||||
<h4>Type away! Press [enter] or mouse away when done.</h4>
|
|
||||||
<div>
|
|
||||||
<input #box
|
|
||||||
(keyup.enter)="values=box.value"
|
|
||||||
(blur)="values=box.value">
|
|
||||||
<div>
|
|
||||||
<div>{{values}}</div>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
class KeyUpComponentV4 {
|
|
||||||
values='';
|
|
||||||
}
|
|
||||||
// #enddocregion key-up4-component
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'my-app',
|
|
||||||
templateUrl: 'app/app.html',
|
|
||||||
directives: [
|
|
||||||
CORE_DIRECTIVES,
|
|
||||||
ClickMeComponent,
|
|
||||||
KeyUpComponent, KeyUpComponentV2, KeyUpComponentV3, KeyUpComponentV4,
|
|
||||||
LoopbackComponent,
|
|
||||||
]
|
|
||||||
})
|
|
||||||
class AppComponent {
|
|
||||||
|
|
||||||
onClickMe(event){
|
|
||||||
let evtMsg = event ? ' Event target class is '+ event.target.className : '';
|
|
||||||
alert('Click me.'+evtMsg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bootstrap(AppComponent);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// #docregion little-tour-of-heroes-app
|
|
||||||
@Component({
|
|
||||||
selector: 'little-tour',
|
|
||||||
template: `
|
|
||||||
<h4>Little Tour of Heroes</h4>
|
|
||||||
<input #new-hero
|
|
||||||
(keyup.enter)="addHero(newHero)"
|
|
||||||
(blur)="addHero(newHero)">
|
|
||||||
<button (click)=addHero(newHero)>Add</button>
|
|
||||||
<ul><li *ng-for="#hero of heroes">{{hero}}</li></ul>
|
|
||||||
`,
|
|
||||||
directives: [CORE_DIRECTIVES]
|
|
||||||
})
|
|
||||||
class LittleTour {
|
|
||||||
heroes=['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
|
|
||||||
|
|
||||||
addHero(newHero) {
|
|
||||||
if (newHero.value) {
|
|
||||||
this.heroes.push(newHero.value);
|
|
||||||
newHero.value = null; // clear the newHero textbox
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bootstrap(LittleTour);
|
|
||||||
// #enddocregion little-tour-of-heroes-app
|
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"files": ["!*.json"]
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ include ../../../../_includes/_util-fns
|
||||||
we want to know about it. These user actions all raise DOM events.
|
we want to know about it. These user actions all raise DOM events.
|
||||||
In this chapter we learn to bind to those events using the Angular Event Binding syntax.
|
In this chapter we learn to bind to those events using the Angular Event Binding syntax.
|
||||||
|
|
||||||
[Live Example](/resources/live-examples/user-input/ts/src/plnkr.html).
|
[Live Example](/resources/live-examples/user-input/ts/plnkr.html).
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
## Binding to User Input Events
|
## Binding to User Input Events
|
||||||
|
@ -15,7 +15,7 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
The syntax is simple. We assign a template expression to the DOM event name, surrounded in parentheses.
|
The syntax is simple. We assign a template expression to the DOM event name, surrounded in parentheses.
|
||||||
A click Event Binding makes for a quick illustration.
|
A click Event Binding makes for a quick illustration.
|
||||||
+makeExample('user-input/ts/src/app/app.html', 'click-me-button')(format=".")
|
+makeExample('user-input/ts/app/click-me.component.ts', 'click-me-button')(format=".", language="html")
|
||||||
|
|
||||||
<a id="click"></a>
|
<a id="click"></a>
|
||||||
:marked
|
:marked
|
||||||
|
@ -28,10 +28,8 @@ include ../../../../_includes/_util-fns
|
||||||
The identifers appearing within an expression belong to a specific context object.
|
The identifers appearing within an expression belong to a specific context object.
|
||||||
That object is usually the Angular component that controls the template ... which it definitely is
|
That object is usually the Angular component that controls the template ... which it definitely is
|
||||||
in this case because that snippet of HTML belongs to the following component:
|
in this case because that snippet of HTML belongs to the following component:
|
||||||
<!--
|
|
||||||
These sample can be found in http://plnkr.co/edit/mr63T5
|
+makeExample('user-input/ts/app/click-me.component.ts', 'click-me-component', 'app/click-me.component.ts')
|
||||||
-->
|
|
||||||
+makeExample('user-input/ts/src/app/app.ts', 'click-me-component')
|
|
||||||
:marked
|
:marked
|
||||||
The `onClickMe` in the template refers to the `onClickMe` method of the component.
|
The `onClickMe` in the template refers to the `onClickMe` method of the component.
|
||||||
When the user clicks the button, Angular calls the component's `onClickMe` method.
|
When the user clicks the button, Angular calls the component's `onClickMe` method.
|
||||||
|
@ -42,27 +40,43 @@ include ../../../../_includes/_util-fns
|
||||||
We can bind to all kinds of events. Let's bind to the "keyup" event of an input box and replay
|
We can bind to all kinds of events. Let's bind to the "keyup" event of an input box and replay
|
||||||
what the user types back onto the screen.
|
what the user types back onto the screen.
|
||||||
|
|
||||||
This time we'll both listen to an event and grab the user's input.
|
This time we'll (1) listen to an event and (2) grab the user's input.
|
||||||
+makeExample('user-input/ts/src/app/app.ts', 'key-up-component')
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-1-template', 'app/keyup.components.ts (template v.1)')
|
||||||
|
:marked
|
||||||
|
Angular makes an event object available in the **`$event`** variable
|
||||||
|
which we pass to the component's `onKey()` method.
|
||||||
|
The user data we want is in that variable somewhere.
|
||||||
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-1-class-no-type', 'app/keyup.components.ts (class v.1)')
|
||||||
:marked
|
:marked
|
||||||
Angular makes an event object available in the **`$event`** variable. The user data we want is in that variable somewhere.
|
|
||||||
|
|
||||||
The shape of the `$event` object is determined by whatever raises the event.
|
The shape of the `$event` object is determined by whatever raises the event.
|
||||||
The `keyup` event comes from the DOM so `$event` must be a [standard DOM event object](https://developer.mozilla.org/en-US/docs/Web/API/Event).
|
The `keyup` event comes from the DOM so `$event` must be a [standard DOM event object](https://developer.mozilla.org/en-US/docs/Web/API/Event).
|
||||||
The `$event.target` gives us the
|
The `$event.target` gives us the
|
||||||
[`HTMLInputElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) which
|
[`HTMLInputElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) which
|
||||||
has a `value` property and that's where we find our user input data.
|
has a `value` property and that's where we find our user input data.
|
||||||
|
|
||||||
With had this in mind when we passed `$event` to our `onKey()` component method. That method extracts the user's input and
|
With had this in mind when we passed `$event` to our `onKey()` component method where we extract the user's input and
|
||||||
concatenates it to the previous user data that we're accumulating in the component's' `values` property.
|
concatenate it to the previous user data that we're accumulating in the component's' `values` property.
|
||||||
We then use [interpolation](./template-syntax.html#interpolation)
|
We then use [interpolation](./template-syntax.html#interpolation)
|
||||||
to display the `values` property back on screen.
|
to display the accumulating `values` property back on screen.
|
||||||
|
|
||||||
Enter the letters "abc", backspace to remove them, and we should see:
|
Enter the letters "abc", backspace to remove them, and we should see:
|
||||||
code-example().
|
code-example().
|
||||||
a | ab | abc | ab | a | |
|
a | ab | abc | ab | a | |
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/user-input/keyup1-anim.gif' alt="key up 1")
|
img(src='/resources/images/devguide/user-input/keyup1-anim.gif' alt="key up 1")
|
||||||
|
|
||||||
|
<a id="keyup1"></a>
|
||||||
|
.l-sub-section
|
||||||
|
:marked
|
||||||
|
We cast the `$event` as an `any` type which means we've abandoned strong typing
|
||||||
|
to simplify our code. We generally prefer the strong typing that TypeScript affords.
|
||||||
|
We can rewrite the method, casting to HTML DOM objects like this.
|
||||||
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-1-class', 'app/keyup.components.ts (class v.1 - strongly typed )')
|
||||||
|
:marked
|
||||||
|
<br>Strong typing reveals a serious problem with passing a DOM event into the method:
|
||||||
|
too much awareness of template details, too little separation of concerns.
|
||||||
|
|
||||||
|
We'll address this problem in our next try at processing user keystrokes.
|
||||||
:marked
|
:marked
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
|
@ -74,28 +88,35 @@ figure.image-display
|
||||||
These variables grant us direct access to an element.
|
These variables grant us direct access to an element.
|
||||||
We declare a local template variable by preceding an identifier with a hash/pound character (#).
|
We declare a local template variable by preceding an identifier with a hash/pound character (#).
|
||||||
|
|
||||||
Let's demonstrate with a clever keystroke loopback in a single line of template HTML.
|
Let's demonstrate with a clever keystroke loopback in an ultra-simple template.
|
||||||
We don't actually need a dedicated component to do this but we'll make one anyway.
|
+makeExample('user-input/ts/app/loop-back.component.ts', 'loop-back-component', 'app/loop-back.component.ts')
|
||||||
+makeExample('user-input/ts/src/app/app.ts', 'loop-back-component')
|
|
||||||
:marked
|
:marked
|
||||||
We've declared a template local variable named `box` on the `<input>` element.
|
We've declared a template local variable named `box` on the `<input>` element.
|
||||||
The `box` variable is a reference to the `<input>` element itself which means we can
|
The `box` variable is a reference to the `<input>` element itself which means we can
|
||||||
grab the input element's `value` and display it
|
grab the input element's `value` and display it
|
||||||
with interpolation between `<p>` tags. The display updates as we type. *Voila!*
|
with interpolation between `<p>` tags.
|
||||||
|
|
||||||
**This won't work at all unless we bind to an event**. Angular only updates the bindings
|
The template is completely self contained. It doesn't bind to the component which does nothing.
|
||||||
(and therefore the screen)
|
|
||||||
|
Type in the input box and watch the display update with each keystroke. *Voila!*
|
||||||
|
|
||||||
|
figure.image-display
|
||||||
|
img(src='/resources/images/devguide/user-input/keyup-loop-back-anim.gif' alt="loop back")
|
||||||
|
.l-sub-section
|
||||||
|
:marked
|
||||||
|
**This won't work at all unless we bind to an event**.
|
||||||
|
|
||||||
|
Angular only updates the bindings (and therefore the screen)
|
||||||
if we do something in response to asynchronous events such as keystrokes.
|
if we do something in response to asynchronous events such as keystrokes.
|
||||||
|
|
||||||
In this silly example we aren't really interested in the event at all.
|
That's why we bind the `keyup` event to an expression that does ... well, nothing.
|
||||||
But an Event Binding requires a template expression to evaluate when the event fires.
|
We're binding to the number 0, the shortest expression we can think of.
|
||||||
Many things qualify as expressions, none simpler than a one-character literal
|
That is all it takes to keep Angular happy. We said it would be clever!
|
||||||
like the number zero. That's all it takes to keep Angular happy. We said it would be clever!
|
:marked
|
||||||
|
|
||||||
That local template variable is intriguing. It's clearly easer to get to the textbox with that
|
That local template variable is intriguing. It's clearly easer to get to the textbox with that
|
||||||
variable than to go through the `$event` object. Maybe we can re-write our previous
|
variable than to go through the `$event` object. Maybe we can re-write our previous
|
||||||
"key-up" example using the variable to acquire the user's' input. Let's give it a try.
|
"key-up" example using the variable to acquire the user's' input. Let's give it a try.
|
||||||
+makeExample('user-input/ts/src/app/app.ts', 'key-up2-component')
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-2' ,'app/keyup.components.ts (v2)')
|
||||||
:marked
|
:marked
|
||||||
That sure seems easier.
|
That sure seems easier.
|
||||||
An especially nice aspect of this approach is that our component code gets clean data values from the view.
|
An especially nice aspect of this approach is that our component code gets clean data values from the view.
|
||||||
|
@ -115,8 +136,10 @@ figure.image-display
|
||||||
|
|
||||||
Only then do we update the component's `values` property ...
|
Only then do we update the component's `values` property ...
|
||||||
inside the event expression rather than in the component ...
|
inside the event expression rather than in the component ...
|
||||||
because we can ... even if it is a dubious practice.
|
because we *can* ... even if it is a dubious practice.
|
||||||
+makeExample('user-input/ts/src/app/app.ts', 'key-up3-component')
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-3' ,'app/keyup.components.ts (v3)')
|
||||||
|
:marked
|
||||||
|
Here's how it works.
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/user-input/keyup3-anim.gif' alt="key up 3")
|
img(src='/resources/images/devguide/user-input/keyup3-anim.gif' alt="key up 3")
|
||||||
|
|
||||||
|
@ -130,7 +153,7 @@ figure.image-display
|
||||||
|
|
||||||
Let's fix that by listening to the input box's blur event as well.
|
Let's fix that by listening to the input box's blur event as well.
|
||||||
|
|
||||||
+makeExample('user-input/ts/src/app/app.ts', 'key-up4-component')
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-4' ,'app/keyup.components.ts (v4)')
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
|
@ -146,43 +169,62 @@ figure.image-display
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes")
|
img(src='/resources/images/devguide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes")
|
||||||
:marked
|
:marked
|
||||||
Below is the entire "Little Tour of Heroes" micro-app in a single component.
|
Below is the "Little Tour of Heroes" component.
|
||||||
We'll call out the highlights after we bask briefly in its minimalist glory.
|
We'll call out the highlights after we bask briefly in its minimalist glory.
|
||||||
<!--
|
|
||||||
This example in http://plnkr.co/edit/JWeIqq
|
+makeExample('user-input/ts/app/little-tour.component.ts', 'little-tour', 'app/little-tour.component.ts')
|
||||||
-->
|
|
||||||
+makeExample('user-input/ts/src/app/app.ts', 'little-tour-of-heroes-app')
|
|
||||||
:marked
|
:marked
|
||||||
We've seen almost everything here before. A few things are new or bear repeating.
|
We've seen almost everything here before. A few things are new or bear repeating.
|
||||||
|
|
||||||
### **Beware of camelCase variable names**
|
### *newHero* template variable
|
||||||
We enter new hero names in the `<input>` element so we chose `newHero` to be the name of the local template variable.
|
|
||||||
|
|
||||||
Unfortunately, we can't use that name when we declare the variable with (#).
|
The *newHero* template variable refers to the `<input>` element.
|
||||||
The browser forces all attribute and element names to lowercase, turning what would be `#newHero`
|
|
||||||
into `#newhero` (all lowercase). We don't want a `newhero` variable name in our template expressions.
|
|
||||||
|
|
||||||
The Angular workaround is to spell the declaration in "kebab case". Angular translates "#new-hero"
|
We can access `newHero` from any sibling or child of the `<input>` element.
|
||||||
to `newHero` for template expressions ... which is exactly what we want.
|
|
||||||
|
|
||||||
### **newHero refers to the `<input>` element**
|
|
||||||
We can access the `newHero` variable from any sibling or child of the `<input>` element.
|
|
||||||
When the user clicks the button, we don't need a fancy css selector to
|
When the user clicks the button, we don't need a fancy css selector to
|
||||||
track down the textbox and extract its value.
|
track down the textbox and extract its value.
|
||||||
The button simply passes the `newHero` textbox reference to its own click handling method.
|
|
||||||
That's a tremendous simplification, as anyone who's wrangled jQuery can confirm.
|
|
||||||
|
|
||||||
Ready access to the `<input>` element also makes it easy for the `addHero` method
|
### Extract the input box *value*
|
||||||
to clear the textbox after processing the new hero.
|
We could have passed the `newHero` into the component's `addHero()` method.
|
||||||
|
|
||||||
### **The *ng-for repeater**
|
But that would require `addHero` to pick its way through the `<input>` DOM element,
|
||||||
The `ng-for` directive repeats the template as many times as there are heroes in the `heroes` list.
|
something we learned to dislike in our first try at a [*KeyupComponent*](#keyup1).
|
||||||
We must remember to list `NgFor` among the directives used by the component's template
|
|
||||||
by importing the `CORE_DIRECTIVES` constant and adding it to the
|
|
||||||
@Component decorator's `directives` array.
|
|
||||||
|
|
||||||
We learned about `NgFor` in the "[Displaying Data](displaying-data.html#ng-for)" chapter.
|
Instead, we grab the input box *value* and pass *that* to `addHero()`.
|
||||||
|
The component knows nothing about HTML or DOM which is the way we like it.
|
||||||
|
|
||||||
|
### Don't let template expressions be complex
|
||||||
|
We bound `(blur)` to *two* JavaScript statements.
|
||||||
|
|
||||||
|
We like the first one that calls `addHero`.
|
||||||
|
We do not like the second one that assigns an empty string to the input box value.
|
||||||
|
|
||||||
|
We did it for a good reason. We have to clear the input box after adding the new hero to the list.
|
||||||
|
The component has no way to do that itself — because it has no access to the
|
||||||
|
input box (our design choice).
|
||||||
|
|
||||||
|
Although it *works*, we are rightly wary of JavaScript in HTML.
|
||||||
|
Template expressions are powerful. We're supposed to use them responsibly.
|
||||||
|
Complex JavaScript in HTML is irresponsible.
|
||||||
|
|
||||||
|
Should we reconsider our reluctance to pass the input box into the component?
|
||||||
|
|
||||||
|
There should be a better third way. And there is as we'll see when we learn about `NgModel` in the [Forms](forms.html) chapter.
|
||||||
|
.l-main-section
|
||||||
|
:marked
|
||||||
|
## Source code
|
||||||
|
|
||||||
|
Here is all the code we talked about in this chapter.
|
||||||
|
+makeTabs(`
|
||||||
|
user-input/ts/app/click-me.component.ts,
|
||||||
|
user-input/ts/app/keyup.components.ts,
|
||||||
|
user-input/ts/app/loop-back.component.ts,
|
||||||
|
user-input/ts/app/little-tour.component.ts
|
||||||
|
`,'',
|
||||||
|
`click-me.component.ts,
|
||||||
|
keyup.components.ts,
|
||||||
|
loop-back.component.ts,
|
||||||
|
little-tour.component.ts`)
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Loading…
Reference in New Issue