skip to Main Content

There’s an input field, when the user will type any fullwidth Japanese character (numbers only) it won’t be displayed on that input field. It’ll be converted to its respective halfwidth character and, then that halfwidth character will be visible inside that same input field.
If user type , this will not be shown in the input field, it’ll show the converted halfwidth 0. In my case the problem is if the user types , the function is running twice and showing 00, but it should be only 0. Can anybody please help me to sort it out?

<input type="text" id="inputField" oninput="convertToHalfWidth(this.value)">
<script>
    function convertToHalfWidth(input) {
        console.log(input);
        // Map of full-width to half-width numbers
        const fullToHalfMap = {
            '0': '0', '1': '1', '2': '2', '3': '3', '4': '4', '5': '5', '6': '6', '7': '7', '8': '8', '9': '9'
        };

        // Replacing full-width numbers with their half-width counterparts
        const convertedInput = input.replace(/[0-9]/g, match => fullToHalfMap[match]);

        // Updating the input field with the converted value
        document.getElementById('inputField').value = convertedInput;
    }
</script> 

2

Answers


  1. You’re so close! I think the issue was that was being converted to zero, but I’m not able to verify that. I also didn’t see the 00 output you described (I’m using Firefox if that matters). However, I did observe that no replacement was made. This was solved by forcing the match output to a string with match.toString()

    function convertToHalfWidth(input) {
        console.log(input);
        // Map of full-width to half-width numbers
        const fullToHalfMap = {
            '0': '0', '1': '1', '2': '2', '3': '3', '4': '4',
            '5': '5', '6': '6', '7': '7', '8': '8', '9': '9'
        };
    
        // Replacing full-width numbers with their half-width counterparts
        const convertedInput = input.replace(/[0-9]/g,
            match => fullToHalfMap[match.toString()]);
    
        // Updating the input field with the converted value
        document.getElementById('inputField').value = convertedInput;
    }
    <input type="text" id="inputField" oninput="convertToHalfWidth(this.value)">
    Login or Signup to reply.
  2. As per spec:

    The start of a composition is marked by dispatching a compositionstart event. During a composition session, whenever a text composition system updates its active text passage, a compositionupdate event is dispatched. After each compositionupdate event, a pair of beforeinput and input events are dispatched.

    The problem is an input event with type insertCompositionText is fired whenever an a composition session starts/updated/ends. Even for simple full width characters like numbers and space that doesn’t require multiple symbols composed using an IME window, there will still be two input event fired by compositionstart and compositionend. (Reproduced on Latin and Chinese IME only. For Japanese IME I can’t figure out how to type full width numbers without choosing them from the IME candidate list. By default in preview they are always half-width, hence only trigger conversion in the compositionend event)

    Note that this problem won’t be reproduced by pasting the full characters because there won’t be any composition session started. Only an input event with type insertText will be started.

    One solution is to use an additional compositionend event to handle composition input types. (Or a simple onkeyup is enough if you are okay with the delay between keydown and keyup.)

    const inputField = document.getElementById('inputField');
    const fullToHalfMap = {
        '0': '0', '1': '1', '2': '2', '3': '3', '4': '4', '5': '5', '6': '6', '7': '7', '8': '8', '9': '9'
    };
    
    inputField.addEventListener('input', function (e) {
        // Might be enough to only check insertFromPaste inputType
        if (e.inputType !== 'insertCompositionText') {
            convertToHalfWidth(e);
        }
    })
    
    inputField.addEventListener('compositionend', convertToHalfWidth);
    
    function convertToHalfWidth(e) {
        const input = e.target.value;
        // Replacing full-width numbers with their half-width counterparts
        const convertedInput = input.replace(/[0-9]/g, match => fullToHalfMap[match]);
        // Updating the input field with the converted value
        inputField.value = convertedInput;
    }
    <input type="text" id="inputField">
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search