Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filling up an array and making it filterable with Angular Material

I want to fill up an array when my Angular app starts and use it for Material Autocomplete. I can receive a JSON from my PHP backend. In ngOnInit I can even give it to the array and log it out. However later my array remains undefined. How should I get it right so that the contents finally show up in my options list?

app.component.html:

<form class="example-form">
  <mat-form-field class="example-full-width">
    <input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
    <mat-autocomplete #auto="matAutocomplete">
      <mat-option *ngFor="let option of filteredOptions | async" [value]="option">
        {{option}}
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>
</form>

app.component.ts:

 import {Component, OnInit, AfterViewInit} from '@angular/core';
import {FormControl} from '@angular/forms';
import {Observable} from 'rxjs';
import {map, startWith, takeUntil, switchMap} from 'rxjs/operators';
import { ServerService } from './server.service';

/**
 * @title Filter autocomplete
 */
@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css'],
})
export class AppComponent implements OnInit {
  myControl = new FormControl();
  megyek: Observable<string[]>;
  filteredOptions: Observable<string[]>;

  constructor(private serverService: ServerService) { }

  ngOnInit() {
    // don't manually subscribe!
    this.megyek = this.serverService.getMegyek();

    // use switchmap, if user types fast
    this.filteredOptions = this.myControl.valueChanges.pipe(
      startWith(''),
      switchMap(value => this._filter(value))
    );
  }

  private _filter(value: string): string[] {
    const filterValue = value.toLowerCase();
    return this.megyek
      .filter(option => option.toLowerCase().includes(filterValue));
  }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { ServerService } from './server.service';
import { HttpModule } from '@angular/http';


import { AppComponent } from './app.component';

import {
  MatButtonModule,
  MatFormFieldModule,
  MatInputModule,
  MatRippleModule,
  MatAutocompleteModule,
} from '@angular/material';

import {BrowserAnimationsModule} from '@angular/platform-browser/animations';

@NgModule({
  exports: [
    MatButtonModule,
    MatFormFieldModule,
    MatInputModule,
    MatRippleModule,
    MatAutocompleteModule,
    ReactiveFormsModule,
    BrowserAnimationsModule,
    FormsModule,
    HttpModule
  ],
  declarations: [],
  imports: []
})
export class MaterialModule {}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    MaterialModule,
    BrowserModule,
  ],
  providers: [ServerService],
  bootstrap: [
    AppComponent,
  ],
  schemas: [],
})
export class AppModule { }

server.service.ts

import {throwError as observableThrowError,  Observable } from 'rxjs';

import {catchError, map} from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { Headers, Http, Response } from '@angular/http';

@Injectable()
export class ServerService {
  constructor(private http: Http) {}
  storeServers(servers: any[]) {
    const headers = new Headers({'Content-Type': 'application/json'});
    // return this.http.post('https://udemy-ng-http.firebaseio.com/data.json',
    //   servers,
    //   {headers: headers});
    return this.http.put('https://udemy-ng-http.firebaseio.com/data.json',
      servers,
      {headers: headers});
  }
  getMegyek() {
    return this.http.get('http://localhost/Varosok/Controller/ControllerCity.php?content=megyek').pipe(
      map(
        (response: Response) => {
          console.log(response);
          const data = response.json();
          /*for (const megye of data) {
            megye.trim();
          }*/
          return data;
        }
      ),
      catchError(
        (error: Response) => {
          console.log(error);
          return observableThrowError('Something went wrong');
        }
      ), );
  }
  getAppName() {
    return this.http.get('https://udemy-ng-http.firebaseio.com/appName.json').pipe(
      map(
        (response: Response) => {
          return response.json();
        }
      ));
  }
}
like image 594
Henrik Hollósi Avatar asked May 29 '26 19:05

Henrik Hollósi


1 Answers

Remember that your request to populate megyek is asynchronous. So when AfterViewInit is executed, megyek has no value (yet) but is undefined, therefore it throws error. Keep megyek as Observable and don't use AfterViewInit. So try:

myControl = new FormControl();
megyek: Observable<string[]>;
filteredOptions: Observable<string[]>;

constructor(private serverService: ServerService) { }

ngOnInit() {
  // don't manually subscribe!
  this.megyek = this.serverService.getMegyek();

  // use switchmap, if user types fast
  this.filteredOptions = this.myControl.valueChanges.pipe(
    startWith(''),
    switchMap(value => this._filter(value))
  );
}

Also in your filter, you need to use map, to get to each field in your array, and also I changed it to rxjs 6 with pipe as seems you are using it.

private _filter(value: string): Observable<string[]> {
  return this.megyek.pipe(
    map(options => options.filter(option => option.toLowerCase().includes(value)))
  )
}

DEMO: StackBlitz

like image 157
AT82 Avatar answered May 31 '26 09:05

AT82



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!