(docs) User Input - refactored to its own example and support blur event
This commit is contained in:
parent
dd0d44eb93
commit
c4416cfb2c
|
@ -78,9 +78,7 @@
|
||||||
<button on-click="onSave()">On Save</button>
|
<button on-click="onSave()">On Save</button>
|
||||||
<button (click)="onSave() || true">Save w/ propagation</button>
|
<button (click)="onSave() || true">Save w/ propagation</button>
|
||||||
|
|
||||||
<!-- #docregion click-me-button -->
|
|
||||||
<button (click)="onClickMe()">Click me!</button>
|
<button (click)="onClickMe()">Click me!</button>
|
||||||
<!-- #enddocregion click-me-button -->
|
|
||||||
|
|
||||||
<div class="parent-div" (click)="onClickMe($event)">Click me
|
<div class="parent-div" (click)="onClickMe($event)">Click me
|
||||||
<div class="child-div">Click me too!</div>
|
<div class="child-div">Click me too!</div>
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
//**** Referenced in template-syntax and user-input chapters
|
// NOT EVERYTHING IS NEEDED BY TEMPLATE-SYNTAX CHAPTER
|
||||||
// #docplaster
|
// Much left-over from support for "User Input" chapter such as
|
||||||
|
// ClickMeComponent,
|
||||||
|
// KeyUpComponent, KeyUpComponentV2, KeyUpComponentV3,
|
||||||
|
// LittleTour, LoopbackComponent,
|
||||||
|
// TODO: purge extraneous material
|
||||||
|
|
||||||
// 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
|
/// #docplaster
|
||||||
|
|
||||||
import {
|
import {bootstrap, Component, CORE_DIRECTIVES,
|
||||||
Input, Output,
|
Input, Output,
|
||||||
Directive,
|
Directive,
|
||||||
ElementRef, EventEmitter,
|
ElementRef, EventEmitter,
|
||||||
|
@ -93,7 +94,6 @@ class LittleHeroComponent {
|
||||||
hero: Hero;
|
hero: Hero;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #docregion click-me-component
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'click-me',
|
selector: 'click-me',
|
||||||
template: '<button (click)="onClickMe()">Click me</button>'
|
template: '<button (click)="onClickMe()">Click me</button>'
|
||||||
|
@ -103,18 +103,14 @@ class ClickMeComponent {
|
||||||
alert('You are my hero!')
|
alert('You are my hero!')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion click-me-component
|
|
||||||
|
|
||||||
// #docregion loop-back-component
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'loop-back',
|
selector: 'loop-back',
|
||||||
template: '<input #box (keyup)="0"> <p>{{box.value}}</p>'
|
template: '<input #box (keyup)="0"> <p>{{box.value}}</p>'
|
||||||
})
|
})
|
||||||
class LoopbackComponent {
|
class LoopbackComponent {
|
||||||
}
|
}
|
||||||
// #enddocregion loop-back-component
|
|
||||||
|
|
||||||
// #docregion key-up-component
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'key-up',
|
selector: 'key-up',
|
||||||
template: `
|
template: `
|
||||||
|
@ -129,9 +125,7 @@ class KeyUpComponent {
|
||||||
this.values += event.target.value + ' | ';
|
this.values += event.target.value + ' | ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion key-up-component
|
|
||||||
|
|
||||||
// #docregion key-up2-component
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'key-up2',
|
selector: 'key-up2',
|
||||||
template: `
|
template: `
|
||||||
|
@ -146,10 +140,7 @@ class KeyUpComponentV2 {
|
||||||
this.values += value + ' | ';
|
this.values += value + ' | ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion key-up2-component
|
|
||||||
|
|
||||||
|
|
||||||
// #docregion key-up3-component
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'key-up3',
|
selector: 'key-up3',
|
||||||
template: `
|
template: `
|
||||||
|
@ -161,10 +152,7 @@ class KeyUpComponentV2 {
|
||||||
class KeyUpComponentV3 {
|
class KeyUpComponentV3 {
|
||||||
values='';
|
values='';
|
||||||
}
|
}
|
||||||
// #enddocregion key-up3-component
|
|
||||||
|
|
||||||
// #docregion little-tour-of-heroes-app
|
|
||||||
// #docregion little-tour-of-heroes-component
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'little-tour',
|
selector: 'little-tour',
|
||||||
template: `
|
template: `
|
||||||
|
@ -185,10 +173,8 @@ class LittleTour {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion little-tour-of-heroes-component
|
|
||||||
|
|
||||||
bootstrap(LittleTour);
|
bootstrap(LittleTour);
|
||||||
// #enddocregion little-tour-of-heroes-app
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
src/**/*.js
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "angular2-template-syntax",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"tsc": "tsc -p src -w",
|
||||||
|
"start": "live-server --open=src"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"angular2": "2.0.0-alpha.44",
|
||||||
|
"systemjs": "0.19.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"live-server": "^0.8.1",
|
||||||
|
"typescript": "^1.6.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<!-- #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>
|
|
@ -0,0 +1,147 @@
|
||||||
|
// #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
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>User Input</title>
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
<script src="../node_modules/systemjs/dist/system.src.js"></script>
|
||||||
|
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
|
||||||
|
<script>
|
||||||
|
System.config({
|
||||||
|
packages: {'app': {defaultExtension: 'js'}}
|
||||||
|
});
|
||||||
|
System.import('app/app');
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<my-app>Loading...</my-app>
|
||||||
|
<hr>
|
||||||
|
<little-tour>Loading...</little-tour>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,9 @@
|
||||||
|
fieldset {border-style:none}
|
||||||
|
img {height: 100px;}
|
||||||
|
.box {border: 1px solid black; padding:3px}
|
||||||
|
.child-div {margin-left: 1em; font-weight: normal}
|
||||||
|
.hidden {display: none}
|
||||||
|
.parent-div {margin-top: 1em; font-weight: bold}
|
||||||
|
.special {font-weight:bold;}
|
||||||
|
.toe {margin-left: 1em; font-style: italic;}
|
||||||
|
little-hero {color:blue; font-size: smaller; background-color: Turquoise }
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES5",
|
||||||
|
"module": "commonjs",
|
||||||
|
"sourceMap": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"removeComments": false,
|
||||||
|
"noImplicitAny": false
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,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('template-syntax/ts/src/app/app.html', 'click-me-button')(format=".")
|
+makeExample('user-input/ts/src/app/app.html', 'click-me-button')(format=".")
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
The `(click)` to the left of the equal sign identifies the button's click event as the **target of the binding**.
|
The `(click)` to the left of the equal sign identifies the button's click event as the **target of the binding**.
|
||||||
|
@ -28,7 +28,7 @@ include ../../../../_includes/_util-fns
|
||||||
<!--
|
<!--
|
||||||
These sample can be found in http://plnkr.co/edit/mr63T5
|
These sample can be found in http://plnkr.co/edit/mr63T5
|
||||||
-->
|
-->
|
||||||
+makeExample('template-syntax/ts/src/app/app.ts', 'click-me-component')
|
+makeExample('user-input/ts/src/app/app.ts', 'click-me-component')
|
||||||
:markdown
|
:markdown
|
||||||
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.
|
||||||
|
@ -40,7 +40,7 @@ include ../../../../_includes/_util-fns
|
||||||
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 both listen to an event and grab the user's input.
|
||||||
+makeExample('template-syntax/ts/src/app/app.ts', 'key-up-component')
|
+makeExample('user-input/ts/src/app/app.ts', 'key-up-component')
|
||||||
:markdown
|
:markdown
|
||||||
Angular makes an event object available in the **`$event`** variable. The user data we want is in that variable somewhere.
|
Angular makes an event object available in the **`$event`** variable. The user data we want is in that variable somewhere.
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ code-example().
|
||||||
|
|
||||||
Let's demonstrate with a clever keystroke loopback in a single line of template HTML.
|
Let's demonstrate with a clever keystroke loopback in a single line of template HTML.
|
||||||
We don't actually need a dedicated component to do this but we'll make one anyway.
|
We don't actually need a dedicated component to do this but we'll make one anyway.
|
||||||
+makeExample('template-syntax/ts/src/app/app.ts', 'loop-back-component')
|
+makeExample('user-input/ts/src/app/app.ts', 'loop-back-component')
|
||||||
:markdown
|
:markdown
|
||||||
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
|
||||||
|
@ -91,7 +91,7 @@ code-example().
|
||||||
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('template-syntax/ts/src/app/app.ts', 'key-up2-component')
|
+makeExample('user-input/ts/src/app/app.ts', 'key-up2-component')
|
||||||
:markdown
|
:markdown
|
||||||
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.
|
||||||
|
@ -112,12 +112,20 @@ code-example().
|
||||||
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('template-syntax/ts/src/app/app.ts', 'key-up3-component')
|
+makeExample('user-input/ts/src/app/app.ts', 'key-up3-component')
|
||||||
.alert.is-helpful
|
|
||||||
:markdown
|
.l-main-section
|
||||||
We won't transfer the current state of the input box if the user mouses away or clicks
|
:markdown
|
||||||
|
## On blur
|
||||||
|
|
||||||
|
Our previous example won't transfer the current state of the input box if the user mouses away and clicks
|
||||||
elsewhere on the page. We only update the component's `values` property when the user presses "Enter"
|
elsewhere on the page. We only update the component's `values` property when the user presses "Enter"
|
||||||
inside the input box.
|
inside the input box.
|
||||||
|
|
||||||
|
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')
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:markdown
|
:markdown
|
||||||
## Put it all together
|
## Put it all together
|
||||||
|
@ -125,7 +133,9 @@ code-example().
|
||||||
We've acquired a small arsenal of event binding techniques in this chapter.
|
We've acquired a small arsenal of event binding techniques in this chapter.
|
||||||
|
|
||||||
Let's put it all together in a micro-app
|
Let's put it all together in a micro-app
|
||||||
that can display a list of heroes and add new heroes to that list.
|
that can display a list of heroes and add new heroes to that list
|
||||||
|
by typing in the input box and hitting "Enter", clicking "Add", or clicking
|
||||||
|
elsewhere on the page.
|
||||||
|
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/user-input/little-tour.png' alt="Little Tour of Heroes")
|
img(src='/resources/images/devguide/user-input/little-tour.png' alt="Little Tour of Heroes")
|
||||||
|
@ -135,7 +145,7 @@ figure.image-display
|
||||||
<!--
|
<!--
|
||||||
This example in http://plnkr.co/edit/JWeIqq
|
This example in http://plnkr.co/edit/JWeIqq
|
||||||
-->
|
-->
|
||||||
+makeExample('template-syntax/ts/src/app/app.ts', 'little-tour-of-heroes-app')
|
+makeExample('user-input/ts/src/app/app.ts', 'little-tour-of-heroes-app')
|
||||||
:markdown
|
:markdown
|
||||||
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.
|
||||||
|
|
||||||
|
@ -149,11 +159,6 @@ figure.image-display
|
||||||
The Angular workaround is to spell the declaration in "snake case". Angular translates "#new-hero"
|
The Angular workaround is to spell the declaration in "snake case". Angular translates "#new-hero"
|
||||||
to `newHero` for template expressions ... which is exactly what we want.
|
to `newHero` for template expressions ... which is exactly what we want.
|
||||||
|
|
||||||
### **keyup.enter filter**
|
|
||||||
We'll add a hero when the user clicks the "Add" button or hits the "Enter" key. We ignore all other keys.
|
|
||||||
We accept that we might lose the new hero if the user clicks elsewhere or leaves the page
|
|
||||||
without having hit "Enter" or the "Add" button first. Let's hope the users don't complain.
|
|
||||||
|
|
||||||
### **newHero refers to the `<input>` element**
|
### **newHero refers to the `<input>` element**
|
||||||
We can access the `newHero` variable from any sibling or child of 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
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 15 KiB |
Loading…
Reference in New Issue