web-dev-qa-db-fra.com

Angular2: Impossible de lire la propriété 'nom' de non défini

Je commence à apprendre Angular2. J'ai suivi le didacticiel des héros fourni sur angular.io. Tout fonctionnait bien jusqu'à ce que, étant gêné par le fouillis de HTML utilisant le modèle, j'ai utilisé l'URL du modèle à la place et déplacé le code HTML vers un fichier nommé hero.html. L'erreur générée est "Impossible de lire la propriété 'nom' de non défini". Étrangement, il est possible d'accéder à la variable heroes qui pointe vers un tableau d'objets, afin que ngFor produise la quantité correcte de balises "li" en fonction du nombre d'objets dans le tableau. Cependant, les données des objets du tableau ne sont pas accessibles. De plus, même une simple variable contenant du texte ne s'affichera pas entre crochets {{}} dans le code HTML (voir le code fourni).

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>

Voici une photo:

enter image description here

56
user4431744

La variable selectedHero ayant la valeur null dans le modèle, vous ne pouvez pas lier selectedHero.name tel quel. Vous devez utiliser l'opérateur elvis pour ce cas:

<input [ngModel]="selectedHero?.name" (ngModelChange)="selectedHero.name = $event" />

La séparation de [(ngModel)] dans [ngModel] et (ngModelChange) est également nécessaire, car vous ne pouvez pas affecter à une expression qui utilise l'opérateur elvis.

Je pense aussi que vous voulez utiliser:

<h2>{{selectedHero?.name}} details!</h2>

au lieu de:

<h2>{{hero.name}} details!</h2>
117
Guilherme Meireles

Vous avez juste besoin de lire un peu plus loin et vous auriez été présenté à la directive structurelle * ngIf.

selectedHero.name n'existe pas encore car l'utilisateur n'a pas encore sélectionné de héros pour qu'il retourne 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>

La directive * ngIf maintient selectedHero hors du DOM jusqu'à ce qu'il soit sélectionné et devient donc une vérité.

Ce document m'a aidé à comprendre les directives structurelles.

24
Tom

Vous avez eu cette erreur parce que vous avez suivi les instructions mal écrites du didacticiel Heroes. Je suis tombé sur la même chose.

Plus précisément, sous la rubrique Afficher les noms de héros dans un modèle, il est indiqué:

Pour afficher les noms de héros dans une liste non ordonnée, insérez le bloc HTML suivant sous le titre et au-dessus des détails du héros.

suivi de ce bloc de code:

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

Il ne vous demande pas de remplacer le code d'identification précédent, et cela devrait être le cas. C'est pourquoi il nous reste:

<h2>{{hero.name}} details!</h2>

en dehors de notre *ngFor.

Toutefois, si vous faites défiler la page plus bas, vous rencontrerez les problèmes suivants:

Le modèle d'affichage des héros devrait ressembler à ceci:

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

Notez l'absence d'éléments de détail des efforts précédents.

Une telle erreur de la part de l'auteur peut donner lieu à une chasse à l'oie assez sauvage. Espérons que ce post aide les autres à éviter cela.

5
Josh Cronkhite

Pour éviter cela, vous pouvez également initialiser le membre selectedHero de votre composant sur un objet vide (au lieu de le laisser indéfini).

Dans votre exemple de code, cela donnerait quelque chose comme ceci:

export class AppComponent {
  title = 'Tour of Heroes';
  heroes = HEROES;
  selectedHero:Hero = new Hero();

  onSelect(hero: Hero):void{
      this.selectedHero = hero;
  }
}
5
Cédric Françoys

Cette ligne

<h2>{{hero.name}} details!</h2>

est en dehors de *ngFor et il n'y a pas de hero, donc hero.name échoue.

2
Günter Zöchbauer

Cela a fonctionné pour moi:

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

   public Hero(i: number, n: string){
     this.id = 0;
     this.name = '';
   }
 }

et assurez-vous d'initialiser ainsi selectedHero

selectedHero: Hero = new Hero();
0
grenny