Reputation: 1656
I would like to to style a select element in an Angular component differently, when a specific option (with an inactive attribute) is selected.
My component look like this:
class ComponentWithSelect {
@Input() ngModel: unknown = null;
@Input() options: { value: unknown, label: string, diasbled: boolean }[]
inactiveSelected: boolean = false;
...
}
and the corresponding template look like this:
<select
[ngModel]="ngModel"
[class.inactive-select]="inactiveSelected">
<option *ngFor="let option of options"
[ngValue]="option.value"
[disabled]="option.disabled">
{{option.label}}
</option>
</select>
I would like to apply the inactive-select class when an option with the inactive attribute is selected OR when a ngModel is passed to the component which corresponds to an option with an inactive attribute.
I tried to use the (ngModelChange)
to set the inactiveSelected property but $event
parameter passed to a corresponding method (onModelChange) does contain the value of the selected option, not the inactive attribute.
I could go with (change)
and access the event.target.options.selectedIndex property but neither of those two approaches works, when the ngModel is set from outside or its initial value is so, that it corresponds to a option with an inactive property
EDIT:
I tried the suggested approach with using the whole option object for ngValue
class ComponentWithSelect {
@Input()
set ngModel(model: unknown) {
this.selectedValue = this.options.find(option => option.value === model) || null;
}
@Input() options: { value: unknown, label: string, disabled: boolean }[] = [];
@Output() ngModelChange = new EventEmitter<unknown>();
selectedValue: { value: unknown, label: string, disabled: boolean } = null;
onModelChange(option: { value: unknown, label: string, disabled: boolean }) {
this.ngModel = option.value;
this.ngModelChange.emit(this.ngModel);
}
and the template
<select
[(ngModel)]="selectedValue"
[class.inactive-select]="selectedValue.disabled">
<option *ngFor="let option of options"
[ngValue]="option">
{{option.label}}
</option>
</select>
The right option is now selected properly when a corresponding ngModel is passed to my component, but when I try to manually change the select, for the for the first time nothing is selected, all consequent changes are working fine.
Upvotes: 1
Views: 2336
Reputation: 1656
I got it working, I had to add getter as well
class ComponentWithSelect {
@Input()
set ngModel(model: unknown) {
this._ngModel = model;
this.selectedValue = this.options.find(option => option.value === model) || null;
}
get (): unknown {
return this._ngModel;
}
@Input() options: { value: unknown, label: string, disabled: boolean }[] = [];
@Output() ngModelChange = new EventEmitter<unknown>();
private _ngModel: unknown;
selectedValue: { value: unknown, label: string, disabled: boolean } = null;
onModelChange(option: { value: unknown, label: string, disabled: boolean }) {
this._ngModel = option.value;
this.ngModelChange.emit(this._ngModel);
}
and the template:
<select
[(ngModel)]="selectedValue"
[class.inactive-select]="selectedValue.disabled">
<option *ngFor="let option of options"
[ngValue]="option">
{{option.label}}
</option>
</select>
Upvotes: 0
Reputation: 2470
There are 2 things you should notice:
Besides you do not need a secondary boolean property for tracking.
Last note, inital bound object must be one from the options array.
*** .html file ***
<select
[(ngModel)]="selectedValue"
[ngClass]="{'inactive-select': selectedValue.inactive}"
>
<option *ngFor="let option of options"
[ngValue]="option">
{{option.label}}
</option>
</select>
*** .ts file ***
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
selectedValue: any;
options: { value: unknown, label: string, inactive: boolean } [] = [
{
value: 1,
label: "1",
inactive: false,
},
{
value: 2,
label: "2",
inactive: true,
},
]
ngOnInit(): void {
this.selectedValue = this.options[0];
}
}
Upvotes: 1