Странное поведение HTML DataList в Angular - PullRequest
0 голосов
/ 30 октября 2019

Я реализовал следующий простой компонент для отображения списка данных с возможностью добавления новых записей.

<h6 *ngIf="withHeader"><label for="select">
  {{title}}
</label></h6>
<label *ngIf="!withHeader" [ngClass]="{'required': required}" for="select">
  {{title}}
</label>
<input id="select" list="dataList" (change)="dataChanged()" [(ngModel)]="selectedValue"/>
<datalist id="dataList">
  <option value=null *ngIf="withButton">{{buttonTitle}}</option>
  <option  *ngFor="let item of data" [ngValue]="item">{{item[shownProperty] || item}}</option>
</datalist>

Это прекрасно работает, если я использую один экземпляр этого компонента в другом компоненте. Если у меня есть форма с двумя компонентами dataList, оба компонента будут заполнены одинаковыми данными.

Например, если у меня есть список A с автомобилями и список B с самолетами, оба изсписки будут заполнены автомобилями - по крайней мере, если пользователь откроет раскрывающийся список.

Если я отследю списки данных в DOM, список A заполняется автомобилями, а B - самолетами - как и должно быть.

Есть ли какая-то путаница с идентификатором списка во входных данных, который указывает на список, который был заполнен первым? Но если это так, как я могу это исправить? Свойство list для входных данных не позволяет вызываться таким образом [list], чтобы я мог использовать уникальный идентификатор.

Обновление:

Следующее не работает, потому что, если я использую [list], возникает следующая ошибка.

Property list is not provided by any applicable directives nor by input element

HTML:

<input id="select" [list]="dataListId" (change)="dataChanged()" [(ngModel)]="selectedValue"/>
<datalist [id]="dataListId">
  <option  *ngFor="let item of data" [ngValue]="item">{{item[shownProperty] || item}}</option>
</datalist>

Component.ts

import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';

@Component({
  selector: 'data-list',
  templateUrl: './data-list.component.html',
  styleUrls: ['./data-list.component.scss']
})
export class DataListComponent {
  @Input() data: any[];
  @Output() selectionChanged = new EventEmitter();
  @Input() selectedValue: any;
  @Input() dataListId: string;

  dataChanged() {
    // Change-Logic
  }

}

1 Ответ

1 голос
/ 30 октября 2019

Вы не можете иметь один и тот же идентификатор несколько раз в HTML. В этом случае будет выбран первый. Попробуйте сгенерировать идентификатор после создания экземпляра вашего компонента. Вы можете зарегистрировать фабрику провайдеров для вашего компонента, который будет вызываться для каждого созданного экземпляра. Затем просто вставьте идентификатор в ваш компонент.

const UNIQ_ID_TOKEN = new InjectionToken('ID');
let id = 0;
@Component({
  providers: [
    {
      provide: UNIQ_ID_TOKEN,
      useFactory: () => id++;
    }
  ]
})
class SelectComponent { 
  constructor(
    @Inject(UNIQ_ID_TOKEN)
    public uniqId: number
  ) {}
}

И используйте внедренный uniqId в шаблоне. Вы можете придумать лучшее генерирование идентификатора.

<h6 *ngIf="withHeader"><label [attr.for]="{{'select-'uniqId}}">
  {{title}}
</label></h6>
<label *ngIf="!withHeader" [ngClass]="{'required': required}" [attr.for]="select">
  {{title}}
</label>
<input [attr.id]="{{'select-'uniqId}}" [attr.list]="{{'dataList-'uniqId}}" (change)="dataChanged()" [(ngModel)]="selectedValue"/>
<datalist [attr.id]="{{'dataList-'uniqId}}">
  <option value=null *ngIf="withButton">{{buttonTitle}}</option>
  <option  *ngFor="let item of data" [ngValue]="item">{{item[shownProperty] || item}}</option>
</datalist>
...