I am trying to remove everything except numbers, colon (:) and a new line. After having entered values with colon say 12:30, when I press enter, I am not able to submit using custom directives. So as of now, I am able to allow numbers and colon but not the enter key.
My custom directive looks something like this :
export class NumberDirective {
constructor(private _el: ElementRef) { }
#HostListener('input', ['$event']) onInputChange(event) {
const initalValue = this._el.nativeElement.value;
this._el.nativeElement.value = initalValue.replace(/[^0-9:\n]*/g, '');
if ( initalValue !== this._el.nativeElement.value) {
event.stopPropagation();
}
}
Please let me know how this can be fixed and thanks in advance.
Bellow I show two approaches, one by updating the text after it is changed, the second by preventing the default behavior of specific keys. The first is more general, but for this case I prefer the second because it prevents the text from going there. The other detail is that by the piece of code you shared I don't understand why you call stopPropagation
const [txt1, txt2] = document.querySelectorAll('textarea')
txt1.addEventListener('input', () => {
txt1.value = txt1.value.replace(/[^0-9:\n]+/g, '')
})
txt2.addEventListener('keypress', (event) => {
if(!(/[0-9:]|Enter/i).test(event.key)){
event.preventDefault();
}
})
textarea { min-height: 5cm }
<textarea placeholder="Type here"></textarea>
<textarea placeholder="Type here"></textarea>
Related
I need some assistance in the rear scenario of the reactive form input field. I have a field name that enters the last four digits of the SSN after filling it out with last four digits an API call is triggered to check valid SSN if it gives success then we pass the last four digits of the SSN and if it gives failure response then we have to move the cursor of the field at the beginning to enter the first 5 digits of SSN with actual SSN format like 123-45-6789.
For example, if the user enters 6789 and API sent a failure response then the input field cursor moves at the beginning and now if a user enters the next digit it shows 5-6789, and after that 45-6789, 3-45-6789, and so on till it doesn't show like 123-45-6789.
HTML code.
<input formControlName="ssn" type="text"
name="ssn" [imask]="ssnMask"
(keyup)="isSSNCorrect($event.target.value)" />
component.ts
this.ssnMask = "0000";
public isSSNCorrect(ssnNumber: string) {
if (ssnMask == '0000') {
if (ssnNumber.length === 4) {
this.service.checkSSN(ssn).subscribe(
res => {
if (res.success) {
console.log('success');
} else {
this.ssnMask = "000-00-0000"
this.atBeginning();
}
}, (err) => {}
);
}
}
}
atBeginning() {
div.nativeElement.setSelectionRange(0, 0);
}
The above code does not shift the cursor at the beginning if I remove the imask then it shifts the cursor at the beginning but in that case, it shows without SSN format.
I attached the below link as a reference, in this, if I enter 4 digits and click on the test button then I want cursor shifts at the beginning of the input field and the next input takes the assigned imask format i.e 123-45-6789.
stackblitz example
Could you try the below code, where set selection seems to work fine?
import { Component, ElementRef, ViewChild } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<input #input [ngModel]="value" [imask]="mask">
<button (click)="click()">test</button>
`,
styleUrls: ['./app.component.css'],
})
export class AppComponent {
#ViewChild('input') input: ElementRef<any>;
name = 'iMask';
maskToDot = {
mask: '000-00-0000',
scale: 2,
};
mask = {
mask: '0000',
scale: 2,
};
value: string = '';
ngAfterViewInit() {
console.log(this.input);
// setCaretPosition(this.input.nativeElement, 3);
}
click() {
this.mask = this.maskToDot;
setTimeout(() => {
this.input.nativeElement.setSelectionRange(0, 0);
this.input.nativeElement.focus();
});
}
}
forked stackblitz
I am building a component in React that is supposed to be a time picker. I want to constraint the input to only allow numbers and backspaces and not allow more than two digits in the input. My component is built like this:
import React, {Component} from 'react';
class Example extends component {
state = {hour: "00"}
hourEdited = (event) => {
this.setState({hour: event.target.value});
}
render() {
<input type="number" value={this.state.hour} onChange={this.hourEdited.bind(this)} />
}
}
My initial thought was to try to check for event.keyCode and check if the keyCode of the event was a code for a numeric value or backspace. That was not correct. How do I do this?
I also thought that if input was of type "number" you could only enter numbers but that isn't the case for me at least.
Thanks in advance!
I fixed this. For some reason the input type="number" was not behaving the way I at least thought it should. I just subbed the wrong characters and checked if the event value exceeded two letters. Here is my new hourEdited function:
hourEdited = (event) => {
let newValue = event.target.value;
if(newValue.length <= 2) {
this.setState(hour: newValue.replace(/[^0-9]+/g, "");
}
}
Hopefully this helped if others run into this!
I have a Vue component (modal) that removes focus from an active element if there is one on mount and, in case there is an input element, focus the first input it finds. The code is working and I have a working test for the first case.
My test to asses that an input element is focused is not working though and I can't find my mistake.
Relevant code parts of the vue-component:
mounted() {
this.removeActiveFocusedElements()
if (this.autoFocusFirstInputElement) {
this.focusFirstInput()
}
}
removeActiveFocusedElements() {
if (document.activeElement) {
document.activeElement.blur()
}
}
focusFirstInput() {
const firstInput = this.$el.querySelector('input')
if (firstInput) {
firstInput.focus()
}
}
The relevant test part:
const wrapper = document.createElement('div')
const initialFocusedElement = document.createElement('button')
wrapper.appendChild(initialFocusedElement)
initialFocusedElement.setAttribute('data-testid', 'initial-focused-element')
const container = render(Modal, {
container: document.body.appendChild(wrapper),
slots: {
header: '<h2>Dialog</h2>',
body: '<div><input type="text" data-testid="first-input"/></div>'
}
})
const firstInput = container.getByTestId('first-input')
expect(firstInput).toHaveFocus()
expect(document.body).not.toHaveFocus()
Things I that know / tried:
If I don't have an input element and remove removeActiveFocusedElements() from my vue-component, the initialFocusedElement is focused, so this is working and I have a test for that.
<input type="text" data-testid="first-input"/> is in the "DOM"
focusFirstInput() is called and finds the input element
If I log document.activeElement.outerHTML after firstInput.focus(), it is the input element with the test-id, so it's correct.
If I log document.activeElement.outerHTML in the test though, it is the body, so of course my expects are failing.
I tried it with queryByTestId and that didn't make any difference
I'm running out on ideas to be honest.
I can easily stop the user from writing future dates using the arrows or the keyboard arrows as you can see below, I want also to prevent him from writing future dates in the input field.
I don't want to disable keyboard input completely though because it's useful
document.getElementById("date_end").addEventListener("change", event => {
if (event.target.value > event.target.max) {
event.target.value = event.target.max;
}
});
<input type='date' name='date_end' id='date_end' max="2023-01-03" value="2020-01-01">
The snippet above works, but I ended up using the snippet below, not sure why, using the code above is better.
const dateToDate = date => {
let params = date.split('-');
params[1]--; // months are zero indexed
return new Date(...params);
};
let end_date_input = document.getElementById('date_end');
end_date_input.addEventListener('input', function(){
if(dateToDate(this.value) > dateToDate(this.max)){
this.value = this.max;
}
});
<input type='date' name='date_end' id='date_end' max="2023-01-03" value="2020-01-01">
This is an HTML5 question but related to Angular.
I've been trying to prevent the input of more than one dot in a field with <input type="number"> inside an Angular form. I've tried:
Directive in input element with keypress event to prevent multiple dots.
Custom validator to raise an error when more than one dot it's present.
For now, I'm trying to prevent multiple dot/comma input with a directive applied to the input, removing dot/comma when there is already present a dot/comma or when the input value is an invalid number.
import { Directive, ElementRef, HostListener } from '#angular/core';
#Directive({
selector: '[single-dot]'
})
export class SingleDotDirective {
private el: HTMLInputElement;
constructor(private elementRef: ElementRef) {
this.el = this.elementRef.nativeElement;
}
#HostListener('keypress', ['$event'])
onkeypress(event: KeyboardEvent): void {
const invalidInput = this.el.validity.badInput;
const inputCharSeparator =
String.fromCharCode(event.charCode) === '.' ||
String.fromCharCode(event.charCode) === ',';
const alreadyWithSeparator =
this.el.value.toString().indexOf('.') !== -1 ||
this.el.value.toString().indexOf(',') !== -1;
if (inputCharSeparator && (alreadyWithSeparator || invalidInput)) {
event.preventDefault();
}
}
}
But I found a problem, when I try to capture the current input value, the browser returns an empty string when the number is invalid. You can see the reason here: How to get the raw value an <input type="number"> field?
So for example, for a field like:
<input type="number" id="edQuantity">
edQuantity.value will return:
"2.1" if input number is 2.1
"" if input number is 2.
"2.1" if input number is 2,1
2 if input number is 2,
If I check edQuantity.validity.badInput for the last case I'm getting false.
My code can't detect that the value of the input is bad when a comma is present, so you can input values like:
2,.22
So, my questions are:
Why the validation result it's different for ,?
What's the function of comma when present in field?
Any idea to fix my code?
I've tested this in Chrome and Fx.
Thanks!