Reputation: 4683
I want to have simple number input component that allows only for numbers from specific range.
I use HTML min/max attributes that works when user is using input "arrows"
<input type="number" style="width: 100px" [(ngModel)]="value" min="0" max="99" />
And I am checking also the values when propagating it further to application:
export class AppInput {
_v: number;
@Input()
get value(): number {
return this._v;
}
set value(v) {
if (v > 99) {
v = 99;
}
this._v = v;
this.valueChange.emit(v);
}
@Output() valueChange = new EventEmitter<number>();
}
When user write directly to the input, when he e.g. press 0
when value is 10
- input is correctly changed to 99
. However when he continues, content of input is changed to 990
(even though model is correctly 99).
How can I limit user what he can enter into input component?
Sample project: https://codesandbox.io/s/w23900kx05
Upvotes: 1
Views: 1734
Reputation: 1648
I don't where is the error but this should work.
<input type="number" style="width: 100px" [(ngModel)]="value" oninput="this.value = this.value > 99?99:this.value" min="0" max="99" />
If 99 is not fixed
<input type="number" style="width: 100px"
[(ngModel)]="value"
(keypress)='inputChanged()'
min="0" max="99" />
in your .ts file
export class AppInput {
maxNumber = 50 // u want to only change this;
maxNumberBackup = this.maxNumber;
_v: number;
constructor(){
this.maxNumber = this.maxNumber -1;
}
inputChanged() {
return this.value > this.maxNumber ? false : true;
}
@Input()
get value(): number {
return this._v;
}
set value(v) {
if (v > this.maxNumberBackup) {
v = this.maxNumberBackup;
}
this._v = v;
this.valueChange.emit(v);
}
@Output() valueChange = new EventEmitter<number>();
}
Upvotes: 2
Reputation: 12960
I don't understand why do you need an Input
property value
for your custom Input from the parent. (Probably you want some default value?).
Coming to the solution of your question. Why is your view(input box) not updating even if the model has the correct maximum value? Let's see it this way:
You have a property value
which is bound to the input box. So when the input value changes, this is how value's
data will be updated. Consider that initially value = 0
, then you input 1
in the input box, due to 2-way binding
, value
will be updated with one. Will it be marked for change detection here? Yes! And this will again update the Input Box on Change Detection cycle. Now, you input 2(input box now contains 12). Again It will be marked for Change Detection. Now, you input 3(The input should had contained 123) but because of your logic, it is changed to 99. So what changes actually? The data in the value
property. Now your input box contains 99. You enter another 0. What happens? Your setter logic will make value
to 99.(But wait it was already 99). So Is is it marked for Change detection? No. So will the Input which is bound to value
see any difference? No.
Note: At least one change detection cycle should run on all your input events in the input box.
How I solved your problem is (I have used property data
instead of value
):
constructor(private _cdr: ChangeDetectorRef) {}
@Input() set data(v) {
this._v = v; // I am assigning whatever value I get to the data property
// so that in the manual change detection a change can be seen
// (even though that change doesn't need to be show)
this._cdr.detectChanges();
if (v > 99) {
v = 99
}
else if (v < 0) {
v = 0
}
this._v = v
this.valueChange.emit(v);
}
In the very first step, I am assigning whatever value I get from the input box to _v
, then I call a manual change detection before proceeding with my logic. So the value of data
is updated with the Input Value
. My logic will revert it back to 99 or 0
, it will be marked for change detection now, and your view will be updated apprpriately (Note: Your output will emit the final value itself.)
See the working example here: https://stackblitz.com/edit/angular-custom-number-input?file=src/app/hello.component.ts
Upvotes: 0
Reputation: 125
If you are looking to validate length use maxLength instead should work.
<input type="text" style="width: 100px" [(ngModel)]="value" maxLength="2" />
Upvotes: 0