3

I am using Angular 5 in a project and i get a typescript error:

ERROR TypeError: Cannot read property 'indexOf' of undefined

What my code is supposed to do is to update the template on input change like this:

The template:

<input #f (input)="filterResults(f.value)"/>

<div *ngIf="filteredCandidates.length">
    <ul class="filtered-candidates-list">
        <li *ngFor="let candidate of filteredCandidates">
            {{ candidate.name }}
        </li>
    </ul>
</div>

And the component.ts:

  private queryString: string;
  private candidates: Candidate[] = []
  private filteredCandidates: Candidate[] = [];

  filterResults(queryString) {
    this.candidatesService.filterCandidates().subscribe(candidates => this.candidates = candidates);
    if (!queryString) {
      return;
    }
    else {
      this.candidates.filter(c => { c.name.indexOf(queryString) >= 0 });
    }
  }

I tried using the method .contains() on the c.name, and got the same result. The typeof candidate.name is still string, as expected, as well as the input which is also a string. However, it is like i can't use the string methods just due to typescript being incorporated.

Gabriel
  • 371
  • 1
  • 3
  • 18

3 Answers3

1

It seems like you're trying to perform filter operation on collection candidates even though it haven't been retrieved from the API server yet. By looking at your UI, it doesn't look like you are peforming any remote filtering based on query string. In this case I'd recommend to retrieve the candidates collection at the start and untill then make input box disabled/readonly. So that will avoid unexpected error to happen.

HTML

<input #f (input)="filterResults(f.value)" [readonly]="candidates.length"/>

<div *ngIf="filteredCandidates.length">
    <ul class="filtered-candidates-list">
        <li *ngFor="let candidate of filteredCandidates">
            {{ candidate.name }}
        </li>
    </ul>
</div>

Component

private queryString: string;
private candidates: Candidate[] = []
private filteredCandidates: Candidate[] = [];

getResults(){
    this.candidatesService.filterCandidates().subscribe(
       candidates => this.candidates = candidates || []
    );
};

filterResults(queryString) {
    if (!queryString) {
      return;
    }
    else {
      this.candidates.filter(c => { c.name && c.name.indexOf(queryString) >= 0 });
    }
}
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • Thank you for your suggestion. It seems to have been a problem with the database, one of the objects having no name property. Thank you for suggestion though. – Gabriel Mar 01 '18 at 20:51
1

If c.name is not defined in some cases, you could do the check like this:

  this.candidates.filter(c => { 
      return c.name !== null && c.name.indexOf(queryString) >= 0 
  });

Here, !== null will check for both null and undefined values.

Lucas
  • 9,871
  • 5
  • 42
  • 52
0

What a foolish mistake. I had to do some error handling. In the database, one of the objects had no property name (undefined). So when the loop got there, the code broke. I have to handle errors better. Thank you all for suggestions though.

Gabriel
  • 371
  • 1
  • 3
  • 18