Подтвердить что ты не робот

Angular2 ngModel/ngValue выбрать объект опции - равенство в разных экземплярах

Ароматизаторы этого вопроса были заданы несколько раз в разных версиях Angular2 до выпуска. Тем не менее, мне еще предстоит найти что-нибудь, что приведет к желаемому поведению (без обходных решений, которые я хочу избежать) в плунге здесь: Выбрать Проблемы с объектом

Мой выбор формы имеет двустороннюю привязку через [(ngModel)] к объекту, а затем 'option' генерируется через * ngFor для списка похожих объектов (все они дифференцируются по id). В моих исследованиях несколько раз упоминалось, что Angular2 использует эквивалентность объектов JavaScript (по экземпляру), поэтому объект в связанной модели, который не имеет одного и того же экземпляра, не будет соответствовать списку. Таким образом, он не отображается как "выбранный" элемент - нарушение привязки данных "2-way".

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

Параметры, которых я хочу избежать:

  • Связывание с чем-то другим, кроме объекта (т.е. id) в ngModel. ngValue - отличная помощь, которую я хочу использовать
  • Обходные пути с помощью обработчиков изменений
  • Принудительное соответствие экземпляров (я получаю объекты из службы данных и не хочу переопределять их все, чтобы они совпадали... что кажется бесполезной тратой ресурсов).

В идеале (и это, по-видимому, обсуждалось как можно скорее в нескольких местах, где были решения - решения, которые были недостаточными в моем случае), можно было бы определить стандарт равенства для ngModel для использования вместо эквивалента экземпляра объекта.

то есть. последняя попытка ниже, где h.id == a.id определяет атрибут "selected". Я не понимаю, почему этот атрибут "selected" не получает визуализацию - он каким-то образом заблокирован ngModel? Установка selected = 'true' вручную в HTML, кажется, исправлена, но генерация с помощью [attr.selected] или любого из других вариантов, которые строят атрибут ng-reflection-selected = 'true', похоже, не делает трюк.

<div *ngFor='let a of activePerson.hobbyList ; let i=index; trackBy:a?.id'>

    <label for='personHobbies'>Hobby:</label>
    <select id='personHobbies' class='form-control'
        name='personHobbies' [(ngModel)]='activePerson.hobbyList[i]' #name='ngModel'>

        <option *ngFor='let h of hobbyListSelect; trackBy:h?.id' 
            [ngValue]='h' 
            [attr.selected]='h.id == a.id ? true : null'
        >
        {{h.name}}
        </option>
    </select>
</div>

Некоторые вещи, которые я пробовал:

  • trackBy
  • Связывание с [selected] =, selected = {{}} и [attr.selected] (похоже, близко)

Я успешно достиг вынесенного HTML, который выглядит так:

<select ...>
    <option selected='true'>Selected</option>
    <option selected='false'>Not Selected</option>
    <!-- and variants, excluding with selected=null-->
</select>

Но все же не выбранное значение, когда экземпляр объекта отличается. Я также удалился, пытаясь выяснить, какой элемент в HTML или CSS записывает выбранное значение, когда пользователь выбирает значение (как обрабатывает ngModel, и какие другие параметры могут быть для обработки).

Любая помощь будет принята с благодарностью. Цель состоит в том, чтобы получить кнопку "Изменить", чтобы изменить базовую модель и соответствующим образом обновить поля выбора. Я сосредоточил свои попытки на "hobbyList". Я пробовал Firefox и Chrome. Спасибо!

4b9b3361

Ответ 1

Per @Klinki

В настоящее время нет простого решения в angular 2, но в angular 4 это уже рассмотрено, так как бета-версия 6 compareWith- см. https://github.com/angular/angular/pull/13349

Чтобы проиллюстрировать использование для предлагаемого случая (см. plunk):

<div *ngFor='let a of activePerson.hobbyList ; let i=index;'>

        <label for='personHobbies'>Hobby:</label> 
        <select id='personHobbies' class='form-control'
          name='personHobbies' [(ngModel)]='activePerson.hobbyList[i]'
          [compareWith]='customCompareHobby'>
          <option *ngFor='let h of hobbyListSelect;' [ngValue]='h'>{{h.name}}</option>
        </select>

</div>
...
customCompareHobby(o1: Hobby, o2: Hobby) {
    return o1.id == o2.id;
}

Ответ 2

В настоящее время нет простого решения в angular 2, но в angular 4 это уже исправлено с бета-версии 6 - см. https://github.com/angular/angular/pull/13349

Ответ 3

Нет прямого подхода к использованию привязки ngModel таким образом. Однако, поскольку вы не хотите регистрировать обработчики событий отдельно, нам может потребоваться изменить способ назначения объекта. Также вам не нужно присваивать идентификатор для тега select, поскольку он не служит цели. Для упомянутого случая использования я изменил его, чтобы увидеть двустороннюю привязку.

Найти конструктор компонента с моделью и printVal() включен только для проверки изменения. Шаблон не содержит ngValue и ngModel, но он может работать как ожидалось.

constructor() {
    this.activePerson = {id: 'a1',
        hobbyList : [
           {
             id: 'h4'
           },
           {
             id : 'h2'
           }
          ]
      }
      
    this.hobbyListSelect = [
        {
         id: 'h1'
        },
        {
         id : 'h2'
        },
        {
         id: 'h3'
        },
        {
         id : 'h4'
        }
      ];
  }

printVal($event,i) {
    console.log(JSON.stringify(this.activePerson.hobbyList))
}
<div *ngFor='let a of activePerson.hobbyList ; let i=index; trackBy:a?.id'>
        <label for='personHobbies'>Hobby:</label>
        <select name='personHobbies' 
        (change)=" activePerson.hobbyList[i] = hobbyListSelect[$event.target.selectedIndex];
        printVal($event,i)">
            <option *ngFor='let h of hobbyListSelect; trackBy:h?.id' 
                [selected]='(h.id == a.id) ? "selected" : null'
            >
            {{h.id}}
            </option>
        </select>
    </div>

Ответ 4

Когда вы получаете объект, переданный откуда-то, что вы хотите сделать выбранным, просто выполните поиск массива hobbyListSelect для соответствующего элемента и назначьте найденный элемент activePerson.hobbyList[i]