Angular 9, NgModel on text input is resetting when string is "0" - html

I have an html input of type text and it's connected by [(ngModel)] to a formattedValue variable which updates whenever a value is entered.
I'm using this input field mainly for displaying numbers and it's of type text because after the user is putting in a number, I want to show it formatted (e.g: 1234 -> 1,234).
The problem occurs when I'm entering the number 0, it converts it to a string "0" and sets the input field value, but the input is always resetting - meaning, its value is being removed and the placeholder is showing.
This is my input:
<input
class="form-control form-text-input"
type="text"
name="field-{{ field.id }}"
id="field-{{ field.id }}"
[(ngModel)]="formattedValue"
(change)="updateFieldValue($event.target)"
placeholder="Enter any number">
And this is the logic:
formattedValue = '';
updateFieldValue($target: any) {
const decimalValue = parseFloat($target.value.replace(/,/g, ''));
if (decimalValue > 999) {
this.formattedValue = this._getFormattedValue();
} else {
this.formattedValue = decimalValue.toString();
}
}
private _getFormattedValue(): string {
return DecimalPipe.prototype.transform(this.field.value || this.field.defaultValue, undefined, 'en-US');
}
Here's a GIF showing the issue:
Thanks!

Related

how frequently pattern attribute will be validating the text entered in html input

when i am doing a input field validation using pattern , how frequently the value will be validated . i would like to know whether it will validate on (keyup) or (change)
for ex:
<input type="email" [(ngModel)]="emailAddress" name="emailAddress" data-toggle="tooltip"
title="{{emailAddress}}" #email="ngModel" multiple
pattern="^(([a-zA-Z0-9_,.]*#*\w+([-+.']\w+)*\w+([-.]\w+)*\.\w+([-.]\w+)*)*([' '])*)*$"
class="form-control" />
i would like to know whether the text i enter will be validated on each keystroke ?
The pattern attribute is checked only upon submission the form or when you press enter on the input tag, so only on the enter key's stroke you might say.
If you want it to be validated on every keypress, keyup or onchange, you can set the corresponding attribute to validate the input like so:
<input keyup="validate(this)" />
...
<script>
function validate(x)
{
regex = /[a-zA-Z0-9]+/;
window.alert(x.value.match(regex) == null);
}
</script>
If I understand correctly your issue, you are trying to check the value entered "real time".
In the case, you could use input event to get value changed.
// Add error message element after input.
$('#input_email').after('<span class="error-message">Please write your message error here!</span>')
$('#input_email').on('input', function (evt) {
var $regex=/^(([a-zA-Z0-9_,.]*#*\w+([-+.']\w+)*\w+([-.]\w+)*\.\w+([-.]\w+)*)*([' '])*)*$/;
var value = evt.target.value;
if (value.length === 0) {
evt.target.className = ''
return
}
var result = value.match($regex);
if (result) {
evt.target.className = 'valid'
} else {
evt.target.className = 'invalid'
}
})
input.invalid + .error-message {
display: initial;
}
.error-message {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="input_email" type="email" [(ngModel)]="emailAddress" name="emailAddress" data-toggle="tooltip"
title="{{emailAddress}}" #email="ngModel" multiple
pattern="^(([a-zA-Z0-9_,.]*#*\w+([-+.']\w+)*\w+([-.]\w+)*\.\w+([-.]\w+)*)*([' '])*)*$"
class="form-control" />

How to add zeros into HTML input?

I have a html input that has a fixed length of 7.
If the users types 1234, how can I prefix this input with a number of zeros in order to have the required length of 7?
I want to do this only in the UI because I already have a method in ts code for prefixing with zeros this input in order to send this correctly to backend.
<input formControlName="userNumber" type="text" class="form-control" placeholder="User #" aria-label="userNumber" aria-describedby="userNumber">
You can make use of input event on input field. Once user enters some numbers and then when the input field loses focus, required number of zeroes will be added.
const $input = document.querySelector('input');
$input.addEventListener('change', (e) => {
const value = e.target.value;
const length = e.target.value.length;
if (length === 0) {
$input.value = value;
}
else if (length < 7) {
$input.value = '0'.repeat(7-length) + value;
}
});
<input formControlName="userNumber" type="text" class="form-control" placeholder="User #" aria-label="userNumber" aria-describedby="userNumber">

refresh input after out of focus

I have an input for an id that must be typed by the user. It should have a fix length of 7.
The user can enter an id like '1234' and I will add zero prefix to get the required legth.
My problem is that after the user types '1234' and gets out of focus, it's not displayed '0001234', it remains '1234'.
component variable
let contact = {
email: 'email#emai.com,
id: Utils.addZeroPrefix(this.id.value, 7),
name: 'name',
}
idChanged() {
this.idNotFound = false;
}
Utils method
public static addZeroPrefix(root, fixedLength) {
while (root.length < fixedLength) {
root = '0' + root;
}
return root;
}
Html
<input formControlName="id" type="text" class="form-control" placeholder="id" aria-label="id" aria-describedby="id" (keyup)="idChanged()">
On (blur) you can append the extra zeros using patchValue
Try like this:
.ts
onBlur() {
let id = this.contactForm.get("id");
id.patchValue(this.addZeroPrefix(id.value, 7));
}
.html
<input type = "text" formControlName="id" (blur)="onBlur()" >
Working Demo

HTML input number type specify first value

I have an HTML input that indicates a year as so:
<input type="number" name="year" placeholder="Year" [max]="presentYear" min="1950">
The input is not required, so by default I simply want the placeholder "Year" to be present. However, as soon as the user clicks on the up or down arrows of the input field, I want the max value to be shown as default, in this case the present year (2018). However, the minimum number is shown instead. This makes no sense for this situation, since the user would have to scroll through 68 years to get to the most common use case.
Is there any way to specify the default "first value" of a number type input field? If it helps answer the question, I'm using Angular 5 for this project.
You can set min to the same value as max initially, and change it for 1950 after the input value has been changed, with the help of ngModel and ngModelChange. The first click on the spinner button will set the current year as the initial value, and the modified min value will allow to change it afterwards.
<input type="number" name="year" placeholder="Year"
[(ngModel)]="year" (ngModelChange)="setMinYear($event)"
[max]="presentYear" [min]="minYear">
export class AppComponent {
presentYear = this.getCurrentYear();
minYear = this.getCurrentYear();
year: number;
private getCurrentYear(): number {
return new Date().getUTCFullYear();
}
public setMinYear(value: number) {
const firstYear = 1950;
if (value >= firstYear) {
this.minYear = firstYear;
} else {
this.minYear = this.presentYear;
}
}
}
The code can be tested in this stackblitz.
in JS:
dateObj: Date = new Date();
year: number = dateObj.getUTCFullYear();
yearModel: number = year;
in HTML
Bind property to your input control , as given in below code it will do for you
<input type="number" name="year"
placeholder="Year"
[(ngModel)] = "yearModel"
[max]="year"
min="1950">
A separate Model prevents the value to go over the current year

Check html input before it's updated

I'm trying to implement a time picker in Angular, and I'm having some trouble figuring out how to check if the text input is valid.
In the html I have an input element that binds to keyPress function.
<input matInput style="text-align: right;" [(ngModel)]="hour" type="number" min="0" max="23" (keypress)="keyPress($event)">
keyPress(event: any) {
const pattern = /^(([[0|1]\d)|(2[0-3]))$/;
let inputChar = String.fromCharCode(event.charCode);
let tempHour = this.hour;
if (!tempHour) {
tempHour = '0';
}
let newHour = (+tempHour * 10 + +inputChar).toString();
if (newHour.length === 1) {
newHour = '0' + newHour;
}
if (!pattern.test(newHour)) {
event.preventDefault();
}
}
The problem here is that the event passed to the keyPress function only contains the current pressed key. This works fine unless the user moves the input cursor. For example: If user presses key "1", and then moves the cursor backwards and enter a "9". My code will treat it as 19 and let it pass, but the actual input is 91. So I guess I need to some how get the cursor position? Or is there a better way to solve this?
Thanks very much!
The problem is that the keypress-event happens before ngModel updates your "hour" variable. In your case I'd suggest to react on the change-event which gets fired after ngModel has already done its update.
(change)="onChange($event)"
And then your method can look like this
<input matInput style="text-align: right;" [(ngModel)]="hour" type="number" min="0" max="23" (change)="onChange($event)">
private lastValue: number = 0;
onChange(event: any) {
const pattern = /^(([[0|1]\d)|(2[0-3]))$/;
if (!pattern.test(this.hour)) {
this.hour = this.lastValue;
} else {
this.lastValue = this.hour;
}
}