The application now has a basic title. Next, create a new component to display hero information and place that component in the application shell.
For the sample application that this page describes, see the live example.
Use ng generate to create a new component named heroes.
ng generate component heroes
ng generate creates a new directory , src/app/heroes/, and generates the three files of the HeroesComponent along with a test file.
The HeroesComponent class file is as follows:
import { Component } from '@angular/core';
@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent {
} You always import the Component symbol from the Angular core library and annotate the component class with @Component.
@Component is a decorator function that specifies the Angular metadata for the component.
ng generate created three metadata properties:
| Properties | Details |
|---|---|
selector | The component's CSS element selector. |
templateUrl | The location of the component's template file. |
styleUrls | The location of the component's private CSS styles. |
The CSS element selector, 'app-heroes', matches the name of the HTML element that identifies this component within a parent component's template.
Always export the component class so you can import it elsewhere … like in the AppModule.
hero propertyAdd a hero property to the HeroesComponent for a hero named, Windstorm.
hero = 'Windstorm';
Open the heroes.component.html template file. Delete the default text that ng generate created and replace it with a data binding to the new hero property.
<h2>{{hero}}</h2> HeroesComponent viewTo display the HeroesComponent, you must add it to the template of the shell AppComponent.
Remember that app-heroes is the element selector for the HeroesComponent. Add an <app-heroes> element to the AppComponent template file, just below the title.
<h1>{{title}}</h1>
<app-heroes></app-heroes> If ng serve is still running, the browser should refresh and display both the application title and the hero's name.
Hero interfaceA real hero is more than a name.
Create a Hero interface in its own file in the src/app directory . Give it id and name properties.
export interface Hero {
id: number;
name: string;
} Return to the HeroesComponent class and import the Hero interface.
Refactor the component's hero property to be of type Hero. Initialize it with an id of 1 and the name Windstorm.
The revised HeroesComponent class file should look like this:
import { Component } from '@angular/core';
import { Hero } from '../hero';
@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent {
hero: Hero = {
id: 1,
name: 'Windstorm'
};
} The page no longer displays properly because you changed the hero from a string to an object.
Update the binding in the template to announce the hero's name and show both id and name in a details display like this:
<h2>{{hero.name}} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div><span>name: </span>{{hero.name}}</div> The browser refreshes and displays the hero's information.
UppercasePipe
Edit the hero.name binding like this:
<h2>{{hero.name | uppercase}} Details</h2> The browser refreshes and now the hero's name is displayed in capital letters.
The word uppercase in the interpolation binding after the pipe | character, activates the built-in UppercasePipe.
Pipes are a good way to format strings, currency amounts, dates, and other display data. Angular ships with several built-in pipes and you can create your own.
Users should be able to edit the hero's name in an <input> text box.
The text box should both display the hero's name property and update that property as the user types. That means data flows from the component class out to the screen and from the screen back to the class.
To automate that data flow, set up a two-way data binding between the <input> form element and the hero.name property.
Refactor the details area in the HeroesComponent template so it looks like this:
<div> <label for="name">Hero name: </label> <input id="name" [(ngModel)]="hero.name" placeholder="name"> </div>
[(ngModel)] is Angular's two-way data binding syntax.
Here it binds the hero.name property to the HTML text box so that data can flow in both directions. Data can flow from the hero.name property to the text box and from the text box back to the hero.name.
FormsModule
Notice that the application stopped working when you added [(ngModel)].
To see the error, open the browser development tools and look in the console for a message like
Template parse errors: Can't bind to 'ngModel' since it isn't a known property of 'input'.
Although ngModel is a valid Angular directive, it isn't available by default.
It belongs to the optional FormsModule and you must opt in to using it.
AppModuleAngular needs to know how the pieces of your application fit together and what other files and libraries the application requires. This information is called metadata.
Some of the metadata is in the @Component decorators that you added to your component classes. Other critical metadata is in @NgModule decorators.
The most important @NgModule decorator annotates the top-level AppModule class.
ng new created an AppModule class in src/app/app.module.ts when it created the project. This is where you opt in to the FormsModule.
FormsModule
Open app.module.ts and import the FormsModule symbol from the @angular/forms library.
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here Add FormsModule to the imports array in @NgModule. The imports array contains the list of external modules that the application needs.
imports: [ BrowserModule, FormsModule ],
When the browser refreshes, the application should work again. You can edit the hero's name and see the changes reflected immediately in the <h2> above the text box.
HeroesComponent
Every component must be declared in exactly one NgModule.
You didn't declare the HeroesComponent. Why did the application work?
It worked because the ng generate declared HeroesComponent in AppModule when it created that component.
Open src/app/app.module.ts and find HeroesComponent imported near the top.
import { HeroesComponent } from './heroes/heroes.component'; The HeroesComponent is declared in the @NgModule.declarations array.
declarations: [ AppComponent, HeroesComponent ],
AppModuledeclares both application components,AppComponentandHeroesComponent.
Here are the code files discussed on this page.
import { Component } from '@angular/core';
import { Hero } from '../hero';
@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent {
hero: Hero = {
id: 1,
name: 'Windstorm'
};
} <h2>{{hero.name | uppercase}} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div>
<label for="name">Hero name: </label>
<input id="name" [(ngModel)]="hero.name" placeholder="name">
</div> import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here
import { AppComponent } from './app.component';
import { HeroesComponent } from './heroes/heroes.component';
@NgModule({
declarations: [
AppComponent,
HeroesComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { } import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Tour of Heroes';
} <h1>{{title}}</h1>
<app-heroes></app-heroes> export interface Hero {
id: number;
name: string;
} ng generate to create a second HeroesComponent.HeroesComponent by adding it to the AppComponent shell.UppercasePipe to format the name.ngModel directive.AppModule.FormsModule in the AppModule so that Angular would recognize and apply the ngModel directive.AppModule.
© 2010–2023 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://angular.io/tutorial/tour-of-heroes/toh-pt1