I am using 4 components , each of them having material autocomplete and all have same options as another. Whenever I select an option in a component isAvailable is set to false and that option should be disabled in other component. Below is the array which needs to be displayed in options -
Planet[] = [
{ name: "one" , distance: 100, isAvailable: true },
{ name: "two" , distance: 200, isAvailable: true},
{ name: "three" , distance: 300, isAvailable: true },
{ name: "four" , distance: 400, isAvailable: true },
{ name: "five" , distance: 500, isAvailable: true },
{ name: "six" , distance: 600, isAvailable: true },
];
I'm subscribed to a common service which gives me the updated list with isAvailable= true/false and with this new array in hand , I need to populate it in the autocomplete.
import { Component, OnInit , Input , ViewEncapsulation} from '@angular/core';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { CommonService } from '../common.service';
@Component({
selector: 'falcone-traveldetails',
templateUrl: './traveldetails.component.html',
styleUrls: ['./traveldetails.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class TraveldetailsComponent implements OnInit {
@Input() planets: any;
currentPlanet: any;
planetControl = new FormControl();
filteredPlanet: Observable<any[]>;
previousPlanet: any;
constructor(private commonService:CommonService) {
this.commonService.planets.subscribe( data =>{
this.planets = data;
var filteredItems = this.planets.filter((planet:any) => {
planet.isAvailable == true;
})
});
this.filteredPlanet = this.planetControl.valueChanges.pipe(
startWith(''),
map(value => {
return this.planets.filter((option:any) =>
option.name?.toLowerCase().includes(value.toLowerCase()) && option.isAvailable === true );
})
);
this.commonService.vehicles.subscribe( data =>{
this.vehicles = data;
});
}
ngOnInit(): void {
}
getPlanetName(planet: any){
return planet ? planet.name: undefined;
}
onPlanetChanged(event:any){
for(var planet of this.planets){
if(planet.name == event.option.value.name){
planet.isAvailable = false;
}
if(planet.name == this.previousPlanet?.name){
planet.isAvailable = true;
}
}
this.commonService.updatePlanetsList(this.planets);
this.previousPlanet = event.option.value;
}
}
The component's html -
<mat-form-field>
<input type="text" placeholder="Choose planet" matInput [matAutocomplete]="planetAuto" [formControl]="planetControl" [(ngModel)]="currentPlanet"/>
<mat-autocomplete #planetAuto="matAutocomplete" [displayWith]="getPlanetName" (optionSelected)="onPlanetChanged($event)" >
<mat-option *ngFor="let planet of filteredPlanet | async" [value]="planet">
{{planet.name}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
CodePudding user response:
you cant use ngif
and ngfor
in a one element so you must use ng-container
. for example :
<mat-form-field>
<input type="text" placeholder="Choose planet" matInput [matAutocomplete]="planetAuto" [formControl]="planetControl" [(ngModel)]="currentPlanet"/>
<mat-autocomplete #planetAuto="matAutocomplete" [displayWith]="getPlanetName" (optionSelected)="onPlanetChanged($event)" >
<ng-container *ngFor="let planet of filteredPlanet | async" >
<mat-option *ngIf="planet.isAvailable" [value]="planet">
{{planet.name}}</mat-option>
</ng-container>
</mat-autocomplete>
</mat-form-field>