Home > Back-end >  Angular Materials auto complete - Display options based on condition
Angular Materials auto complete - Display options based on condition

Time:10-17

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>
  • Related