1
votes

I am trying to bring data( strings) sent from a rest API to a dropdown menu on an online form. I cannot figure out where I am going wrong in my code, as it used to work, but now I am getting null / empty arrays coming in.

I've tried switching around a lot of the array names, and trying to match things up, but I can't seem to make sense of things. I feel like I need to have my original array of strings that is filled with the subscribe method mentioned again, but I am not certain.

Variable/Method explanations:

nameService: instance of name-service.ts. this brings in the Observable array of strings from the api.

names: a string array initialized empty, to be filled with the retrieved names

nameSearch: the formControl Name for the element that contains the filtered search in the html and can be referenced in the .ts.

filteredNames: an observable string array to be sent to the html object full of the names. not sure if I can bypass going through so many arrays, but my code is based off the angular Mat-Autocomplete filtered search template found here

names(): getter method in the nameService. does not take params.

//In the NgOnInit:

this.nameService.names().subscribe(res => this.names= res).add( () => {
      console.log(this.names); //last place data is not null

      this.filteredNames = this.NameSearch.valueChanges.pipe(
        startWith(''),
        map(value => this._filter(value))
      )
      }
    )
//Outside NgOnInit custom _filter method, if this helps:

private _filter(value: string): string[] {
    console.log(value);
    const filterVal = value.toLowerCase();
    console.log(filterVal);
    let result = this.opts.filter(opt =>
      opt.toLowerCase().includes(filterVal)
    )
  }
//in the HTML:
    <mat-card class="item">
                    <label> Name:
            <br>
            <mat-form-field hintLabel="Pick your name or enter a new one">
              <input type="text" matInput formControlName="nameSearch" [matAutocomplete]="auto" required>
              <mat-autocomplete #auto="matAutocomplete">
                <mat-option *ngFor="let name of filteredNames | async" [value]="name">
                  {{ name }}
                </mat-option>
              </mat-autocomplete>
            </mat-form-field>
          </label>
                </mat-card>

I want the dropdown to have the list of names pulled in from the database displayed, but right now nothing is coming through. In my error tracing thusfar, I have found that the loss of data happens in the NgOnInit method, where I have commented in the code. I have tried putting the this.names object in the pipe function to no avail.

2
Consider changing the title of this post. The problem is not just asynchronous data, but an RxJs Observable. The Angular version is relevant here, as well. - Ben Hulan

2 Answers

0
votes

Your <mat-option> doesn't know what [value]="name" is. Can you wrap the <mat-option> in a <div> and put the *ngFor on that?

Also, if you do an async pipe on the ngFor you shouldn't need to do another one internally.

<div *ngFor="let name of filteredNames | async">
  <mat-option [value]="name">
    {{ name }}
  </mat-option>
</div>
0
votes

I updated this according to your response. Does this work? Also I noticed that you have <label> including the whole input field, is that correct?

//In the NgOnInit:

this.names$ = this.nameService.names();
this.nameSearch$ = this.NameSearch.valueChanges(pipe(startWith('')));

this.filteredNames$ = combinelatest(this.names$, nameSearch$).pipe(
  (names, search)=> names.filter(name=>name.toLowerCase().includes(search.toLowerCase()))
  );


//in the HTML:
<mat-card class="item">
  <label> Name:</label>
  <br>
  <mat-form-field hintLabel="Pick your name or enter a new one">
    <input type="text" matInput formControlName="nameSearch" [matAutocomplete]="auto" required>

    <mat-autocomplete #auto="matAutocomplete">
      <mat-option *ngFor="let name of filteredNames$ | async" [value]="name">
        {{ name }}
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>
</mat-card>