Angular 4 - Reactive Forms - выберите элемент в списке из объекта, на который нет ссылок в этом списке - проблема с отслеживанием?

Я конвертирую код Angular 1.6 в Angular 4, и у меня есть проблема со списком элементов. Код в Angular 1.6:

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

Уровень объекта не указан в моем списке, поскольку этот список загружается с использованием объекта referentiel.levels. Но соответствие между элементами моего списка и моим уровнем объекта выполняется благодаря trackby. Поэтому, когда мой объект Level загружен, элемент выбирается в списке.

Теперь я пытаюсь преобразовать этот код с помощью Reactive Forms. В моем HTML-коде у меня есть:

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

И в моем компоненте я имею в методе OnInit:

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

И метод идентификации прост:

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

Но ассортимент другой. Когда я устанавливаю значение своего элемента управления, используя свой уровень объекта, элемент с таким же идентификатором в списке не выбирается.

Я нашел решение, но я не понимаю, почему оно не работает. Мой обходной путь - написать этот код в HTML:

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

И в моем машинописном файле:

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

Итак, теперь это работает: мой элемент выбран в списке.

Я не понимаю разницу между двумя версиями Angular в этом случае. Может быть, я что-то пропустил...

Спасибо за вашу помощь.

1 ответ

Решение

Я не вижу, что вам понадобится trackBy здесь, если вы не хотите его использовать. Но это не имеет никакого отношения к тому, почему ваш вариант по умолчанию не работает.

Почему это работает с level.id потому что это строка (число?), тогда как level это объект, который не имеет ссылки на ваш массив, поэтому он не может быть распознан из списка.

Поскольку вы используете Angular 4, у нас теперь есть новая директива [compareWith] где мы можем сравнить некоторые свойства из вашего levelнапример id, Сравните это с массивом и найдите совпадение. Так что вы можете сделать следующее:

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

составная часть:

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

Также обратите внимание, что я изменился

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

в

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

так что Angular не пытается сравнить с null значение. Это может привести к ошибке.

Другие вопросы по тегам