web-dev-qa-db-fra.com

Angular 4 - Formulaires réactifs - sélectionnez l'élément dans une liste à partir d'un objet non référencé dans cette liste - problème de suivi?

Je convertis Angular 1.6 code en Angular 4 et j'ai un problème avec une liste d'éléments. Le code dans Angular = 1,6 est:

<select ng-model="$ctrl.level" ng-options="item as item.label for item in $ctrl.referentiel.levels | orderBy : 'index' track by item.id"                                   id="childLevel" name="childLevel" class="size-xl"                               >
<option value="">Select</option>
</select>

Le niveau objet n'est pas référencé dans ma liste car cette liste est chargée à l'aide de l'objet referentiel.levels. Mais l'appariement entre les éléments de ma liste et mon niveau d'objet se fait grâce à trackby. Ainsi, lorsque mon objet Level est chargé, l'élément est sélectionné dans la liste.

Maintenant, j'essaie de convertir ce code en utilisant des formulaires réactifs. Dans mon code HTML, j'ai:

<select formControlName="levelControl" id="levelSelect" name="levelSelect" class="size-xl">
<option [ngValue]="null">Select</option>
<option *ngFor="let level of referentiel.levels;trackBy:identify" [ngValue]="level">{{level.label }}</option>
</select>

Et dans mon composant, j'ai dans la méthode OnInit:

(<FormControl>this.myForm.controls.levelControl).setValue(this.level);

Et la méthode identifier est simple:

identify(index,item){
   return item.id;
}

Mais le comportement est différent. Lorsque je définit la valeur de mon contrôle à l'aide de mon niveau d'objet, l'élément avec le même identifiant dans la liste n'est pas sélectionné.

J'ai trouvé une solution mais je ne comprends pas pourquoi cela ne fonctionne pas. Ma solution consiste à écrire ce code en HTML:

<option *ngFor="let level of referentiel.levels;trackBy:identify" [ngValue]="level.id">{{level.label }}</option>

Et dans mon fichier TypeScript:

(<FormControl>this.myForm.controls.levelControl).setValue(this.level.id);

Alors maintenant ça marche: mon article est sélectionné dans la liste.

Je ne comprends pas la différence entre les deux versions de Angular dans ce cas. Peut-être que j'ai raté quelque chose ...

Merci de votre aide.

7
Adrien

Je ne vois pas que vous auriez besoin du trackBy ici, à moins que vous ne vouliez l'utiliser. Mais cela n'a rien à voir avec la raison pour laquelle votre option par défaut ne fonctionne pas.

Pourquoi cela fonctionne avec level.id est parce que c'est une chaîne (nombre?) tandis que level est un objet qui n'a aucune référence à votre tableau, donc il ne peut pas être reconnu dans la liste.

Puisque vous utilisez Angular 4, nous avons maintenant une nouvelle directive [compareWith] où nous pouvons comparer certaines propriétés de votre level, par exemple le id. Comparez-le avec le tableau et trouvez une correspondance. Donc, ce que vous pouvez faire est le suivant:

<select formControlName="levelControl" [compareWith]="compare" 
  id="levelSelect" name="levelSelect" class="size-xl">
    <option value="">Select</option>
    <option *ngFor="let level of referentiel.levels" [ngValue]="level">
      {{level.label }}
    </option>
</select>

composant:

compare(val1, val2) {
  return val1.id === val2.id;
}

Notez également que j'ai changé

<option [ngValue]="null">Select</option>

à

<option value="">Select</option>

de sorte que Angular n'essaie pas de comparer à une valeur null. Cela générerait une erreur.

28
AJT82