[WIP] docs(user-input): Jessica's user input edits (#2683)
This commit is contained in:
parent
fc303c0697
commit
694b58d06e
@ -20,15 +20,14 @@ export class KeyUpComponent_v1 {
|
|||||||
// #enddocregion key-up-component-1-class, key-up-component-1-class-no-type
|
// #enddocregion key-up-component-1-class, key-up-component-1-class-no-type
|
||||||
/*
|
/*
|
||||||
// #docregion key-up-component-1-class-no-type
|
// #docregion key-up-component-1-class-no-type
|
||||||
// without strong typing
|
onKey(event:any) { // without type info
|
||||||
onKey(event:any) {
|
|
||||||
this.values += event.target.value + ' | ';
|
this.values += event.target.value + ' | ';
|
||||||
}
|
}
|
||||||
// #enddocregion key-up-component-1-class-no-type
|
// #enddocregion key-up-component-1-class-no-type
|
||||||
*/
|
*/
|
||||||
// #docregion key-up-component-1-class
|
// #docregion key-up-component-1-class
|
||||||
// with strong typing
|
|
||||||
onKey(event: KeyboardEvent) {
|
onKey(event: KeyboardEvent) { // with type info
|
||||||
this.values += (<HTMLInputElement>event.target).value + ' | ';
|
this.values += (<HTMLInputElement>event.target).value + ' | ';
|
||||||
}
|
}
|
||||||
// #docregion key-up-component-1-class-no-type
|
// #docregion key-up-component-1-class-no-type
|
||||||
@ -53,23 +52,22 @@ export class KeyUpComponent_v2 {
|
|||||||
}
|
}
|
||||||
// #enddocregion key-up-component-2
|
// #enddocregion key-up-component-2
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
|
|
||||||
// #docregion key-up-component-3
|
// #docregion key-up-component-3
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'key-up3',
|
selector: 'key-up3',
|
||||||
template: `
|
template: `
|
||||||
<input #box (keyup.enter)="values=box.value">
|
<input #box (keyup.enter)="onEnter(box.value)">
|
||||||
<p>{{values}}</p>
|
<p>{{value}}</p>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class KeyUpComponent_v3 {
|
export class KeyUpComponent_v3 {
|
||||||
values = '';
|
value = '';
|
||||||
|
onEnter(value: string) { this.value = value; }
|
||||||
}
|
}
|
||||||
// #enddocregion key-up-component-3
|
// #enddocregion key-up-component-3
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
|
|
||||||
// #docregion key-up-component-4
|
// #docregion key-up-component-4
|
||||||
@ -77,13 +75,14 @@ export class KeyUpComponent_v3 {
|
|||||||
selector: 'key-up4',
|
selector: 'key-up4',
|
||||||
template: `
|
template: `
|
||||||
<input #box
|
<input #box
|
||||||
(keyup.enter)="values=box.value"
|
(keyup.enter)="update(box.value)"
|
||||||
(blur)="values=box.value">
|
(blur)="update(box.value)">
|
||||||
|
|
||||||
<p>{{values}}</p>
|
<p>{{value}}</p>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class KeyUpComponent_v4 {
|
export class KeyUpComponent_v4 {
|
||||||
values = '';
|
value = '';
|
||||||
|
update(value: string) { this.value = value; }
|
||||||
}
|
}
|
||||||
// #enddocregion key-up-component-4
|
// #enddocregion key-up-component-4
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
include ../_util-fns
|
include ../_util-fns
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
When the user clicks a link, pushes a button, or enters text
|
User actions such as clicking a link, pushing a button, and entering
|
||||||
we want to know about it. These user actions all raise DOM events.
|
text raise DOM events.
|
||||||
In this chapter we learn to bind to those events using the Angular
|
This page explains how to bind those events to component event handlers using the Angular
|
||||||
event binding syntax.
|
event binding syntax.
|
||||||
|
|
||||||
Run the <live-example></live-example>.
|
Run the <live-example></live-example>.
|
||||||
@ -11,136 +11,154 @@ include ../_util-fns
|
|||||||
:marked
|
:marked
|
||||||
## Binding to user input events
|
## Binding to user input events
|
||||||
|
|
||||||
We can use [Angular event bindings](./template-syntax.html#event-binding)
|
You can use [Angular event bindings](./template-syntax.html#event-binding)
|
||||||
to respond to [any DOM event](https://developer.mozilla.org/en-US/docs/Web/Events).
|
to respond to any [DOM event](https://developer.mozilla.org/en-US/docs/Web/Events).
|
||||||
|
Many DOM events are triggered by user input. Binding to these events provides a way to
|
||||||
|
get input from the user.
|
||||||
|
|
||||||
The syntax is simple. We surround the DOM event name in parentheses and assign a quoted template statement to it.
|
To bind to a DOM event, surround the DOM event name in parentheses and assign a quoted
|
||||||
As an example, here's an event binding that implements a click handler:
|
[template statement](./template-syntax.html#template-statements) to it.
|
||||||
|
|
||||||
|
The following example shows an event binding that implements a click handler:
|
||||||
+makeExample('user-input/ts/app/click-me.component.ts', 'click-me-button')(format=".", language="html")
|
+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
|
||||||
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 equals sign identifies the button's click event as the **target of the binding**.
|
||||||
The text within quotes on the right is the **template statement** in which we
|
The text in quotes to the right of the equals sign
|
||||||
respond to the click event by calling the component's `onClickMe` method. A [template statement](./template-syntax.html#template-statements) is a subset
|
is the **template statement**, which responds
|
||||||
of JavaScript with restrictions and a few added tricks.
|
to the click event by calling the component's `onClickMe` method.
|
||||||
|
|
||||||
When writing a binding we must be aware of a template statement's **execution context**.
|
When writing a binding, be aware of a template statement's **execution context**.
|
||||||
The identifiers appearing within a statement belong to a specific context object.
|
The identifiers in a template statement belong to a specific context object,
|
||||||
That object is usually the Angular component that controls the template ... which it definitely is
|
usually the Angular component controlling the template.
|
||||||
in this case because that snippet of HTML belongs to the following component:
|
The example above shows a single line of HTML, but that HTML belongs to a larger component:
|
||||||
|
|
||||||
+makeExample('user-input/ts/app/click-me.component.ts', 'click-me-component', 'app/click-me.component.ts')(format=".")
|
+makeExample('user-input/ts/app/click-me.component.ts', 'click-me-component', 'app/click-me.component.ts')(format=".")
|
||||||
:marked
|
:marked
|
||||||
When the user clicks the button, Angular calls the component's `onClickMe` method.
|
When the user clicks the button, Angular calls the `onClickMe` method from `ClickMeComponent`.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Get user input from the $event object
|
## Get user input from the $event object
|
||||||
We can bind to all kinds of events. Let's bind to the keyup event of an input box and replay
|
DOM events carry a payload of information that may be useful to the component.
|
||||||
what the user types back onto the screen.
|
This section shows how to bind to the `keyup` event of an input box to get the user's input after each keystroke.
|
||||||
|
|
||||||
This time we'll (1) listen to an event and (2) grab the user's input.
|
The following code listens to the `keyup` event and passes the entire event payload (`$event`) to the component event handler.
|
||||||
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-1-template', 'app/keyup.components.ts (template v.1)')(format=".")
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-1-template', 'app/keyup.components.ts (template v.1)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
Angular makes an event object available in the **`$event`** variable,
|
When a user presses and releases a key, the `keyup` event occurs, and Angular provides a corresponding
|
||||||
which we pass to the component's `onKey()` method.
|
DOM event object in the `$event` variable which this code passes as a parameter 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)')(format=".")
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-1-class-no-type', 'app/keyup.components.ts (class v.1)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
The shape of the `$event` object is determined by whatever raises the event.
|
The properties of an `$event` object vary depending on the type of DOM event. For example,
|
||||||
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).
|
a mouse event includes different information than a input box editing event.
|
||||||
The `$event.target` gives us an
|
|
||||||
[`HTMLInputElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement), which
|
|
||||||
has a `value` property that contains our user input data.
|
|
||||||
|
|
||||||
The `onKey()` component method is where we extract the user's input
|
All [standard DOM event objects](https://developer.mozilla.org/en-US/docs/Web/API/Event)
|
||||||
from the event object, adding that input to the list of user data that we're accumulating in the component's `values` property.
|
have a `target` property, a reference to the element that raised the event.
|
||||||
We then use [interpolation](./template-syntax.html#interpolation)
|
In this case, `target` refers to the [`<input>` element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) and
|
||||||
to display the accumulating `values` property back on screen.
|
`event.target.value` returns the current contents of that element.
|
||||||
|
|
||||||
Enter the letters "abc", and then backspace to remove them.
|
After each call, the `onKey()` method appends the contents of the input box value to the list
|
||||||
|
in the component's `values` property, followed by a separator character (|).
|
||||||
|
The [interpolation](./template-syntax.html#interpolation)
|
||||||
|
displays the accumulating input box changes from the `values` property.
|
||||||
|
|
||||||
|
Suppose the user enters the letters "abc", and then backspaces to remove them one by one.
|
||||||
Here's what the UI displays:
|
Here's what the UI displays:
|
||||||
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
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
We cast the `$event` as an `any` type, which means we've abandoned strong typing
|
Alternatively, you could accumulate the individual keys themselves by substituting `event.key`
|
||||||
to simplify our code. We generally prefer the strong typing that TypeScript affords.
|
for `event.target.value` in which case the same user input would produce:
|
||||||
We can rewrite the method, casting to HTML DOM objects like this.
|
code-example().
|
||||||
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-1-class', 'app/keyup.components.ts (class v.1 - strongly typed )')(format=".")
|
a | b | c | backspace | backspace | backspace |
|
||||||
: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.
|
a#keyup1
|
||||||
:marked
|
:marked
|
||||||
|
### Type the _$event_
|
||||||
|
|
||||||
|
The example above casts the `$event` as an `any` type.
|
||||||
|
That simplifies the code at a cost.
|
||||||
|
There is no type information
|
||||||
|
that could reveal properties of the event object and prevent silly mistakes.
|
||||||
|
|
||||||
|
The following example rewrites the method with types:
|
||||||
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-1-class', 'app/keyup.components.ts (class v.1 - typed )')(format=".")
|
||||||
|
|
||||||
|
:marked
|
||||||
|
The `$event` is now a specific `KeyboardEvent`.
|
||||||
|
Not all elements have a `value` property so it casts `target` to an input element.
|
||||||
|
The `OnKey` method more clearly expresses what it expects from the template and how it interprets the event.
|
||||||
|
|
||||||
|
### Passing _$event_ is a dubious practice
|
||||||
|
Typing the event object reveals a significant objection to passing the entire DOM event into the method:
|
||||||
|
the component has too much awareness of the template details.
|
||||||
|
It can't extract information without knowing more than it should about the HTML implementation.
|
||||||
|
That breaks the separation of concerns between the template (_what the user sees_)
|
||||||
|
and the component (_how the application processes user data_).
|
||||||
|
|
||||||
|
The next section shows how to use template reference variables to address this problem.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Get user input from a template reference variable
|
## Get user input from a template reference variable
|
||||||
There's another way to get the user data without the `$event` variable.
|
There's another way to get the user data: use Angular
|
||||||
|
[**template reference variables**](./template-syntax.html#ref-vars).
|
||||||
|
These variables provide direct access to an element from within the template.
|
||||||
|
To declare a template reference variable, precede an identifier with a hash (or pound) character (#).
|
||||||
|
|
||||||
Angular has a syntax feature called [**template reference variables**](./template-syntax.html#ref-vars).
|
The following example uses a template reference variable
|
||||||
These variables grant us direct access to an element.
|
to implement a keystroke loopback in a simple template.
|
||||||
We declare a template reference variable by preceding an identifier with a hash/pound character (#).
|
|
||||||
|
|
||||||
Here's an example of using a template reference variable
|
|
||||||
to implement a clever keystroke loopback in an ultra-simple template.
|
|
||||||
+makeExample('user-input/ts/app/loop-back.component.ts', 'loop-back-component', 'app/loop-back.component.ts')(format=".")
|
+makeExample('user-input/ts/app/loop-back.component.ts', 'loop-back-component', 'app/loop-back.component.ts')(format=".")
|
||||||
:marked
|
:marked
|
||||||
We've declared a template reference variable named `box` on the `<input>` element.
|
The template reference variable named `box`, declared on the `<input>` element,
|
||||||
The `box` variable is a reference to the `<input>` element itself, which means we can
|
refers to the `<input>` element itself.
|
||||||
grab the input element's `value` and display it
|
The code uses the `box` variable to get the input element's `value` and display it
|
||||||
with interpolation between `<p>` tags.
|
with interpolation between `<p>` tags.
|
||||||
|
|
||||||
The template is completely self contained. It doesn't bind to the component,
|
The template is completely self contained. It doesn't bind to the component,
|
||||||
and the component does nothing.
|
and the component does nothing.
|
||||||
|
|
||||||
Type in the input box, and watch the display update with each keystroke. *Voila!*
|
Type something in the input box, and watch the display update with each keystroke.
|
||||||
|
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/user-input/keyup-loop-back-anim.gif' alt="loop back")
|
img(src='/resources/images/devguide/user-input/keyup-loop-back-anim.gif' alt="loop back")
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
**This won't work at all unless we bind to an event**.
|
**This won't work at all unless you bind to an event**.
|
||||||
|
|
||||||
Angular only updates the bindings (and therefore the screen)
|
Angular updates the bindings (and therefore the screen)
|
||||||
if we do something in response to asynchronous events such as keystrokes.
|
only if the app does something in response to asynchronous events, such as keystrokes.
|
||||||
|
This example code binds the `keyup` event
|
||||||
That's why we bind the `keyup` event to a statement that does ... well, nothing.
|
to the number 0, the shortest template statement possible.
|
||||||
We're binding to the number 0, the shortest statement we can think of.
|
While the statement does nothing useful,
|
||||||
That is all it takes to keep Angular happy. We said it would be clever!
|
it satisfies Angular's requirement so that Angular will update the screen.
|
||||||
:marked
|
:marked
|
||||||
That template reference variable is intriguing. It's clearly easier to get to the textbox with that
|
It's easier to get to the input box with the template reference
|
||||||
variable than to go through the `$event` object. Maybe we can rewrite our previous
|
variable than to go through the `$event` object. Here's a rewrite of the previous
|
||||||
keyup example so that it uses the variable to get the user's input. Let's give it a try.
|
`keyup` example that uses a template reference variable to get the user's input.
|
||||||
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-2' ,'app/keyup.components.ts (v2)')(format=".")
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-2' ,'app/keyup.components.ts (v2)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
That sure seems easier.
|
A nice aspect of this approach is that the component 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.
|
|
||||||
It no longer requires knowledge of the `$event` and its structure.
|
It no longer requires knowledge of the `$event` and its structure.
|
||||||
|
|
||||||
<a id="key-event"></a>
|
<a id="key-event"></a>
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Key event filtering (with `key.enter`)
|
## Key event filtering (with `key.enter`)
|
||||||
Perhaps we don't care about every keystroke.
|
The `(keyup)` event handler hears *every keystroke*.
|
||||||
Maybe we're only interested in the input box value when the user presses Enter, and we'd like to ignore all other keys.
|
Sometimes only the _Enter_ key matters, because it signals that the user has finished typing.
|
||||||
When we bind to the `(keyup)` event, our event handling statement hears *every keystroke*.
|
One way to reduce the noise would be to examine every `$event.keyCode` and take action only when the key is _Enter_.
|
||||||
We could filter the keys first, examining every `$event.keyCode`, and update the `values` property only if the key is Enter.
|
|
||||||
|
|
||||||
Angular can filter the key events for us. Angular has a special syntax for keyboard events.
|
There's an easier way: bind to Angular's `keyup.enter` pseudo-event.
|
||||||
We can listen for just the Enter key by binding to Angular's `keyup.enter` pseudo-event.
|
Then Angular calls the event handler only when the user presses _Enter_.
|
||||||
|
|
||||||
Only then do we update the component's `values` property. (In this example,
|
|
||||||
the update happens inside the event binding statement. A better practice
|
|
||||||
would be to put the update code in the component.)
|
|
||||||
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-3' ,'app/keyup.components.ts (v3)')(format=".")
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-3' ,'app/keyup.components.ts (v3)')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Here's how it works.
|
Here's how it works.
|
||||||
figure.image-display
|
figure.image-display
|
||||||
@ -150,76 +168,53 @@ figure.image-display
|
|||||||
:marked
|
:marked
|
||||||
## On blur
|
## On blur
|
||||||
|
|
||||||
Our previous example won't transfer the current state of the input box if the user mouses away and clicks
|
In the previous example, the current state of the input box
|
||||||
elsewhere on the page. We update the component's `values` property only when the user presses Enter
|
is lost if the user mouses away and clicks elsewhere on the page
|
||||||
while the focus is inside the input box.
|
without first pressing _Enter_.
|
||||||
|
The component's `value` property is updated only when the user presses _Enter_.
|
||||||
|
|
||||||
Let's fix that by listening to the input box's blur event as well.
|
To fix this issue, listen to both the _Enter_ key and the _blur_ event.
|
||||||
|
|
||||||
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-4' ,'app/keyup.components.ts (v4)')(format=".")
|
+makeExample('user-input/ts/app/keyup.components.ts', 'key-up-component-4' ,'app/keyup.components.ts (v4)')(format=".")
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Put it all together
|
## Put it all together
|
||||||
We learned how to [display data](./displaying-data.html) in the previous chapter.
|
The previous page showed how to [display data](./displaying-data.html).
|
||||||
We've acquired a small arsenal of event binding techniques in this chapter.
|
This page demonstrated event binding techniques.
|
||||||
|
|
||||||
Let's put it all together in a micro-app
|
Now, 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 the list.
|
||||||
The user can add a hero by first typing in the input box and then
|
The user can add a hero by typing the hero's name in the input box and
|
||||||
pressing Enter, clicking the Add button, or clicking elsewhere on the page.
|
clicking **Add**.
|
||||||
|
|
||||||
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 "Little Tour of Heroes" component.
|
Below is the "Little Tour of Heroes" component.
|
||||||
We'll call out the highlights after we bask briefly in its minimalist glory.
|
|
||||||
|
|
||||||
+makeExample('user-input/ts/app/little-tour.component.ts', 'little-tour', 'app/little-tour.component.ts')(format=".")
|
+makeExample('user-input/ts/app/little-tour.component.ts', 'little-tour', 'app/little-tour.component.ts')(format=".")
|
||||||
:marked
|
:marked
|
||||||
We've seen almost everything here before. A few things are new or bear repeating.
|
### Observations
|
||||||
|
|
||||||
### Use template variables to refer to elements
|
|
||||||
|
|
||||||
|
* **Use template variables to refer to elements** —
|
||||||
The `newHero` template variable refers to the `<input>` element.
|
The `newHero` template variable refers to the `<input>` element.
|
||||||
We can use `newHero` from any sibling or child of the `<input>` element.
|
You can reference `newHero` from any sibling or child of the `<input>` element.
|
||||||
|
|
||||||
Getting the element from a template variable makes the button click handler
|
* **Pass values, not elements** —
|
||||||
simpler. Without the variable, we'd have to use a fancy CSS selector
|
Instead of passing the `newHero` into the component's `addHero` method,
|
||||||
to find the input element.
|
get the input box value and pass *that* to `addHero`.
|
||||||
|
|
||||||
### Pass values, not elements
|
* **Keep template statements simple** —
|
||||||
|
The `(blur)` event is bound to two JavaScript statements.
|
||||||
|
The first statement calls `addHero`. The second statement, `newHero.value=''`,
|
||||||
|
clears the input box after a new hero is added to the list.
|
||||||
|
|
||||||
We could have passed the `newHero` into the component's `addHero` method.
|
|
||||||
|
|
||||||
But that would require `addHero` to pick its way through the `<input>` DOM element,
|
|
||||||
something we learned to dislike in our first try at a [keyup component](#keyup1).
|
|
||||||
|
|
||||||
Instead, we grab the input box *value* and pass *that* to `addHero`.
|
|
||||||
The component knows nothing about HTML or the DOM, which is the way we like it.
|
|
||||||
|
|
||||||
### Keep template statements simple
|
|
||||||
We bound `(blur)` to *two* JavaScript statements.
|
|
||||||
|
|
||||||
We like the first one, which calls `addHero`.
|
|
||||||
We do not like the second one, which assigns an empty string to the input box value.
|
|
||||||
|
|
||||||
The second statement exists 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 the example *works*, we are rightly wary of JavaScript in HTML.
|
|
||||||
Template statements 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
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Source code
|
## Source code
|
||||||
|
|
||||||
Here is all the code we talked about in this chapter.
|
Following is all the code discussed in this page.
|
||||||
+makeTabs(`
|
+makeTabs(`
|
||||||
user-input/ts/app/click-me.component.ts,
|
user-input/ts/app/click-me.component.ts,
|
||||||
user-input/ts/app/keyup.components.ts,
|
user-input/ts/app/keyup.components.ts,
|
||||||
@ -235,10 +230,11 @@ figure.image-display
|
|||||||
:marked
|
:marked
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
We've mastered the basic primitives for responding to user input and gestures.
|
You have mastered the basic primitives for responding to user input and gestures.
|
||||||
As powerful as these primitives are, they are a bit clumsy for handling
|
|
||||||
large amounts of user input. We're operating down at the low level of events when
|
|
||||||
we should be writing two-way bindings between data entry fields and model properties.
|
|
||||||
|
|
||||||
Angular has a two-way binding called `NgModel`, which we'll learn about
|
These techniques are useful for small-scale demonstrations, but they
|
||||||
in the `Forms` chapter.
|
quickly become verbose and clumsy when handling large amounts of user input.
|
||||||
|
Two-way data binding is a more elegant and compact way to move
|
||||||
|
values between data entry fields and model properties.
|
||||||
|
The next page, `Forms`, explains how to write
|
||||||
|
two-way bindings with `NgModel`.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user