5 lines
24 KiB
JSON
5 lines
24 KiB
JSON
{
|
|
"id": "guide/user-input",
|
|
"title": "User input",
|
|
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/guide/user-input.md?message=docs%3A%20describe%20your%20change...\" aria-label=\"Suggest Edits\" title=\"Suggest Edits\"><i class=\"material-icons\" aria-hidden=\"true\" role=\"img\">mode_edit</i></a>\n</div>\n\n\n<div class=\"content\">\n <h1 id=\"user-input\">User input<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#user-input\"><i class=\"material-icons\">link</i></a></h1>\n<div class=\"callout is-critical\">\n<header>Marked for archiving</header>\n<p>To ensure that you have the best experience possible, this topic is marked for archiving until we determine\nthat it clearly conveys the most accurate information possible.</p>\n<p>In the meantime, this topic might be helpful: <a href=\"guide/event-binding\">Event binding</a>.</p>\n<p>If you think this content should not be archived, please file a <a href=\"https://github.com/angular/angular/issues/new?template=3-docs-bug.md\">GitHub issue</a>.</p>\n</div>\n<p>User actions such as clicking a link, pushing a button, and entering\ntext raise DOM events.\nThis page explains how to bind those events to component event handlers using the Angular\nevent binding syntax.</p>\n<p>Run the <live-example></live-example>.</p>\n<h2 id=\"binding-to-user-input-events\">Binding to user input events<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#binding-to-user-input-events\"><i class=\"material-icons\">link</i></a></h2>\n<p>You can use <a href=\"guide/event-binding\">Angular event bindings</a>\nto respond to any <a href=\"https://developer.mozilla.org/en-US/docs/Web/Events\">DOM event</a>.\nMany DOM events are triggered by user input. Binding to these events provides a way to\nget input from the user.</p>\n<p>To bind to a DOM event, surround the DOM event name in parentheses and assign a quoted\n<a href=\"guide/template-statements\">template statement</a> to it.</p>\n<p>The following example shows an event binding that implements a click handler:</p>\n<code-example path=\"user-input/src/app/click-me.component.ts\" region=\"click-me-button\" header=\"src/app/click-me.component.ts\">\n<button (click)=\"onClickMe()\">Click me!</button>\n\n</code-example>\n<a id=\"click\"></a>\n<p>The <code>(click)</code> to the left of the equals sign identifies the button's click event as the <strong>target of the binding</strong>.\nThe text in quotes to the right of the equals sign\nis the <strong>template statement</strong>, which responds\nto the click event by calling the component's <code>onClickMe</code> method.</p>\n<p>When writing a binding, be aware of a template statement's <strong>execution context</strong>.\nThe identifiers in a template statement belong to a specific context object,\nusually the Angular component controlling the template.\nThe example above shows a single line of HTML, but that HTML belongs to a larger component:</p>\n<code-example path=\"user-input/src/app/click-me.component.ts\" region=\"click-me-component\" header=\"src/app/click-me.component.ts\">\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-click-me',\n template: `\n <button (click)=\"onClickMe()\">Click me!</button>\n {{clickMessage}}`\n})\nexport class ClickMeComponent {\n clickMessage = '';\n\n onClickMe() {\n this.clickMessage = 'You are my hero!';\n }\n}\n\n</code-example>\n<p>When the user clicks the button, Angular calls the <code>onClickMe</code> method from <code>ClickMeComponent</code>.</p>\n<h2 id=\"get-user-input-from-the-event-object\">Get user input from the $event object<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#get-user-input-from-the-event-object\"><i class=\"material-icons\">link</i></a></h2>\n<p>DOM events carry a payload of information that may be useful to the component.\nThis section shows how to bind to the <code>keyup</code> event of an input box to get the user's input after each keystroke.</p>\n<p>The following code listens to the <code>keyup</code> event and passes the entire event payload (<code>$event</code>) to the component event handler.</p>\n<code-example path=\"user-input/src/app/keyup.components.ts\" region=\"key-up-component-1-template\" header=\"src/app/keyup.components.ts (template v.1)\">\ntemplate: `\n <input (keyup)=\"onKey($event)\">\n <p>{{values}}</p>\n`\n\n</code-example>\n<p>When a user presses and releases a key, the <code>keyup</code> event occurs, and Angular provides a corresponding\nDOM event object in the <code>$event</code> variable which this code passes as a parameter to the component's <code>onKey()</code> method.</p>\n<code-example path=\"user-input/src/app/keyup.components.ts\" region=\"key-up-component-1-class-no-type\" header=\"src/app/keyup.components.ts (class v.1)\">\nexport class KeyUpComponent_v1 {\n values = '';\n\n onKey(event: any) { // without type info\n this.values += event.target.value + ' | ';\n }\n}\n\n</code-example>\n<p>The properties of an <code>$event</code> object vary depending on the type of DOM event. For example,\na mouse event includes different information than an input box editing event.</p>\n<p>All <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Event\">standard DOM event objects</a>\nhave a <code>target</code> property, a reference to the element that raised the event.\nIn this case, <code>target</code> refers to the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement\"><code><input></code> element</a> and\n<code>event.target.value</code> returns the current contents of that element.</p>\n<p>After each call, the <code>onKey()</code> method appends the contents of the input box value to the list\nin the component's <code>values</code> property, followed by a separator character (|).\nThe <a href=\"guide/interpolation\">interpolation</a>\ndisplays the accumulating input box changes from the <code>values</code> property.</p>\n<p>Suppose the user enters the letters \"abc\", and then backspaces to remove them one by one.\nHere's what the UI displays:</p>\n<code-example>\n a | ab | abc | ab | a | |\n</code-example>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/user-input/keyup1-anim.gif\" alt=\"key up 1\" width=\"176\" height=\"100\">\n</div>\n<div class=\"alert is-helpful\">\n<p>Alternatively, you could accumulate the individual keys themselves by substituting <code>event.key</code>\nfor <code>event.target.value</code> in which case the same user input would produce:</p>\n<code-example>\n a | b | c | backspace | backspace | backspace |\n\n</code-example>\n</div>\n<a id=\"keyup1\"></a>\n<h3 id=\"type-the-event\">Type the <em>$event</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#type-the-event\"><i class=\"material-icons\">link</i></a></h3>\n<p>The example above casts the <code>$event</code> as an <code>any</code> type.\nThat simplifies the code at a cost.\nThere is no type information\nthat could reveal properties of the event object and prevent silly mistakes.</p>\n<p>The following example rewrites the method with types:</p>\n<code-example path=\"user-input/src/app/keyup.components.ts\" region=\"key-up-component-1-class\" header=\"src/app/keyup.components.ts (class v.1 - typed )\">\nexport class KeyUpComponent_v1 {\n values = '';\n\n\n onKey(event: KeyboardEvent) { // with type info\n this.values += (event.target as HTMLInputElement).value + ' | ';\n }\n}\n\n</code-example>\n<p>The <code>$event</code> is now a specific <code>KeyboardEvent</code>.\nNot all elements have a <code>value</code> property so it casts <code>target</code> to an input element.\nThe <code>OnKey</code> method more clearly expresses what it expects from the template and how it interprets the event.</p>\n<h3 id=\"passing-event-is-a-dubious-practice\">Passing <em>$event</em> is a dubious practice<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#passing-event-is-a-dubious-practice\"><i class=\"material-icons\">link</i></a></h3>\n<p>Typing the event object reveals a significant objection to passing the entire DOM event into the method:\nthe component has too much awareness of the template details.\nIt can't extract information without knowing more than it should about the HTML implementation.\nThat breaks the separation of concerns between the template (<em>what the user sees</em>)\nand the component (<em>how the application processes user data</em>).</p>\n<p>The next section shows how to use template reference variables to address this problem.</p>\n<h2 id=\"get-user-input-from-a-template-reference-variable\">Get user input from a template reference variable<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#get-user-input-from-a-template-reference-variable\"><i class=\"material-icons\">link</i></a></h2>\n<p>There's another way to get the user data: use Angular\n<a href=\"guide/template-reference-variables\"><strong>template reference variables</strong></a>.\nThese variables provide direct access to an element from within the template.\nTo declare a template reference variable, precede an identifier with a hash (or pound) character (#).</p>\n<p>The following example uses a template reference variable\nto implement a keystroke loopback in a simple template.</p>\n<code-example path=\"user-input/src/app/loop-back.component.ts\" region=\"loop-back-component\" header=\"src/app/loop-back.component.ts\">\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-loop-back',\n template: `\n <input #box (keyup)=\"0\">\n <p>{{box.value}}</p>\n `\n})\nexport class LoopbackComponent { }\n\n</code-example>\n<p>The template reference variable named <code>box</code>, declared on the <code><input></code> element,\nrefers to the <code><input></code> element itself.\nThe code uses the <code>box</code> variable to get the input element's <code>value</code> and display it\nwith interpolation between <code><p></code> tags.</p>\n<p>The template is completely self contained. It doesn't bind to the component,\nand the component does nothing.</p>\n<p>Type something in the input box, and watch the display update with each keystroke.</p>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/user-input/keyup-loop-back-anim.gif\" alt=\"loop back\" width=\"204\" height=\"100\">\n</div>\n<div class=\"alert is-helpful\">\n<p><strong>This won't work at all unless you bind to an event</strong>.</p>\n<p>Angular updates the bindings (and therefore the screen)\nonly if the app does something in response to asynchronous events, such as keystrokes.\nThis example code binds the <code>keyup</code> event\nto the number 0, the shortest template statement possible.\nWhile the statement does nothing useful,\nit satisfies Angular's requirement so that Angular will update the screen.</p>\n</div>\n<p>It's easier to get to the input box with the template reference\nvariable than to go through the <code>$event</code> object. Here's a rewrite of the previous\n<code>keyup</code> example that uses a template reference variable to get the user's input.</p>\n<code-example path=\"user-input/src/app/keyup.components.ts\" region=\"key-up-component-2\" header=\"src/app/keyup.components.ts (v2)\">\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-key-up2',\n template: `\n <input #box (keyup)=\"onKey(box.value)\">\n <p>{{values}}</p>\n `\n})\nexport class KeyUpComponent_v2 {\n values = '';\n onKey(value: string) {\n this.values += value + ' | ';\n }\n}\n\n</code-example>\n<p>A nice aspect of this approach is that the component gets clean data values from the view.\nIt no longer requires knowledge of the <code>$event</code> and its structure.\n<a id=\"key-event\"></a></p>\n<h2 id=\"key-event-filtering-with-keyenter\">Key event filtering (with <code>key.enter</code>)<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#key-event-filtering-with-keyenter\"><i class=\"material-icons\">link</i></a></h2>\n<p>The <code>(keyup)</code> event handler hears <em>every keystroke</em>.\nSometimes only the <em>Enter</em> key matters, because it signals that the user has finished typing.\nOne way to reduce the noise would be to examine every <code>$event.keyCode</code> and take action only when the key is <em>Enter</em>.</p>\n<p>There's an easier way: bind to Angular's <code>keyup.enter</code> pseudo-event.\nThen Angular calls the event handler only when the user presses <em>Enter</em>.</p>\n<code-example path=\"user-input/src/app/keyup.components.ts\" region=\"key-up-component-3\" header=\"src/app/keyup.components.ts (v3)\">\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-key-up3',\n template: `\n <input #box (keyup.enter)=\"onEnter(box.value)\">\n <p>{{value}}</p>\n `\n})\nexport class KeyUpComponent_v3 {\n value = '';\n onEnter(value: string) { this.value = value; }\n}\n\n</code-example>\n<p>Here's how it works.</p>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/user-input/keyup3-anim.gif\" alt=\"key up 3\" width=\"280\" height=\"100\">\n</div>\n<h2 id=\"on-blur\">On blur<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#on-blur\"><i class=\"material-icons\">link</i></a></h2>\n<p>In the previous example, the current state of the input box\nis lost if the user mouses away and clicks elsewhere on the page\nwithout first pressing <em>Enter</em>.\nThe component's <code>value</code> property is updated only when the user presses <em>Enter</em>.</p>\n<p>To fix this issue, listen to both the <em>Enter</em> key and the <em>blur</em> event.</p>\n<code-example path=\"user-input/src/app/keyup.components.ts\" region=\"key-up-component-4\" header=\"src/app/keyup.components.ts (v4)\">\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-key-up4',\n template: `\n <input #box\n (keyup.enter)=\"update(box.value)\"\n (blur)=\"update(box.value)\">\n\n <p>{{value}}</p>\n `\n})\nexport class KeyUpComponent_v4 {\n value = '';\n update(value: string) { this.value = value; }\n}\n\n</code-example>\n<h2 id=\"put-it-all-together\">Put it all together<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#put-it-all-together\"><i class=\"material-icons\">link</i></a></h2>\n<p>This page demonstrated several event binding techniques.</p>\n<p>Now, put it all together in a micro-app\nthat can display a list of heroes and add new heroes to the list.\nThe user can add a hero by typing the hero's name in the input box and\nclicking <strong>Add</strong>.</p>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/user-input/little-tour-anim.gif\" alt=\"Little Tour of Heroes\" width=\"472\" height=\"268\">\n</div>\n<p>Below is the \"Little Tour of Heroes\" component.</p>\n<code-example path=\"user-input/src/app/little-tour.component.ts\" region=\"little-tour\" header=\"src/app/little-tour.component.ts\">\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-little-tour',\n template: `\n <input #newHero\n (keyup.enter)=\"addHero(newHero.value)\"\n (blur)=\"addHero(newHero.value); newHero.value='' \">\n\n <button (click)=\"addHero(newHero.value)\">Add</button>\n\n <ul><li *<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let hero of heroes\">{{hero}}</li></ul>\n `\n})\nexport class LittleTourComponent {\n heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];\n addHero(newHero: string) {\n if (newHero) {\n this.heroes.push(newHero);\n }\n }\n}\n\n</code-example>\n<h3 id=\"observations\">Observations<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#observations\"><i class=\"material-icons\">link</i></a></h3>\n<ul>\n<li>\n<p><strong>Use template variables to refer to elements</strong> —\nThe <code>newHero</code> template variable refers to the <code><input></code> element.\nYou can reference <code>newHero</code> from any sibling or child of the <code><input></code> element.</p>\n</li>\n<li>\n<p><strong>Pass values, not elements</strong> —\nInstead of passing the <code>newHero</code> into the component's <code>addHero</code> method,\nget the input box value and pass <em>that</em> to <code>addHero</code>.</p>\n</li>\n<li>\n<p><strong>Keep template statements simple</strong> —\nThe <code>(blur)</code> event is bound to two JavaScript statements.\nThe first statement calls <code>addHero</code>. The second statement, <code>newHero.value=''</code>,\nclears the input box after a new hero is added to the list.</p>\n</li>\n</ul>\n<h2 id=\"source-code\">Source code<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#source-code\"><i class=\"material-icons\">link</i></a></h2>\n<p>Following is all the code discussed in this page.</p>\n<code-tabs>\n\n <code-pane header=\"click-me.component.ts\" path=\"user-input/src/app/click-me.component.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a> } from '@angular/core';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-click-me',\n template: `\n <button (click)=\"onClickMe()\">Click me!</button>\n {{clickMessage}}`\n})\nexport class ClickMeComponent {\n clickMessage = '';\n\n onClickMe() {\n this.clickMessage = 'You are my hero!';\n }\n}\n\n\n</code-pane>\n\n <code-pane header=\"keyup.components.ts\" path=\"user-input/src/app/keyup.components.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a> } from '@angular/core';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-key-up1',\n template: `\n <input (keyup)=\"onKey($event)\">\n <p>{{values}}</p>\n `\n})\nexport class KeyUpComponent_v1 {\n values = '';\n\n /*\n onKey(event: any) { // without type info\n this.values += event.target.value + ' | ';\n }\n */\n\n onKey(event: KeyboardEvent) { // with type info\n this.values += (event.target as HTMLInputElement).value + ' | ';\n }\n}\n\n//////////////////////////////////////////\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-key-up2',\n template: `\n <input #box (keyup)=\"onKey(box.value)\">\n <p>{{values}}</p>\n `\n})\nexport class KeyUpComponent_v2 {\n values = '';\n onKey(value: string) {\n this.values += value + ' | ';\n }\n}\n\n//////////////////////////////////////////\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-key-up3',\n template: `\n <input #box (keyup.enter)=\"onEnter(box.value)\">\n <p>{{value}}</p>\n `\n})\nexport class KeyUpComponent_v3 {\n value = '';\n onEnter(value: string) { this.value = value; }\n}\n\n//////////////////////////////////////////\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-key-up4',\n template: `\n <input #box\n (keyup.enter)=\"update(box.value)\"\n (blur)=\"update(box.value)\">\n\n <p>{{value}}</p>\n `\n})\nexport class KeyUpComponent_v4 {\n value = '';\n update(value: string) { this.value = value; }\n}\n\n\n</code-pane>\n\n <code-pane header=\"loop-back.component.ts\" path=\"user-input/src/app/loop-back.component.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a> } from '@angular/core';\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-loop-back',\n template: `\n <input #box (keyup)=\"0\">\n <p>{{box.value}}</p>\n `\n})\nexport class LoopbackComponent { }\n\n\n</code-pane>\n\n <code-pane header=\"little-tour.component.ts\" path=\"user-input/src/app/little-tour.component.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a> } from '@angular/core';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-little-tour',\n template: `\n <input #newHero\n (keyup.enter)=\"addHero(newHero.value)\"\n (blur)=\"addHero(newHero.value); newHero.value='' \">\n\n <button (click)=\"addHero(newHero.value)\">Add</button>\n\n <ul><li *<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let hero of heroes\">{{hero}}</li></ul>\n `\n})\nexport class LittleTourComponent {\n heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];\n addHero(newHero: string) {\n if (newHero) {\n this.heroes.push(newHero);\n }\n }\n}\n\n\n</code-pane>\n\n</code-tabs>\n<p>Angular also supports passive event listeners. For example, you can use the following steps to make the scroll event passive.</p>\n<ol>\n<li>Create a file <code>zone-flags.ts</code> under <code>src</code> directory.</li>\n<li>Add the following line into this file.</li>\n</ol>\n<code-example>\n(window as any)['__zone_symbol__PASSIVE_EVENTS'] = ['scroll'];\n</code-example>\n<ol start=\"3\">\n<li>In the <code>src/polyfills.ts</code> file, before importing zone.js, import the newly created <code>zone-flags</code>.</li>\n</ol>\n<code-example>\nimport './zone-flags';\nimport 'zone.js'; // Included with Angular CLI.\n</code-example>\n<p>After those steps, if you add event listeners for the <code>scroll</code> event, the listeners will be <code>passive</code>.</p>\n<h2 id=\"summary\">Summary<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/user-input#summary\"><i class=\"material-icons\">link</i></a></h2>\n<p>You have mastered the basic primitives for responding to user input and gestures.</p>\n<p>These techniques are useful for small-scale demonstrations, but they\nquickly become verbose and clumsy when handling large amounts of user input.\nTwo-way data binding is a more elegant and compact way to move\nvalues between data entry fields and model properties.\nThe <a href=\"guide/forms-overview\"><code>Forms</code></a> page explains how to write\ntwo-way bindings with <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">NgModel</a></code>.</p>\n\n \n</div>\n\n<!-- links to this doc:\n - guide/architecture-components\n - guide/example-apps-list\n - guide/forms\n-->\n<!-- links from this doc:\n - api/common/NgForOf\n - api/core/Component\n - api/forms/NgModel\n - guide/event-binding\n - guide/forms-overview\n - guide/interpolation\n - guide/template-reference-variables\n - guide/template-statements\n - guide/user-input#binding-to-user-input-events\n - guide/user-input#get-user-input-from-a-template-reference-variable\n - guide/user-input#get-user-input-from-the-event-object\n - guide/user-input#key-event-filtering-with-keyenter\n - guide/user-input#observations\n - guide/user-input#on-blur\n - guide/user-input#passing-event-is-a-dubious-practice\n - guide/user-input#put-it-all-together\n - guide/user-input#source-code\n - guide/user-input#summary\n - guide/user-input#type-the-event\n - guide/user-input#user-input\n - https://developer.mozilla.org/en-US/docs/Web/API/Event\n - https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement\n - https://developer.mozilla.org/en-US/docs/Web/Events\n - https://github.com/angular/angular/edit/master/aio/content/guide/user-input.md?message=docs%3A%20describe%20your%20change...\n - https://github.com/angular/angular/issues/new?template=3-docs-bug.md\n-->"
|
|
} |