(docs) User Input - refactored to its own example and support blur event

This commit is contained in:
Ward Bell 2015-10-31 17:24:50 -07:00 committed by Naomi Black
parent dd0d44eb93
commit c4416cfb2c
11 changed files with 257 additions and 43 deletions

View File

@ -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>

View File

@ -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',

View File

@ -0,0 +1 @@
src/**/*.js

View File

@ -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"
}
}

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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 }

View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
}
}

View File

@ -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
elsewhere on the page. We only update the component's `values` property when the user presses "Enter" ## On blur
inside the input box.
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"
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