Angular2: Не удается прочитать свойство 'name' из undefined
Я начинаю изучать Angular2. Я слежу за учебником Heroes, представленным в angular.io.
Все работало нормально до тех пор, пока его не раздражало беспорядок HTML с использованием шаблона, вместо этого я использовал URL-адрес шаблона и переместил HTML в файл с именем hero.html.
Создается ошибка: "Невозможно прочитать свойство" имя "undefined".
Как ни странно, переменная героев, которая указывает на массив объектов, может быть доступна, так что ngFor будет производить правильное количество тегов "li" в соответствии с количеством объектов в массиве. Однако доступ к данным объектов массива невозможен.
Кроме того, даже простая переменная, содержащая некоторый текст, не будет отображаться с помощью {{}} скобок в HTML (см. Приведенный код).
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './hero.html',
styleUrls:['./styles.css']
})
export class AppComponent {
title = 'Tour of Heroes';
heroes = HEROES;
selectedHero:Hero;
onSelect(hero: Hero):void{
this.selectedHero = hero;
}
}
export class Hero{
id: number;
name: string;
}
const HEROES: Hero[] = [
{ id: 1, name: 'Mr. Nice' },
{ id: 2, name: 'Narco' },
{ id: 3, name: 'Bombasto' },
{ id: 4, name: 'Celeritas' },
{ id: 5, name: 'Magneta' },
{ id: 6, name: 'RubberMan' },
{ id: 7, name: 'Dynama' },
{ id: 8, name: 'Dr IQ' },
{ id: 9, name: 'Magma' },
{ id: 10, name: 'Tornado' }
];
hero.html
<h1>{{title}}</h1>
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<h2>{{hero.name}} details!</h2>
<div>
<label>id: </label>{{hero.id}}
</div>
<div>
<label>name: </label>
<input [(ngModel)]="selectedHero.name" placeholder="name">
<div>
Вот фото:
![введите описание изображения здесь]()
Ответы
Ответ 1
Выбранная переменнаяHero имеет значение null в шаблоне, поэтому вы не можете привязать выбранноеHero.name как есть. Вам нужно использовать оператор elvis для этого случая:
<input [ngModel]="selectedHero?.name" (ngModelChange)="selectedHero.name = $event" />
Разделение [(ngModel)] в [ngModel] и (ngModelChange) также необходимо, потому что вы не можете назначить выражение, которое использует оператор elvis.
Я также думаю, что вы хотите использовать:
<h2>{{selectedHero?.name}} details!</h2>
вместо:
<h2>{{hero.name}} details!</h2>
Ответ 2
Вам просто нужно было прочитать немного дальше, и вы бы познакомились с структурной директивой * ngIf.
selectedHero.name еще не существует, поскольку пользователю еще предстоит выбрать героя, чтобы он возвращал undefined.
<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 от DOM до тех пор, пока она не будет выбрана и поэтому станет правдой.
Этот документ помог мне понять структурные директивы.
Ответ 3
Вы получили эту ошибку, потому что следовали плохо написанным указаниям в учебнике Heroes. Я столкнулся с тем же.
В частности, под заголовком "Отображать имена героев в шаблоне" указано:
Чтобы отобразить имена героев в неупорядоченном списке, вставьте следующее фрагмент HTML под заголовком и над деталями героя.
за которым следует этот код:
<h2>My Heroes</h2>
<ul class="heroes">
<li>
<!-- each hero goes here -->
</li>
</ul>
Он не рекомендует вам заменять предыдущий детальный код, и он должен. Вот почему мы остались:
<h2>{{hero.name}} details!</h2>
вне нашего *ngFor
.
Однако, если вы прокрутите страницу вниз, вы столкнетесь со следующим:
Шаблон для отображения героев должен выглядеть так:
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
Обратите внимание на отсутствие элементов детали из предыдущих усилий.
Ошибка, подобная этой автору, может привести к довольно дикому гусиному преследованию. Надеюсь, этот пост помогает другим избежать этого.
Ответ 4
Чтобы избежать этого, вы также можете инициализировать элемент selectedHero
вашего компонента пустым объектом (вместо того, чтобы оставить его неопределенным).
В вашем примере кода это выглядело бы примерно так:
export class AppComponent {
title = 'Tour of Heroes';
heroes = HEROES;
selectedHero:Hero = new Hero();
onSelect(hero: Hero):void{
this.selectedHero = hero;
}
}
Ответ 5
Эта строка
<h2>{{hero.name}} details!</h2>
находится вне *ngFor
, и нет hero
, поэтому hero.name
терпит неудачу.
Ответ 6
Это сработало для меня:
export class Hero{
id: number;
name: string;
public Hero(i: number, n: string){
this.id = 0;
this.name = '';
}
}
и убедитесь, что вы также инициализировали selectedHero
selectedHero: Hero = new Hero();