Spec-Zone.ru › Angular 2

Главная/Детальная страница

Создайте страницу "главная/детальная" со списком героев.

На этой странице вы расширите приложение Tour of Heroes, чтобы отобразить список героев и позволить пользователям выбрать героя и отобразить его подробности.

Когда вы закончите с этой страницей, приложение должно выглядеть так, как показано в этом примере.

Где вы остановились

Прежде чем продолжить работу на этой странице приложения Tour of Heroes, убедитесь, что у вас есть следующая структура после страницы Редактор героя. Если ваша структура не совпадает, вернитесь на эту страницу, чтобы выяснить, что вы упустили.

angular-tour-of-heroes
  src
    app
      app.component.ts
      app.module.ts
    main.ts
    index.html
    styles.css
    systemjs.config.js
    tsconfig.json
  node_modules ...
  package.json

Поддерживайте транспиляцию и работу приложения

Введите следующую команду в окне терминала:

npm start

Эта команда запускает компилятор TypeScript в режиме "наблюдения", автоматически перекомпилируя код при его изменении. Одновременно команда запускает приложение в браузере и обновляет браузер при изменении кода.

Вы можете продолжать разработку приложения Tour of Heroes, не прерывая перекомпиляцию или обновление браузера.

Отображение героев

Чтобы отобразить список героев, добавьте героев в шаблон представления.

Создание героев

Создайте массив из десяти героев.

src/app/app.component.ts (массив героев)

const HEROES: Hero[] = [
  { id: 11, name: 'Mr. Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];

Массив HEROES имеет тип Hero, класс, определённый на предыдущей странице. В конечном итоге это приложение будет получать список героев из веб-сервиса, но пока вы можете отображать модели героев.

Отображение героев

Создайте общедоступное свойство в AppComponent, которое отображает героев для привязки.

app.component.ts (свойство массива героев)

heroes = HEROES;

Тип heroes не определён, так как TypeScript выводит его из массива HEROES.

Данные о героях отделены от реализации класса, поскольку в конечном итоге имена героев будут получены из службы данных.

Отображение имён героев в шаблоне

Чтобы отобразить имена героев в неупорядоченном списке, вставьте следующий фрагмент HTML ниже заголовка и выше подробностей о герое.

app.component.ts (шаблон героев)

<h2>My Heroes</h2>
<ul class="heroes">
  <li>
    <!-- each hero goes here -->
  </li>
</ul>

Теперь вы можете заполнить шаблон именами героев.

Отображение героев с помощью ngFor

Цель состоит в том, чтобы связать массив heroes в компоненте с шаблоном, перебрать его и отобразить элементы по отдельности.

Измените тег <li> добавив встроенную директиву *ngFor.

app.component.ts (ngFor)

<li *ngFor="let hero of heroes">

Префикс (*) для ngFor является критической частью этого синтаксиса. Он указывает, что элемент <li> и его потомки составляют мастер-шаблон.

Директива ngFor итерирует массив heroes компонента и отображает экземпляр этого шаблона для каждого героя в этом массиве.

Часть выражения let hero определяет hero как переменную ввода шаблона, которая содержит текущий элемент героя для каждого итерационного цикла. Вы можете обратиться к этой переменной в шаблоне, чтобы получить доступ к свойствам текущего героя.

Дополнительную информацию о ngFor и переменных ввода шаблона можно найти в разделе «Отображение свойства массива с помощью *ngFor» страницы «Отображение данных» и разделе «ngFor» страницы «Синтаксис шаблонов».

Внутри тегов <li> добавьте содержимое, которое использует переменную шаблона hero для отображения свойств героя.

app.component.ts (шаблон ngFor)

<li *ngFor="let hero of heroes">
  <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>

После обновления браузера отобразится список героев.

Стилизация героев

Пользователи должны получить визуальные подсказки о том, над каким героем они наводят курсор и какой герой выбран.

Чтобы добавить стили в свой компонент, установите свойство styles декоратора @Component на следующие классы CSS:

src/app/app.component.ts (стили)

styles: [`
  .selected {
    background-color: #CFD8DC !important;
    color: white;
  }
  .heroes {
    margin: 0 0 2em 0;
    list-style-type: none;
    padding: 0;
    width: 15em;
  }
  .heroes li {
    cursor: pointer;
    position: relative;
    left: 0;
    background-color: #EEE;
    margin: .5em;
    padding: .3em 0;
    height: 1.6em;
    border-radius: 4px;
  }
  .heroes li.selected:hover {
    background-color: #BBD8DC !important;
    color: white;
  }
  .heroes li:hover {
    color: #607D8B;
    background-color: #DDD;
    left: .1em;
  }
  .heroes .text {
    position: relative;
    top: -3px;
  }
  .heroes .badge {
    display: inline-block;
    font-size: small;
    color: white;
    padding: 0.8em 0.7em 0 0.7em;
    background-color: #607D8B;
    line-height: 1em;
    position: relative;
    left: -1px;
    top: -4px;
    height: 1.8em;
    margin-right: .8em;
    border-radius: 4px 0 0 4px;
  }
`]

Помните о использовании обратных кавычек для многострочных строк.

Добавление этих стилей делает файл намного длиннее. На последующих страницах вы перенесёте стили в отдельный файл.

Когда вы назначаете стили компоненту, они ограничены этим конкретным компонентом. Эти стили применяются только к AppComponent и не влияют на внешний HTML.

Шаблон для отображения героев должен выглядеть следующим образом:

src/app/app.component.ts (стилизованные герои)

<h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

Выбор героя

Теперь приложение отображает список героев, а также одного героя в представлении подробностей. Но список и представление подробностей не связаны. Когда пользователи выбирают героя из списка, выбранный герой должен отображаться в представлении подробностей. Эта структура пользовательского интерфейса известна как «главная/детальная». В данном случае главная — это список героев, а детальная — выбранный герой.

Далее вы соедините главную с деталями через свойство компонента selectedHero, которое привязано к событию клика.

Добавление события клика

Добавьте привязку события клика к <li> следующим образом:

app.component.ts (фрагмент шаблона)

<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
  ...
</li>

Скобки обозначают событие <li> элемента как целевое. Выражение onSelect(hero) вызывает метод AppComponent, onSelect(), передавая переменную шаблона hero, в качестве аргумента. Это та же переменная hero , которую вы определили ранее в директиве ngFor.

Дополнительную информацию о привязке событий можно найти на странице «Ввод данных пользователя» и в разделе «Привязка событий» на странице «Синтаксис шаблонов».

Добавление обработчика клика для отображения выбранного героя

Вам больше не нужно свойство hero, поскольку вы больше не отображаете одного героя; вы отображаете список героев. Но пользователь сможет выбрать одного из героев, нажав на него. Поэтому замените свойство hero этим простым свойством selectedHero.

src/app/app.component.ts (selectedHero)

selectedHero: Hero;

Имена героев должны быть отменены до того, как пользователь выберет героя, поэтому вы не будете инициализировать selectedHero как вы делали с hero.

Добавьте метод onSelect, который устанавливает свойство selectedHero в значение hero, на которое пользователь нажимает.

src/app/app.component.ts (onSelect)

onSelect(hero: Hero): void {
  this.selectedHero = hero;
}

Шаблон всё ещё ссылается на старое свойство hero. Вместо этого привяжитесь к новому свойству selectedHero следующим образом:

app.component.ts (фрагмент шаблона)

<h2>{{selectedHero.name}} details!</h2>
<div><label>id: </label>{{selectedHero.id}}</div>
<div>
    <label>name: </label>
    <input [(ngModel)]="selectedHero.name" placeholder="name"/>
</div>

Скрыть пустые детали с помощью ngIf

При загрузке приложения selectedHero имеет значение undefined, и оно не будет определено до тех пор, пока вы не нажмёте на имя героя. Angular не может отобразить свойства undefined selectedHero и генерирует следующую ошибку, видимую в консоли браузера:

EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null]

Хотя selectedHero.name отображается в шаблоне, вы должны удерживать детали героя вне DOM до тех пор, пока не будет выбран герой.

Окружите HTML-содержимое деталей героя в шаблоне <div>. Затем добавьте встроенную директиву ngIf и установите её в свойство selectedHero компонента.

src/app/app.component.ts (ngIf)

<div *ngIf="selectedHero">
  <h2>{{selectedHero.name}} details!</h2>
  <div><label>id: </label>{{selectedHero.id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="selectedHero.name" placeholder="name"/>
  </div>
</div>

Не забывайте о звездочке (*) перед ngIf.

Приложение больше не терпит сбои, и список имён снова отображается в браузере.

Когда selectedHero отсутствует, директива ngIf удаляет HTML-содержимое подробностей героя из DOM. Нет необходимости беспокоиться об элементах и привязках подробностей героев.

Когда пользователь выбирает героя, selectedHero становится определённым, и ngIf помещает содержимое подробностей героя в DOM и вычисляет вложенные привязки.

Дополнительную информацию о ngIf и ngFor можно найти на странице «Структурные директивы» и в разделе «Встроенные директивы» на странице «Синтаксис шаблонов».

Стилизация выбранного героя

Хотя выбранные детали героя отображаются ниже списка, трудно идентифицировать выбранного героя в самом списке.

В метаданных styles , которые вы добавили выше, есть пользовательский класс CSS под названием selected. Чтобы сделать выбранного героя более заметным, вы примените этот класс selected к <li> при нажатии пользователем на имя героя. Например, при нажатии на "Магнета" он должен отображаться с отличительным, но нежным фоновым цветом, как показано ниже:

Selected hero

В шаблоне добавьте следующую привязку [class.selected] к <li>.

app.component.ts (установка класса CSS)

[class.selected]="hero === selectedHero"

Когда выражение (hero === selectedHero) имеет значение true, Angular добавляет класс CSS selected. Когда выражение имеет значение false, Angular удаляет класс CSS selected.

Дополнительную информацию о привязке [class] можно найти в руководстве по синтаксису шаблонов.

Окончательная версия <li> выглядит следующим образом:

app.component.ts (стилизация каждого героя)

<li *ngFor="let hero of heroes"
  [class.selected]="hero === selectedHero"
  (click)="onSelect(hero)">
  <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>

После нажатия на "Магнета" список должен выглядеть так:

Output of heroes list app

Вот полная версия app.component.ts на данный момент:

src/app/app.component.ts

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

export class Hero {
  id: number;
  name: string;
}

const HEROES: Hero[] = [
  { id: 11, name: 'Mr. Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];

@Component({
  selector: 'my-app',
  template: `
    <h1>{{title}}</h1>
    <h2>My Heroes</h2>
    <ul class="heroes">
      <li *ngFor="let hero of heroes"
        [class.selected]="hero === selectedHero"
        (click)="onSelect(hero)">
        <span class="badge">{{hero.id}}</span> {{hero.name}}
      </li>
    </ul>
    <div *ngIf="selectedHero">
      <h2>{{selectedHero.name}} details!</h2>
      <div><label>id: </label>{{selectedHero.id}}</div>
      <div>
        <label>name: </label>
        <input [(ngModel)]="selectedHero.name" placeholder="name"/>
      </div>
    </div>
  `,
  styles: [`
    .selected {
      background-color: #CFD8DC !important;
      color: white;
    }
    .heroes {
      margin: 0 0 2em 0;
      list-style-type: none;
      padding: 0;
      width: 15em;
    }
    .heroes li {
      cursor: pointer;
      position: relative;
      left: 0;
      background-color: #EEE;
      margin: .5em;
      padding: .3em 0;
      height: 1.6em;
      border-radius: 4px;
    }
    .heroes li.selected:hover {
      background-color: #BBD8DC !important;
      color: white;
    }
    .heroes li:hover {
      color: #607D8B;
      background-color: #DDD;
      left: .1em;
    }
    .heroes .text {
      position: relative;
      top: -3px;
    }
    .heroes .badge {
      display: inline-block;
      font-size: small;
      color: white;
      padding: 0.8em 0.7em 0 0.7em;
      background-color: #607D8B;
      line-height: 1em;
      position: relative;
      left: -1px;
      top: -4px;
      height: 1.8em;
      margin-right: .8em;
      border-radius: 4px 0 0 4px;
    }
  `]
})
export class AppComponent {
  title = 'Tour of Heroes';
  heroes = HEROES;
  selectedHero: Hero;

  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }
}

Путь, который вы прошли

Вот что вы достигли на этой странице:

  • Приложение Tour of Heroes отображает список выбираемых героев.
  • Вы добавили возможность выбора героя и отображения деталей героя.
  • Вы узнали, как использовать встроенные директивы ngIf и ngFor в шаблоне компонента.

Ваше приложение должно выглядеть так же, как этот живой пример.

Путь вперёд

Вы расширили приложение Tour of Heroes, но оно далеко от завершения. Вы не можете поместить всё приложение в один компонент. На следующей странице вы разделите приложение на подкомпоненты и заставите их работать вместе.

Следующий шаг

Несколько компонентов

© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://v2.angular.io/docs/ts/latest/tutorial/toh-pt2.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API