I am making a project on angular 7.It has a table with a column having dropdowns. The dropdown contains various languages. When a language is selected in a particular row, t
you can solve the problem by holding a set of selected languages and display options conditionally based on whether an option/language is selected before or not.
create a Set
to hold selected langs
selectedLangs = new Set<string>();
create a view query to get a list of all select elements
@ViewChildren("selectLang") langSelects: QueryList<ElementRef<HTMLSelectElement>>;
whenever a selection is made/changed on any of the select elements re-populate the selectedLangs
set
selected() {
this.selectedLangs.clear();
this.langSelects.forEach(ls => {
const selectedVal = ls.nativeElement.value;
if (selectedVal && selectedVal !== "undefined") this.selectedLangs.add(selectedVal);
});
}
whenever a field is deleted just remove that language from selectedLangs
deleteFieldValue(index: number, lang: string) {
this.selectedLangs.delete(lang);
this.fieldArray.splice(index, 1);
}
and when displaying options for a select check if it is currently selected on current select or already selected in another select *ngIf="selectLang.value === lang.name || !isSelected(lang.name)"
<ng-container *ngFor="let lang of languageList" >
<option *ngIf="selectLang.value === lang.name || !isSelected(lang.name)" value={{lang.name}} [ngValue]="lang.name">
{{lang.name}}
</option>
</ng-container>
where isSelected
is defined as
isSelected(lang: string) {
return this.selectedLangs.has(lang);
}
here is a working demo with full source https://stackblitz.com/edit/angular-dqvvf5
You can store the langs in an array make a function like
lang = []; //define the array
getLang(i, languageList) {
return i == 0 ? languageList :
this.getLang(i - 1, languageList.filter(x => x.name != this.lang[i-1]))
}
So, you can has some like
<div *ngFor="let a of languageList;let i=index">
<select [(ngModel)]="lang[i]">
<option value="undefined" disabled>Select Language</option>
<option *ngFor="let lang of getLang(i,languageList)"
[value]="lang.name" >{{lang.name}}</option>
</select>
</div>
But I don't like because each change force Angular to calculate all the options. So we are going to improve the code using FormArray and an array langList, and make sure that we can not choose the same language
First our variable and our function changed
langList=[];
getLangForFormArray(i, languageList) {
return i == 0 ? languageList :
this.getLang(i - 1, this.langList[i-1].filter(x => x.name != this.formArray.value[i-1]))
}
We create a formArray
formArray=new FormArray(this.languageList.map(()=>new FormControl(null)))
And in ngOnInit
ngOnInit()
{
this.formArray.valueChanges.pipe(startWith(null)).subscribe(()=>{
//create the langList array
for (let i=0;i<this.languageList.length;i++)
this.langList[i]=this.getLangForFormArray(i,this.languageList)
//check no repeat values
if (value)
{
value.forEach((x,index)=>{
if (this.formArray.value.findIndex(v=>v==x)!=index)
this.formArray.at(index).setValue(null,{emitEvent:false})
})
}
})
}
See that use formArray valueChanges with pipe(startWith(null)) to create at first the langList
The .html
<div *ngFor="let control of formArray.controls;let i=index">
<select [formControl]="control">
<option value="null" disabled>Select Language</option>
<option *ngFor="let lang of langList[i]"
[value]="lang.name" >{{lang.name}}</option>
</select>
</div>
And the demo in stackblitz