> For the complete documentation index, see [llms.txt](https://m335.ict-bz.ch/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://m335.ict-bz.ch/tag-1/tour-of-heroes/1.-the-hero-editor.md).

# 1. The hero editor

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](https://v17.angular.io/generated/live-examples/toh-pt1/stackblitz.html) / [download example](https://v17.angular.io/generated/zips/toh-pt1/toh-pt1.zip).

## Create the heroes component <a href="#create-the-heroes-component" id="create-the-heroes-component"></a>

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:

{% tabs %}
{% tab title="app/heroes/heroes.component.ts (initial version)" %}

```typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css'],
})
export class HeroesComponent {
}
```

{% endtab %}
{% endtabs %}

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](https://developer.mozilla.org/docs/Web/CSS/Type_selectors), `'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`.

### Add a `hero` property <a href="#add-a-hero-property" id="add-a-hero-property"></a>

Add a `hero` property to the `HeroesComponent` for a hero named, `Windstorm`.

{% tabs %}
{% tab title="heroes.component.ts (hero property)" %}

```typescript
hero = 'Windstorm';
```

{% endtab %}
{% endtabs %}

### Show the hero <a href="#show-the-hero" id="show-the-hero"></a>

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.

{% tabs %}
{% tab title="heroes.component.html" %}

```html
<h2>{{hero}}</h2>
```

{% endtab %}
{% endtabs %}

## Show the `HeroesComponent` view <a href="#show-the-heroescomponent-view" id="show-the-heroescomponent-view"></a>

To 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.

{% tabs %}
{% tab title="src/app/app.component.html" %}

```html
<h1>{{title}}</h1>
<app-heroes></app-heroes>
```

{% endtab %}
{% endtabs %}

If `ng serve` is still running, the browser should refresh and display both the application title and the hero's name.

<figure><img src="/files/VGeR38aLpsNRk4JSqrOq" alt="" width="117"><figcaption></figcaption></figure>

Tipp von Jason:

> Wenn du wie von uns vorgeschlagen Webstorm als IDE verwendest, können Module mit den folgenden Tastenkürzel einfach importiert werden.
>
> Windows / Linux: `Alt + Enter`
>
> Mac: `Option + Enter`

## Create a `Hero` interface <a href="#create-a-hero-interface" id="create-a-hero-interface"></a>

A 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.

{% tabs %}
{% tab title="src/app/hero.ts" %}

```typescript
export interface Hero {
  id: number;
  name: string;
}
```

{% endtab %}
{% endtabs %}

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:

{% tabs %}
{% tab title="src/app/heroes/heroes.component.ts" %}

```typescript
import {  } from '@angular/core';
import { Hero } from '../hero';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css'],
  standalone: true,
})
export class HeroesComponent {
  hero: Hero = {
    id: 1,
    name: 'Windstorm'
  };
}
```

{% endtab %}
{% endtabs %}

The page no longer displays properly because you changed the hero from a string to an object.

## Show the hero object <a href="#show-the-hero-object" id="show-the-hero-object"></a>

Update the binding in the template to announce the hero's name and show both `id` and `name` in a details display like this:

{% tabs %}
{% tab title="heroes.component.html (HeroesComponent template)" %}

```html
<h2>{{hero.name}} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div><span>name: </span>{{hero.name}}</div>
```

{% endtab %}
{% endtabs %}

The browser refreshes and displays the hero's information.

## Format with the `UppercasePipe` <a href="#format-with-the-uppercasepipe" id="format-with-the-uppercasepipe"></a>

Edit the `hero.name` binding like this:

{% tabs %}
{% tab title="src/app/heroes/heroes.component.html" %}

```html
<h2>{{hero.name | uppercase}} Details</h2>
```

{% endtab %}
{% endtabs %}

The browser refreshes and now the hero's name is displayed in capital letters.

The word [`uppercase`](https://v17.angular.io/api/common/UpperCasePipe) in the interpolation binding after the pipe `|` character, activates the built-in `UppercasePipe`.

[Pipes](https://v17.angular.io/guide/pipes-overview) 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.

## Edit the hero <a href="#edit-the-hero" id="edit-the-hero"></a>

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.

### Two-way binding <a href="#two-way-binding" id="two-way-binding"></a>

Refactor the details area in the `HeroesComponent` template so it looks like this:

{% tabs %}
{% tab title="src/app/heroes/heroes.component.html (HeroesComponent's template)" %}

```html
<div>
  <label for="name">Hero name: </label>
  <input id="name" [(ngModel)]="hero.name" placeholder="name">
</div>
```

{% endtab %}
{% endtabs %}

`[(`[`ngModel`](https://v17.angular.io/api/forms/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`.

#### The missing [`FormsModule`](https://v17.angular.io/api/forms/FormsModule) <a href="#the-missing-formsmodule" id="the-missing-formsmodule"></a>

Notice that the application stopped working when you added `[(`[`ngModel`](https://v17.angular.io/api/forms/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`](https://v17.angular.io/api/forms/NgModel) is a valid Angular directive, it isn't available by default.

It belongs to the optional [`FormsModule`](https://v17.angular.io/api/forms/FormsModule) and you must *opt in* to using it.

{% tabs %}
{% tab title=" src/app/heroes/heroes.component.ts" %}

```typescript
import { Component } from '@angular/core';
import { Hero } from '../hero';
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here


@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css'],
  standalone: true,
  imports: [
    BrowserModule,
    FormsModule, // <-- Import the forms module
  ],
})
export class HeroesComponent {
  // ...
}
```

{% endtab %}
{% endtabs %}

## Final code review <a href="#final-code-review" id="final-code-review"></a>

Here are the code files discussed on this page.

{% tabs %}
{% tab title=" src/app/heroes/heroes.component.ts" %}

```typescript
import { Component } from '@angular/core';
import { Hero } from '../hero';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css'],
  standalone: true,
  imports: [
    BrowserModule,
    FormsModule,
  ],
})
export class HeroesComponent {
  hero: Hero = {
    id: 1,
    name: 'Windstorm'
  };
}
```

{% endtab %}

{% tab title="src/app/heroes/heroes.component.html" %}

```html
<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>
```

{% endtab %}

{% tab title="src/app/app.component.ts" %}

```typescript
@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss'],
    standalone: true,
    imports: [RouterLink, RouterOutlet, MessagesComponent]
})
export class AppComponent {
  title = 'Tour of Heroes';
}
```

{% endtab %}

{% tab title="src/app.app.component.html" %}

```html
<h1>{{title}}</h1>
<app-heroes></app-heroes>
```

{% endtab %}

{% tab title="src/app/hero.ts" %}

```typescript
export interface Hero {
  id: number;
  name: string;
}
```

{% endtab %}
{% endtabs %}

## Summary <a href="#summary" id="summary"></a>

* You used `ng generate` to create a second `HeroesComponent`.
* You displayed the `HeroesComponent` by adding it to the `AppComponent` shell.
* You applied the `UppercasePipe` to format the name.
* You used two-way data binding with the [`ngModel`](https://v17.angular.io/api/forms/NgModel) directive.
* You learned about the `AppModule`.
* You imported the [`FormsModule`](https://v17.angular.io/api/forms/FormsModule) in the `AppModule` so that Angular would recognize and apply the [`ngModel`](https://v17.angular.io/api/forms/NgModel) directive.
* You learned the importance of declaring components in the `AppModule`.

## -> Hier geht es weiter

{% content-ref url="/pages/XtrwCjRwMyWg08sUPoO4" %}
[Hinweise und Zusatzaufgaben zu Kapitel 1](/tag-1/tour-of-heroes/1.-the-hero-editor/hinweise-und-zusatzaufgaben-zu-kapitel-1.md)
{% endcontent-ref %}
