Home > OS >  Input Masking in Javascript
Input Masking in Javascript

Time:05-25

I have an input where users are going to type identification numbers and I would like to mask that input so that it always has this format : XX-XXXXXXXX-X

The X's can only be numbers and the dashes need to be always in those positions.

Here is what I got so far:

import React from "react";
import { Inertia } from "@inertiajs/inertia";
import {useForm, usePage} from "@inertiajs/inertia-react";
import ErrorForm from "./ErrorForm"

function Login() {
    const{data , setData , processing ,reset} = useForm({
        cuit: '',
        password: ''
    })
    const errors = usePage().props.errors

    function submit(e){
        e.preventDefault()
        Inertia.post(route('login'),data,{
            one rror:() => reset('password')
        })
    }

    function handleChange(e){
        if(e.target.value.length === 11){
            e.target.value = [e.target.value.slice(0,11),'-'].join('')
        }else if(e.target.value.length >= 2){
            if(!e.target.value.includes('-')){
                e.target.value = [e.target.value.slice(0,2),'-',e.target.value.slice(2)].join('')
            }
        }
        setData('cuit',e.target.value)
    }

    function handleKeyDown(e){
        if(e.key === "0" || e.key === "1" || e.key === "2" || e.key === "3" || e.key === "4" || e.key === "5" || e.key === "6" || e.key === "7" || e.key === "8" || e.key === "9"){
            handleChange(e)
        }
    }
    return(
        <div className="ContenedorLogin">
            <form onSubmit={submit}>
                <input
                    name="cuit"
                    type="text"
                    placeholder="C.U.I.T."
                    className="input"
                    onKeyDown={handleKeyDown}
                    maxLength="13"
                />
                {errors.cuit &&
                    <ErrorForm
                        content={errors.cuit}
                    />
                }
                <input
                    name="password"
                    type="Password"
                    placeholder="Contraseña"
                    className="input"
                    value={data.password}
                    onChange={e => setData('password',e.target.value)}
                />
                <button className="btn-consejo" type="submit" disabled={processing}>INGRESAR</button>
            </form>
        </div>
    )

}

export default Login

Basically I'm capturing a keyDown event, then changing the input only if the user typed a number and finally in the handleChange function I try to mask and set the value.

It kind of work but not for all cases, for example if I'm in the middle of typing and I already have the first dash and I add a number before the first dash its going to allow it leaving me with something like this : XXXX-XXXXX

I imagine I can achieve the result using regular expressions or something like that but I'm not familiar at all with them

Thanks in advance!

CodePudding user response:

It would work if you bind event on whole input value instead of each key press.

Here, instead of using event "onKeyDown", use "onChange". Also You can use html pattern for accepting number only.

<input
    name="cuit"
    type="number"
    pattern="[0-9\/]*"
    placeholder="C.U.I.T."
    className="input"
    onChange={handleChange} // calling handleChange on input change directly
    maxLength="13"
/>

You already have working handleChange() function, which will work perfectly.

CodePudding user response:

Instead of using JS to do this use the in-build HTML form validation.

Add a required attribute and a regex pattern to the input. The form won't submit until the input has been validated. And you'll also get little tool-tips to explain what the issue is if you try to submit and the input isn't validated.

In this case the regex reads:

^ - start of the value
[0-9]{2}- two numbers followed by a dash
[0-9]{8}- eight numbers followed by a dash
[0-9] - one number
$ - end of the value

const { useState } = React;

function Example() {
  
  const [input, setInput] = useState('');
  
  function handleSubmit(e) {
    e.preventDefault();
    console.log(`Submitted: ${input}`);
  }
  
  function handleChange(e) {
    setInput(e.target.value);
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        onChange={handleChange}
        placeholder="dd-dddddddd-d"
        pattern="^[0-9]{2}-[0-9]{8}-[0-9]$"
        value={input}
        required
      />
      <button type="submit">Submit</button>
    </form>
  );

}

ReactDOM.render(
  <Example />,
  document.getElementById('react')
);
input, button { font-size: 1.2em; }
input { padding: 0.3em; }
input:invalid { border: 1px solid red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

  • Related