The minimal code to produce the issue can be seen at
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
}
CodePudding user response:
<option>
values must be convertible to strings, because behind the scenes they're getting represented as HTML DOM.
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 .....
}