Reputation: 898
I've implemented the following simple component to display a list of data with the ability to add new entries.
<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>
It works perfectly fine if I use one instance of this component in another component. If I have a form which has two dataList-Components, both of the Components will be populated with the same data.
For example - if I have a list A with cars and a list B with planes both of the lists will be populated with cars - at least if the user opens the dropdown.
If I trace the datalists in the DOM List A is populated with cars and B with planes - right as it should be.
Is there some mix up with the list-identifier in the input which points to the list that was populated first? But if it is like that how can I fix it? The list-property of the input doesn't allow to be called like this [list]
so that I could use a unique identifier.
Update:
The following does not work because if I use [list]
the following error occurs.
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
}
}
Upvotes: 0
Views: 1210
Reputation: 602
You cannot have the same id appeared several times in HTML. In that case, the first one will be selected. Try generating id once instance of your component is being created. You can register a provider factory on your component which is gonna be called for each created instance. Then just inject id in your component.
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
) {}
}
And use injected uniqId in template. You can come up with better id generation.
<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>
Upvotes: 2