1

I am trying to use a search box in a mat-select that works correctly only when using data loaded by default. I want to use data from an api. But it does not work properly, the data is not displayed in the mat-select when loading the page, but it is displayed when a focus occurs in the mat-select tag.

I have a model where I use the data from a test API

export interface DataModel {
  id: number;
  title: string;
  userId: number;
}

export const DataModels: DataModel[] = [
  { id: 1, title: 'Option A', userId: 23 },
  { id: 2, title: 'Option B', userId: 24 },
  { id: 3, title: 'Option C', userId: 25 },
  { id: 4, title: 'Option D', userId: 26 }
];

My service where I make the call

@Injectable()
export class DataloadService {
  constructor(private http: HttpClient) {}

  LoadData(): Observable<any> {
    return this.http.get('https://jsonplaceholder.typicode.com/albums');
  }
}

The component where the search filter is performed and controls are set. Following the documentation NgxMatSelectSearch

constructor(private service: DataloadService) {}
  dataModel: DataModel[] = []; //DataModels
  dataCtrl: FormControl = new FormControl();
  dataFilterCtrl: FormControl = new FormControl();
  filteredData: ReplaySubject<DataModel[]> = new ReplaySubject<DataModel[]>(1);
  @ViewChild('singleSelect', { static: true }) singleSelect: MatSelect;

  _onDestroy = new Subject<void>();

  ngOnInit() {
    this.load();
    this.filteredData.next(this.dataModel.slice());
    this.dataFilterCtrl.valueChanges
      .pipe(takeUntil(this._onDestroy))
      .subscribe(() => {
        this.filterData();
      });
  }

  ngOnDestroy() {
    this._onDestroy.next();
    this._onDestroy.complete();
  }

  filterData() {
    if (!this.dataModel) {
      return;
    }
    let search = this.dataFilterCtrl.value;
    if (!search) {
      this.filteredData.next(this.dataModel.slice());
      return;
    } else {
      search = search.toLowerCase();
    }
    this.filteredData.next(
      this.dataModel.filter(
        (x: any) => x.title.toLowerCase().indexOf(search) > -1
      )
    );
  }
  load() {
    return this.service.LoadData().subscribe(res => {
      this.dataModel = res;
    });
  }

And the HTML

<mat-card>
  <mat-toolbar>Demo</mat-toolbar><br />
  <mat-card-content>
    <mat-select [formControl]="dataCtrl" placeholder="Data" #singleSelect>
      <mat-option>
        <ngx-mat-select-search
          [formControl]="dataFilterCtrl"
        ></ngx-mat-select-search>
      </mat-option>

      <mat-option *ngFor="let x of filteredData | async" [value]="x.id">
        {{x.title}}
      </mat-option>
    </mat-select>
  </mat-card-content>
</mat-card>

If I use the data that is by default in the model to simulate the process using "dataModels"

dataModel: DataModel[] = []; //DataModels

Instead of initializing it empty. It works normally but if I load the data with the request made to the API, the problem arises that it is not loaded after a focus occurs.

The demo I have in Stackblitz: Demo Stackblitz

1 Answer 1

2

You should add this line

this.filteredData.next(this.dataModel.slice());

into subscribe event of this.service.LoadData() as it is asynchronous. So that when the response result is returned, the filteredData is bonded with the response result.

load() {
  return this.service.LoadData().subscribe(res => {
    this.dataModel = res;
    this.filteredData.next(this.dataModel.slice());
  });
}

Sample Solution on StackBlitz

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.