Home > Software design >  No person shown after selecting ALL genders from a dropdown
No person shown after selecting ALL genders from a dropdown

Time:01-28

The minimal code to produce the issue can be seen at enter image description here

Code Snippet:

<div>
  <select [(ngModel)]="selectedFilter">
    <option [value]="undefined">All</option>
    <option *ngFor="let gender of ['male','female']" [value]="gender">
      {{gender}}
    </option>
  </select>
  <ul>
    <li *ngFor="let person of peopleByGender">
      {{person.name}}
    </li>
  </ul>
</div>
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  selectedFilter?: "male" | "female";

  people: { name: string; gender: "male" | "female"; }[] = [
    { name: "Anton", gender: "male" },
    { name: "Bob", gender: "male" },
    { name: "Cindy", gender: "female" }
  ];


  get peopleByGender(): readonly { name: string; gender: "male" | "female"; }[] {
    return this.people
      .filter(x => this.selectedFilter == undefined || x.gender == this.selectedFilter);
  }

}

Question

What causes this issue? And how to solve it?

Note: Using type or interface are intentionally ignored to focus on the main issue.

Logging

get peopleByGender(): readonly { name: string; gender: "male" | "female"; }[] 
{
  console.log(

  `Selected Filter: ${this.selectedFilter}. 
   Is it undefined? ${this.selectedFilter == undefined}`

  );

 // ... others
}

enter image description here

CodePudding user response:

<option> values must be convertible to strings, because behind the scenes they're getting represented as HTML DOM.

DOM Representation

So when a user selects the "All" option, they're not changing the value to undefined: they're changing it to "undefined".

If you omit the option's value entirely, the DOM will implicitly assign its inner text ("All") to be its value.

Instead of trying to use undefined, use a special string value. For example, you could use "All", or you could just use an empty string:

  <option value="">All</option>
export class AppComponent {
  selectedFilter: "male" | "female" | "" = "";

  people: { name: string; gender: "male" | "female"; }[] = [
    { name: "Anton", gender: "male" },
    { name: "Bob", gender: "male" },
    { name: "Cindy", gender: "female" }
  ];


  get peopleByGender(): readonly { name: string; gender: "male" | "female" | ""; }[] {
    return this.people
      .filter(x => this.selectedFilter === "" || x.gender == this.selectedFilter);
  }

CodePudding user response:

You should add value “all” to the All option and in your function check if the value of selected filter equals “all” and return this.people else run the filter method on your array and return that array.

CodePudding user response:

Based on StriplingWarrior's answer:

So when a user selects the "All" option, they're not changing the value to undefined: they're changing it to "undefined".

And because I want to keep using undefined, here is my trick.

get peopleByGender(): /* others ...*/ {

  if (this.selectedFilter?.toString() === String(undefined))
    this.selectedFilter = undefined;

  // others .....
}
  • Related