5 lines
21 KiB
JSON

{
"id": "tutorial/toh-pt1",
"title": "The hero editor",
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/tutorial/toh-pt1.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=\"the-hero-editor\">The hero editor<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#the-hero-editor\"><i class=\"material-icons\">link</i></a></h1>\n<p>The application now has a basic title.\nNext you will create a new component to display hero information\nand place that component in the application shell.</p>\n<div class=\"alert is-helpful\">\n<p> For the sample app that this page describes, see the <live-example></live-example>.</p>\n</div>\n<h2 id=\"create-the-heroes-component\">Create the heroes component<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#create-the-heroes-component\"><i class=\"material-icons\">link</i></a></h2>\n<p>Using the Angular CLI, generate a new component named <code>heroes</code>.</p>\n<code-example language=\"sh\" class=\"code-shell\">\n ng generate component heroes\n</code-example>\n<p>The CLI creates a new folder, <code>src/app/heroes/</code>, and generates\nthe three files of the <code>HeroesComponent</code> along with a test file.</p>\n<p>The <code>HeroesComponent</code> class file is as follows:</p>\n<code-example path=\"toh-pt1/src/app/heroes/heroes.component.ts\" region=\"v1\" header=\"app/heroes/heroes.component.ts (initial version)\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a>, <a href=\"api/core/OnInit\" class=\"code-anchor\">OnInit</a> } from '@angular/core';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-heroes',\n templateUrl: './heroes.component.html',\n styleUrls: ['./heroes.component.css']\n})\nexport class HeroesComponent implements <a href=\"api/core/OnInit\" class=\"code-anchor\">OnInit</a> {\n\n constructor() { }\n\n ngOnInit() {\n }\n\n}\n\n</code-example>\n<p>You always import the <code><a href=\"api/core/Component\" class=\"code-anchor\">Component</a></code> symbol from the Angular core library\nand annotate the component class with <code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a></code>.</p>\n<p><code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a></code> is a decorator function that specifies the Angular metadata for the component.</p>\n<p>The CLI generated three metadata properties:</p>\n<ol>\n<li><code>selector</code>— the component's CSS element selector</li>\n<li><code>templateUrl</code>— the location of the component's template file.</li>\n<li><code>styleUrls</code>— the location of the component's private CSS styles.</li>\n</ol>\n<a id=\"selector\"></a>\n<p>The <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors\">CSS element selector</a>,\n<code>'app-heroes'</code>, matches the name of the HTML element that identifies this component within a parent component's template.</p>\n<p>The <code>ngOnInit()</code> is a <a href=\"guide/lifecycle-hooks#oninit\">lifecycle hook</a>.\nAngular calls <code>ngOnInit()</code> shortly after creating a component.\nIt's a good place to put initialization logic.</p>\n<p>Always <code>export</code> the component class so you can <code>import</code> it elsewhere ... like in the <code>AppModule</code>.</p>\n<h3 id=\"add-a-hero-property\">Add a <code>hero</code> property<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#add-a-hero-property\"><i class=\"material-icons\">link</i></a></h3>\n<p>Add a <code>hero</code> property to the <code>HeroesComponent</code> for a hero named \"Windstorm.\"</p>\n<code-example path=\"toh-pt1/src/app/heroes/heroes.component.ts\" region=\"add-hero\" header=\"heroes.component.ts (hero property)\">\nhero = 'Windstorm';\n\n</code-example>\n<h3 id=\"show-the-hero\">Show the hero<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#show-the-hero\"><i class=\"material-icons\">link</i></a></h3>\n<p>Open the <code>heroes.component.html</code> template file.\nDelete the default text generated by the Angular CLI and\nreplace it with a data binding to the new <code>hero</code> property.</p>\n<code-example path=\"toh-pt1/src/app/heroes/heroes.component.1.html\" header=\"heroes.component.html\" region=\"show-hero-1\">\n&#x3C;h2>{{hero}}&#x3C;/h2>\n\n</code-example>\n<h2 id=\"show-the-heroescomponent-view\">Show the <code>HeroesComponent</code> view<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#show-the-heroescomponent-view\"><i class=\"material-icons\">link</i></a></h2>\n<p>To display the <code>HeroesComponent</code>, you must add it to the template of the shell <code>AppComponent</code>.</p>\n<p>Remember that <code>app-heroes</code> is the <a href=\"tutorial/toh-pt1#selector\">element selector</a> for the <code>HeroesComponent</code>.\nSo add an <code>&#x3C;app-heroes></code> element to the <code>AppComponent</code> template file, just below the title.</p>\n<code-example path=\"toh-pt1/src/app/app.component.html\" header=\"src/app/app.component.html\">\n&#x3C;h1>{{title}}&#x3C;/h1>\n&#x3C;app-heroes>&#x3C;/app-heroes>\n\n\n</code-example>\n<p>Assuming that the CLI <code>ng serve</code> command is still running,\nthe browser should refresh and display both the application title and the hero name.</p>\n<h2 id=\"create-a-hero-interface\">Create a Hero interface<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#create-a-hero-interface\"><i class=\"material-icons\">link</i></a></h2>\n<p>A real hero is more than a name.</p>\n<p>Create a <code>Hero</code> interface in its own file in the <code>src/app</code> folder.\nGive it <code>id</code> and <code>name</code> properties.</p>\n<code-example path=\"toh-pt1/src/app/hero.ts\" header=\"src/app/hero.ts\">\nexport interface Hero {\n id: number;\n name: string;\n}\n\n\n</code-example>\n<p>Return to the <code>HeroesComponent</code> class and import the <code>Hero</code> interface.</p>\n<p>Refactor the component's <code>hero</code> property to be of type <code>Hero</code>.\nInitialize it with an <code>id</code> of <code>1</code> and the name <code>Windstorm</code>.</p>\n<p>The revised <code>HeroesComponent</code> class file should look like this:</p>\n<code-example path=\"toh-pt1/src/app/heroes/heroes.component.ts\" header=\"src/app/heroes/heroes.component.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a>, <a href=\"api/core/OnInit\" class=\"code-anchor\">OnInit</a> } from '@angular/core';\nimport { Hero } from '../hero';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-heroes',\n templateUrl: './heroes.component.html',\n styleUrls: ['./heroes.component.css']\n})\nexport class HeroesComponent implements <a href=\"api/core/OnInit\" class=\"code-anchor\">OnInit</a> {\n hero: Hero = {\n id: 1,\n name: 'Windstorm'\n };\n\n constructor() { }\n\n ngOnInit() {\n }\n\n}\n\n</code-example>\n<p>The page no longer displays properly because you changed the hero from a string to an object.</p>\n<h2 id=\"show-the-hero-object\">Show the hero object<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#show-the-hero-object\"><i class=\"material-icons\">link</i></a></h2>\n<p>Update the binding in the template to announce the hero's name\nand show both <code>id</code> and <code>name</code> in a details layout like this:</p>\n<code-example path=\"toh-pt1/src/app/heroes/heroes.component.1.html\" region=\"show-hero-2\" header=\"heroes.component.html (HeroesComponent&#x27;s template)\">\n&#x3C;h3>{{hero.name}} Details&#x3C;/h3>\n&#x3C;div>&#x3C;span>id: &#x3C;/span>{{hero.id}}&#x3C;/div>\n&#x3C;div>&#x3C;span>name: &#x3C;/span>{{hero.name}}&#x3C;/div>\n\n</code-example>\n<p>The browser refreshes and displays the hero's information.</p>\n<h2 id=\"format-with-the-uppercasepipe\">Format with the <em>UppercasePipe</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#format-with-the-uppercasepipe\"><i class=\"material-icons\">link</i></a></h2>\n<p>Modify the <code>hero.name</code> binding like this.\n<code-example path=\"toh-pt1/src/app/heroes/heroes.component.html\" header=\"src/app/heroes/heroes.component.html\" region=\"pipe\">\n&#x3C;h2>{{hero.name | <a href=\"api/common/UpperCasePipe\" class=\"code-anchor\">uppercase</a>}} Details&#x3C;/h2>\n\n</code-example></p>\n<p>The browser refreshes and now the hero's name is displayed in capital letters.</p>\n<p>The word <code><a href=\"api/common/UpperCasePipe\" class=\"code-anchor\">uppercase</a></code> in the interpolation binding,\nright after the pipe operator ( | ),\nactivates the built-in <code>UppercasePipe</code>.</p>\n<p><a href=\"guide/pipes\">Pipes</a> are a good way to format strings, currency amounts, dates and other display data.\nAngular ships with several built-in pipes and you can create your own.</p>\n<h2 id=\"edit-the-hero\">Edit the hero<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#edit-the-hero\"><i class=\"material-icons\">link</i></a></h2>\n<p>Users should be able to edit the hero name in an <code>&#x3C;input></code> textbox.</p>\n<p>The textbox should both <em>display</em> the hero's <code>name</code> property\nand <em>update</em> that property as the user types.\nThat means data flows from the component class <em>out to the screen</em> and\nfrom the screen <em>back to the class</em>.</p>\n<p>To automate that data flow, setup a two-way data binding between the <code>&#x3C;input></code> form element and the <code>hero.name</code> property.</p>\n<h3 id=\"two-way-binding\">Two-way binding<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#two-way-binding\"><i class=\"material-icons\">link</i></a></h3>\n<p>Refactor the details area in the <code>HeroesComponent</code> template so it looks like this:</p>\n<code-example path=\"toh-pt1/src/app/heroes/heroes.component.1.html\" region=\"name-input\" header=\"src/app/heroes/heroes.component.html (HeroesComponent&#x27;s template)\">\n&#x3C;div>\n &#x3C;label for=\"name\">Hero name: &#x3C;/label>\n &#x3C;input id=\"name\" [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"hero.name\" placeholder=\"name\">\n&#x3C;/div>\n\n</code-example>\n<p><strong>[(ngModel)]</strong> is Angular's two-way data binding syntax.</p>\n<p>Here it binds the <code>hero.name</code> property to the HTML textbox so that data can flow <em>in both directions:</em> from the <code>hero.name</code> property to the textbox, and from the textbox back to the <code>hero.name</code>.</p>\n<h3 id=\"the-missing-formsmodule\">The missing <em>FormsModule</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#the-missing-formsmodule\"><i class=\"material-icons\">link</i></a></h3>\n<p>Notice that the app stopped working when you added <code>[(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]</code>.</p>\n<p>To see the error, open the browser development tools and look in the console\nfor a message like</p>\n<code-example language=\"sh\" class=\"code-shell\">\nTemplate parse errors:\nCan't bind to 'ngModel' since it isn't a known property of 'input'.\n</code-example>\n<p>Although <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code> is a valid Angular directive, it isn't available by default.</p>\n<p>It belongs to the optional <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code> and you must <em>opt-in</em> to using it.</p>\n<h2 id=\"appmodule\"><em>AppModule</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#appmodule\"><i class=\"material-icons\">link</i></a></h2>\n<p>Angular needs to know how the pieces of your application fit together\nand what other files and libraries the app requires.\nThis information is called <em>metadata</em>.</p>\n<p>Some of the metadata is in the <code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a></code> decorators that you added to your component classes.\nOther critical metadata is in <a href=\"guide/ngmodules\"><code>@NgModule</code></a> decorators.</p>\n<p>The most important <code>@<a href=\"api/core/NgModule\" class=\"code-anchor\">NgModule</a></code> decorator annotates the top-level <strong>AppModule</strong> class.</p>\n<p>The Angular CLI generated an <code>AppModule</code> class in <code>src/app/app.module.ts</code> when it created the project.\nThis is where you <em>opt-in</em> to the <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code>.</p>\n<h3 id=\"import-formsmodule\">Import <em>FormsModule</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#import-formsmodule\"><i class=\"material-icons\">link</i></a></h3>\n<p>Open <code>AppModule</code> (<code>app.module.ts</code>) and import the <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code> symbol from the <code>@angular/forms</code> library.</p>\n<code-example path=\"toh-pt1/src/app/app.module.ts\" header=\"app.module.ts (FormsModule symbol import)\" region=\"formsmodule-js-import\">\nimport { <a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a> } from '@angular/forms'; // &#x3C;-- <a href=\"api/forms/NgModel\" class=\"code-anchor\">NgModel</a> lives here\n\n</code-example>\n<p>Then add <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code> to the <code>@<a href=\"api/core/NgModule\" class=\"code-anchor\">NgModule</a></code> metadata's <code>imports</code> array, which contains a list of external modules that the app needs.</p>\n<code-example path=\"toh-pt1/src/app/app.module.ts\" header=\"app.module.ts (@NgModule imports)\" region=\"ng-imports\">\nimports: [\n <a href=\"api/platform-browser/BrowserModule\" class=\"code-anchor\">BrowserModule</a>,\n <a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a>\n],\n\n</code-example>\n<p>When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the <code>&#x3C;h2></code> above the textbox.</p>\n<h3 id=\"declare-heroescomponent\">Declare <code>HeroesComponent</code><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#declare-heroescomponent\"><i class=\"material-icons\">link</i></a></h3>\n<p>Every component must be declared in <em>exactly one</em> <a href=\"guide/ngmodules\">NgModule</a>.</p>\n<p><em>You</em> didn't declare the <code>HeroesComponent</code>.\nSo why did the application work?</p>\n<p>It worked because the Angular CLI declared <code>HeroesComponent</code> in the <code>AppModule</code> when it generated that component.</p>\n<p>Open <code>src/app/app.module.ts</code> and find <code>HeroesComponent</code> imported near the top.\n<code-example path=\"toh-pt1/src/app/app.module.ts\" header=\"src/app/app.module.ts\" region=\"heroes-import\">\nimport { HeroesComponent } from './heroes/heroes.component';\n\n</code-example></p>\n<p>The <code>HeroesComponent</code> is declared in the <code>@<a href=\"api/core/NgModule#declarations\" class=\"code-anchor\">NgModule.declarations</a></code> array.\n<code-example path=\"toh-pt1/src/app/app.module.ts\" header=\"src/app/app.module.ts\" region=\"declarations\">\ndeclarations: [\n AppComponent,\n HeroesComponent\n],\n\n</code-example></p>\n<p>Note that <code>AppModule</code> declares both application components, <code>AppComponent</code> and <code>HeroesComponent</code>.</p>\n<h2 id=\"final-code-review\">Final code review<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#final-code-review\"><i class=\"material-icons\">link</i></a></h2>\n<p>Here are the code files discussed on this page.</p>\n<code-tabs>\n\n <code-pane header=\"src/app/heroes/heroes.component.ts\" path=\"toh-pt1/src/app/heroes/heroes.component.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a>, <a href=\"api/core/OnInit\" class=\"code-anchor\">OnInit</a> } from '@angular/core';\nimport { Hero } from '../hero';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'app-heroes',\n templateUrl: './heroes.component.html',\n styleUrls: ['./heroes.component.css']\n})\nexport class HeroesComponent implements <a href=\"api/core/OnInit\" class=\"code-anchor\">OnInit</a> {\n hero: Hero = {\n id: 1,\n name: 'Windstorm'\n };\n\n constructor() { }\n\n ngOnInit() {\n }\n\n}\n\n</code-pane>\n\n <code-pane header=\"src/app/heroes/heroes.component.html\" path=\"toh-pt1/src/app/heroes/heroes.component.html\">\n&#x3C;h2>{{hero.name | <a href=\"api/common/UpperCasePipe\" class=\"code-anchor\">uppercase</a>}} Details&#x3C;/h2>\n&#x3C;div>&#x3C;span>id: &#x3C;/span>{{hero.id}}&#x3C;/div>\n&#x3C;div>\n &#x3C;label for=\"name\">Hero name: &#x3C;/label>\n &#x3C;input id=\"name\" [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"hero.name\" placeholder=\"name\">\n&#x3C;/div>\n\n\n</code-pane>\n\n <code-pane header=\"src/app/app.module.ts\" path=\"toh-pt1/src/app/app.module.ts\">\nimport { <a href=\"api/platform-browser/BrowserModule\" class=\"code-anchor\">BrowserModule</a> } from '@angular/platform-browser';\nimport { <a href=\"api/core/NgModule\" class=\"code-anchor\">NgModule</a> } from '@angular/core';\nimport { <a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a> } from '@angular/forms'; // &#x3C;-- <a href=\"api/forms/NgModel\" class=\"code-anchor\">NgModel</a> lives here\n\nimport { AppComponent } from './app.component';\nimport { HeroesComponent } from './heroes/heroes.component';\n\n@<a href=\"api/core/NgModule\" class=\"code-anchor\">NgModule</a>({\n declarations: [\n AppComponent,\n HeroesComponent\n ],\n imports: [\n <a href=\"api/platform-browser/BrowserModule\" class=\"code-anchor\">BrowserModule</a>,\n <a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a>\n ],\n providers: [],\n bootstrap: [AppComponent]\n})\nexport class AppModule { }\n\n\n</code-pane>\n\n <code-pane header=\"src/app/app.component.ts\" path=\"toh-pt1/src/app/app.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-root',\n templateUrl: './app.component.html',\n styleUrls: ['./app.component.css']\n})\nexport class AppComponent {\n title = 'Tour of Heroes';\n}\n\n\n</code-pane>\n\n <code-pane header=\"src/app/app.component.html\" path=\"toh-pt1/src/app/app.component.html\">\n&#x3C;h1>{{title}}&#x3C;/h1>\n&#x3C;app-heroes>&#x3C;/app-heroes>\n\n\n</code-pane>\n\n <code-pane header=\"src/app/hero.ts\" path=\"toh-pt1/src/app/hero.ts\">\nexport interface Hero {\n id: number;\n name: string;\n}\n\n\n</code-pane>\n\n</code-tabs>\n<h2 id=\"summary\">Summary<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"tutorial/toh-pt1#summary\"><i class=\"material-icons\">link</i></a></h2>\n<ul>\n<li>You used the CLI to create a second <code>HeroesComponent</code>.</li>\n<li>You displayed the <code>HeroesComponent</code> by adding it to the <code>AppComponent</code> shell.</li>\n<li>You applied the <code>UppercasePipe</code> to format the name.</li>\n<li>You used two-way data binding with the <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code> directive.</li>\n<li>You learned about the <code>AppModule</code>.</li>\n<li>You imported the <code><a href=\"api/forms/FormsModule\" class=\"code-anchor\">FormsModule</a></code> in the <code>AppModule</code> so that Angular would recognize and apply the <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code> directive.</li>\n<li>You learned the importance of declaring components in the <code>AppModule</code>\nand appreciated that the CLI declared it for you.</li>\n</ul>\n\n \n</div>\n\n<!-- links to this doc:\n - guide/example-apps-list\n-->\n<!-- links from this doc:\n - api/common/UpperCasePipe\n - api/core/Component\n - api/core/NgModule\n - api/core/NgModule#declarations\n - api/core/OnInit\n - api/forms/FormsModule\n - api/forms/NgModel\n - api/platform-browser/BrowserModule\n - guide/lifecycle-hooks#oninit\n - guide/ngmodules\n - guide/pipes\n - tutorial/toh-pt1#add-a-hero-property\n - tutorial/toh-pt1#appmodule\n - tutorial/toh-pt1#create-a-hero-interface\n - tutorial/toh-pt1#create-the-heroes-component\n - tutorial/toh-pt1#declare-heroescomponent\n - tutorial/toh-pt1#edit-the-hero\n - tutorial/toh-pt1#final-code-review\n - tutorial/toh-pt1#format-with-the-uppercasepipe\n - tutorial/toh-pt1#import-formsmodule\n - tutorial/toh-pt1#selector\n - tutorial/toh-pt1#show-the-hero\n - tutorial/toh-pt1#show-the-hero-object\n - tutorial/toh-pt1#show-the-heroescomponent-view\n - tutorial/toh-pt1#summary\n - tutorial/toh-pt1#the-hero-editor\n - tutorial/toh-pt1#the-missing-formsmodule\n - tutorial/toh-pt1#two-way-binding\n - https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors\n - https://github.com/angular/angular/edit/master/aio/content/tutorial/toh-pt1.md?message=docs%3A%20describe%20your%20change...\n-->"
}