Below shows that the string value works however if my input is a number it doesn't work. Any ideas aside from making a variable a string?
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<p>Model: {{model | json}}</p>
NOT WORKING<br/>
<input type="radio" name="foo" value="1" [(ngModel)]="model.foo" kendoRadioButton />
<input type="radio" name="foo" value="2" [(ngModel)]="model.foo" kendoRadioButton />
<input type="radio" name="foo" value="3" [(ngModel)]="model.foo" kendoRadioButton />
<br/>
WORKING<br/>
<input type="radio" name="bar" value="1" [(ngModel)]="model.bar" kendoRadioButton />
<input type="radio" name="bar" value="2" [(ngModel)]="model.bar" kendoRadioButton />
<input type="radio" name="bar" value="3" [(ngModel)]="model.bar" kendoRadioButton />
`
})
export class AppComponent {
public model = {
foo: 3,
bar: "2"
};
}
Instead of using [(ngModel)]
for two-way binding, you could implement the two-way binding yourself by stringifying the setting, and handling the change events.
Each input for a numeric type would look like this:
<input type="radio" name="foo" value="1" kendoRadioButton
[ngModel]="model.foo.toString()"
(ngModelChange)="onFooChanged($event)" />
Your event handler in your component would look like this:
onFooChanged(value) {
this.model.foo = parseInt(value);
}
Without knowing what's going on behind the scenes with [(ngModel)]
, I assume it is doing a strict equality check for boolean types such as radio buttons.
DEMO: https://stackblitz.com/edit/angular-w3xwmx
Creating an event handler per property would quickly get tedious if you have several of these. Alternatively you could create your own component that wraps this functionality.
number-radio.input.component.ts
import { Component, Input, forwardRef, ChangeDetectorRef } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
@Component({
selector: 'number-radio-input',
templateUrl: './number-radio-input.component.html',
providers: [
{ provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NumberRadioInputComponent),
multi: true }
]
})
export class NumberRadioInputComponent implements ControlValueAccessor {
@Input() name: string;
@Input() value: string;
model: string;
private _value: number;
private onChangeCallback: (value: number) => void = () => { };
onModelChange(): void {
this._value = parseInt(this.model, 10);
this.onChangeCallback(this._value);
}
registerOnChange(fn: (value: number) => void): void {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void {}
writeValue(val: number): void {
this._value = val;
this.model = val ? val.toString() : '';
}
}
number-radio-input.component.html
<input type="radio" [name]="name"
[value]="value"
[(ngModel)]="model" (ngModelChange)="onModelChange()" />
component.html
<number-radio-input [(ngModel)]="model.foo" value="1" name="foo">
</number-radio-input>
You would need to pass in additional properties if you wanted to configure the input differently, but at least this will allow you to bind to your model directly.