Form input field - formating a number when it's introduced key by key
Tags: javascript, form, input, format
Published: 2021-01-14 01:56:27

There are various classes
Integer numbers positives and negatives or only the positives
Float numbers positives and negatives or only the positives
Float numbers fixing to 2 decimals 

demo and free to copy from:
https://www.bc3toexcel.com/compartir/input-format-number-as-keyed.htm

```
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>FORMAT (PUT THOUSANDS SEPARATOR) INSIDE A FORM NUMERIC INPUT FIELD AS THE VALUE IS KEYED</title>
        <style>
            input {padding: 20px;margin: 10px;font-size: 18px;}
            .label,
            .integerPositive,
            .integerIndistinct,
            .numberPositive,
            .numberIndistinct,
            .numberPositiveFixed,
            .numberIndistinctFixed {text-align: right;}
            .positives {color: black;}
            .negatives {color: red;}
            .oculto{display:none;}
            .visible{display:block;}
            .table_data_received table,
            .table_data_received tr,
            .table_data_received th,
            .table_data_received td{border: 1px solid black; text-align:right;}
        </style>
    </head>
    <body>
        <h2>FORMAT (PUT THOUSANDS SEPARATOR) INSIDE A FORM NUMERIC INPUT FIELD AS THE VALUE IS KEYED</h2>
        <!-- ONLY FOR TESTING PURPOSE -->
        <div id="data_received" class="oculto">
            <h2>DATA RECEIVED FROM FORM</h2>
        </div>
        <!-- TEST FORM SAMPLE-->
        <form id="TheForm" class="oculto" method="get" action="input-format-number-as-keyed.htm" onsubmit="return removeNumberFormat(true);">
            <table>
                <tr>
                    <td class="label">Integer(+/-)</td>
                    <td><input class="integerIndistinct" name="integer1" id="integer1"></td>
                </tr>
                <tr>
                    <td class="label">Integer(+)&gt;= 0</td>
                    <td><input class="integerPositive" name="integer2" id="integer2"></td>
                </tr>
                <tr>
                    <td class="label">Float(+/-)</td>
                    <td><input class="numberIndistinct" name="number1" id="number1"></td>
                </tr>
                <tr>
                    <td class="label">Float(+)&gt;= 0</td>
                    <td><input class="numberPositive" name="number2" id="number2"></td>
                </tr>
                <tr>
                    <td class="label">Float Fixed 2 (+/-)</td>
                    <td><input class="numberIndistinctFixed" name="number3" id="number3"></td>
                </tr>
                <tr>
                    <td class="label">Float Fixed 2 (+)&gt;= 0</td>
                    <td><input class="numberPositiveFixed" name="number4" id="number4"></td>
                </tr>
            </table>
            <input type="submit" value="submit">
        </form>
        <script>
        //================================      ======================================
        //==============   THIS PART OF THE CODE IS ONLY FOR TESTING    ==============
        //================================      ======================================
        //To test if the form submitted data has been changed removing the thousands
        //separators from the numeric values and show the result in dev.tools console.
        //Can be eliminated after test is successful
        //============================================================================
        function reset_form() {
        	window.location.replace(location.pathname);
        }
        const getURLParameters = url =>
        (
        /*
         * extract the parameters from the url that has been called
         * @param  {string} the url that has been called
         * @return {array} returns an associative array of the input variables
         */
        	url.match(/([^?=&]+)(=([^&]*))/g) ||[]).reduce(
        	(a, v) => ((a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a), {}
        );
        let array_param = getURLParameters(window.location.href);
        let array_keys = Object.keys(array_param);
        if (array_keys.length!==0) {
        	let div = document.getElementById("data_received");
        	let table = document.createElement("table");
        	table.className = "table_data_received";
        	let tr = document.createElement("tr");
        	let len = array_keys.length;
        	for(let i = 0; i < len; i++) {
        		let th = document.createElement("th");
        		th.innerHTML = decodeURIComponent(array_keys[i]);
        		tr.appendChild(th);
        	}
        	table.appendChild(tr);
        	tr = document.createElement("tr");
        	for(let j = 0; j < len; j++) {
        		let td = document.createElement("td");
        		td.innerHTML = decodeURIComponent(array_param[array_keys[j]]);
        		tr.appendChild(td);
        	}
        	table.appendChild(tr);
        	div.appendChild(table);
        	let button = document.createElement("input");
        	button.setAttribute("style", "cursor:pointer; margin-top:10px;");
        	button.setAttribute("type", "button");
        	button.setAttribute("value", "Repeat");
        	button.setAttribute("onclick", "reset_form();");
        	div.appendChild(button);
        	div.className = "visible";
        	let form = document.getElementById("TheForm");
        	form.className = "oculto";
        }else {
        	let form = document.getElementById("TheForm");
        	form.className = "visible";
        }
        //================================      ======================================
        //==========================   END OF TESTING    =============================
        //================================      ======================================
        //############################################################################
        /**
         * @format-numeric-input-as-keyed.js
         * @version     : 1.0
         * @author      : Aitor Solozabal Merino (aitorsolozabal@gmail.com)
         * @purpose     : Format a number (with thousands separator) in an input field
         *                of a form as it is being entered key by key on the keyboard
         * History
         * @version     : v1.0 – initial
         * FUNCTIONS LIST
         * ==============
         * function integerFormatIndistinct()
         * function integerFormatPositive()
         * function numberFormatIndistinct()
         * function numberFormatPositive()
         * function numberFormatIndistinctFixed()
         * function numberFormatPositiveFixed()
         * There are classes / categories defined to associate with each function and that
         * are related when declaring the keyup event for each one of them
         *   .integerPositive,
         *   .integerIndistinct,
         *   .numberPositive,
         *   .numberIndistinct,
         *   .numberPositiveFixed,
         *   .numberIndistinctFixed {text-align: right;}
         *   .positives {color: black;}
         *   .negatives {color: red;}
         * function numberFormat(strNumber, n, thousands, decimals, minusSigned = true)
         * function removeNumberFormat(emptyValues = true) to be call from form submit
         */
        //############################################################################
        // global variables to define the thousands and decimals separator
        // For thousands a comma and a point for decimal (USA)
        let DECIMALS = ".";
        let THOUSANDS = ",";
        // change to "," for decimal comma and point in thousands (SPAIN)
        // =============================================== ===========================
        function numberFormat(strNumber, n, thousands, decimals, minusSigned = true) {
        /**
         *This function is called from other functions that are activated when the "keyup"
         *event occurs when typing from the keyboard by entering a character within a text
         *entry in a form that you want to give a numeric format.
         *
         *As it is allowed to add characters to the beginning in the middle or at the
         *end of the input text of the form, cases of generation of invalid numbers
         *can occur due to the concurrence of multiple factors.
         *Cases to control of strNumber content with the rule that there can only be
         *one minus symbol and it must be at the beginning and a single decimal
         *separator that can be anywhere.
         *In addition, the following combinations must be processed
         * "-" "." "-." "--" ".." "0" "-0" "-0." "0." "00" "0n" ".n" ".n." "-n-"
         *
         * This function also serves to return a formatted number for printing or display
         * on the screen independently of using it in the numeric fields of a form
         * ===============================================================================
         * @param string strNumber: string with the number to format
         * @param integer n: length of decimal (>0)fixed (=0)integer (=-1)float not fixed
         * @param string  thousands: sections delimiter THOUSANDS  USA "," SPAIN "."
         * @param string  decimals: decimal separator   DECIMALS   USA "." SPAIN ","
         * ===============================================================================
         * @VERSION  : 1.0
         * @DATE     : 27 January 2020
         * @AUTHOR   : Aitor Solozabal Merino (aitorsolozabal@gmail.com)
         * sample use:
         * integer not minus
         * console.log("integer "+"-123456.789"+"  0 decimales = "+numberFormat("-123456.789", 0, ",", ".",false));
         * output 123,456
         * float indistinct not fixed
         * console.log("float "+"-123456.789"+"  -1 decimales = "+numberFormat("-123456.789", -1, ",", ".",true));
         * output -123,456.789
         * float fixed not minus
         * console.log("float "+"-123456.789"+"   2 decimales = "+numberFormat("-123456.789",  2, THOUSANDS, DECIMALS,false));
         * output 123,456.78
         */
        	let re = '\\d(?=(\\d{3})+$)';
        	let resultado = "";
        	let hasminusSymbol = false;
        	let hasdecimalsSeparator = false;
        	let nextCharacter = "";
        	let initialZero = false;
        	let numParts =[];
        	let integerPart = "";
        	let decimalPart = "";
        	let firstDecimal = -1;
        	//filter (minusSigned && n!==0) numbers, minus symbol, decimals separator
        	let filterNumber1 = new RegExp('[^ 0-9\\-\\'+decimals+']', 'g');
        	//filter (minusSigned && n===0) numbers, minus symbol not decimals separator
        	let filterNumber2 = new RegExp('[^ 0-9\\-]', 'g');
        	//filter (!minusSigned && n!==0) numbers, decimals separator not minus symbol
        	let filterNumber3 = new RegExp('[^ 0-9\\'+decimals+']', 'g');
        	//filter (!minusSigned && n===0) only numbers are permitted
        	let filterNumber4 = new RegExp('[^ 0-9]', 'g');
        	//Only numbers, decimals separator and minus symbol are allowed, so the
        	//number is filtered to eliminate those characters that are not valid
        	//================================================================== F I R S T
        	//first filtering of invalid characters
            //the thousands delimeters are eliminated in this filter process
        	strNumber = strNumber.replace(filterNumber1, "");
        	if (strNumber.length>0) {
        		//============================================================ S E C O N D
        		//If the minusSigned parameter is false, then this symbol is not allowed
        		//and only positive values are valid.
        		//Therefore you have to see if the first character is the minus symbol "-"
        		//and, if so, it must be removed to be added to the final result of the
        		//formatting process if the minusSigned parameter is true.
        		hasminusSymbol = (strNumber.substring(0, 1)==="-");
        		strNumber = strNumber.replace(filterNumber3, "");
        		if (strNumber.length>0) {
        			//========================================================== T H I R D
        			//if the first character is the decimal separator strNumber must be
        			//filtered eliminating all ocurrences of the decimalseparator in
        			//strNumber with a filter and then it is added with the zero character
        			//previously "." --> "0."
        			hasdecimalsSeparator = (strNumber.substring(0, 1)===decimals);
        			strNumber = (hasdecimalsSeparator)? "0.": strNumber;
        			if (!hasdecimalsSeparator) {
        				//if there is no decimal separator at the beginning, check if there
        				//is a decimal separator and check that this is the only one by
        				//erasing the excess ones
        				firstDecimal = strNumber.indexOf(decimals);
                        hasdecimalsSeparator = (firstDecimal>0);
    					//There is at least one decimal separator in strNumber
    					//Clean any other occurrence of a decimal separator in strNumber
    					strNumber = hasdecimalsSeparator?strNumber.substring(0, firstDecimal)+decimals+strNumber.substring(firstDecimal+1, strNumber.length).replace(filterNumber4, ""):strNumber;
        			}
        			//======================================================== F O U R T H
        			//"0"
        			initialZero = (strNumber.substring(0, 1)==="0");
        			//the first character can be a 0 or a decimal separator
        			if (initialZero) {
        				//if the first character is the number zero then the next character
        				//must be obtained and find out if it is a number or the decimal
        				//separator.
        				//It could be a "0." or a "0n"
        				nextCharacter = (strNumber.length>1)? strNumber.substring(1, 2): "";
    					//strNumber is of type "0n"
    					//"01"     "1" / "00"    "0"
    					//In this case the leading zero character is removed
    				    strNumber = ((nextCharacter.length>0) && (nextCharacter!==decimals))?strNumber.substring(1, strNumber.length):strNumber;
        			}
        			//========================================================== F I F T H
        			//strNumber is divided into 2 parts using the defined decimal separator
        			//character as an element that separates the integer part and the
        			//decimal part if it exists
        			numParts = strNumber.split(decimals);
        			integerPart = numParts[0];
        			decimalPart = (numParts.length>1)? numParts[1]: "";
        			//========================================================== S I X T H
        			// add the thousands separators
        			resultado = integerPart.replace(new RegExp(re, 'g'), '$&' + (thousands));
        			//====================================================== S E V E N T H
        			//join the 2 parts to obtain the result with the established format
        			if (n!==0) {
        				if (n>0) {
        					//fixed decimals
        					decimalPart = (decimalPart.length>n)? decimalPart.substring(0, n): decimalPart;
        				}
    					resultado = (hasdecimalsSeparator)? resultado+decimals+decimalPart: resultado;
        			}
        		}
        	}
        	//================================================================ E I G H T H
        	//check if the minus symbol is allowed so that if it exists add it to the final
        	//result before being returned
        	resultado = (minusSigned && hasminusSymbol)? "-"+resultado: resultado;
        	return resultado;
        }
        function integerFormatIndistinct() {
        	// Format integers indistinctly both positive and negative
        	if (this.value.length>0) {
        		this.value = numberFormat(this.value, 0, THOUSANDS, DECIMALS, true);
        		this.className = (this.value.substring(0, 1)==="-")? "negatives integerIndistinct": "positives integerIndistinct";
        	}
        }
        function integerFormatPositive() {
        	// Format only positive integers
        	this.value = this.value.length>0? numberFormat(this.value, 0, THOUSANDS, DECIMALS, false): "";
        }
        function numberFormatIndistinct() {
        	// Format decimal numbers indistinctly both positive and negative
        	if (this.value.length>0) {
                this.value = numberFormat(this.value, -1, THOUSANDS, DECIMALS, true);
        		this.className = (this.value.substring(0, 1)==="-")? "negatives integerIndistinct": "positives integerIndistinct";
        	}
        }
        function numberFormatPositive() {
        	// Format only positive decimal numbers
        	this.value = this.value.length>0? numberFormat(this.value, -1, THOUSANDS, DECIMALS, false): "";
        }
        function numberFormatIndistinctFixed() {
        	// Format decimal numbers indistinctly both positive and negative
        	// but with 2 decimal places fixed as maximum
        	if (this.value.length>0) {
            	this.value = numberFormat(this.value, 2, THOUSANDS, DECIMALS, true);
        		this.className = (this.value.substring(0, 1)==="-")? "negatives integerIndistinct": "positives integerIndistinct";
        	}
        }
        function numberFormatPositiveFixed() {
        	// Format only positive decimal numbers with 2 decimal places fixed as maximum
        	this.value = this.value.length>0? numberFormat(this.value, 2, THOUSANDS, DECIMALS, false): "";
        }
        function removeNumberFormat(emptyValues = true) {
        	//************************************************************************
        	//The text input fields that contain the formatted numbers of the form must be
        	//prepared before they are sent, eliminating the thousands separators and
        	//placing the decimal separators of the system to transmit the data.
        	//If the boolean variable emptyValues is true, then all values will be sent
        	//including those that are empty, otherwise only non-empty values will be sent
        	//This function is called with the instruction in the <form> tag
        	//onsubmit = "return removeNumberFormat(emptyValues);"
        	//************************************************************************
        	let filterNumber = new RegExp('[^ 0-9\\-' + '\\' + DECIMALS + ']', 'g');
        	let integer1 = document.getElementById('integer1');
        	//eliminate thousands separator with the filterNumber
        	integer1.value = integer1.value.replace(filterNumber, "");
        	//to remove the field integer1 from submit data if it is empty then:
        	if (!emptyValues) {
        		if (integer1.value==="") {integer1.parentNode.removeChild(integer1);}
        	}
        	let integer2 = document.getElementById('integer2');
        	//eliminate thousands separator with the filterNumber
        	integer2.value = integer2.value.replace(filterNumber, "");
        	//to remove the field integer2 from submit data if it is empty then:
        	if (!emptyValues) {
        		if (integer2.value==="") {integer2.parentNode.removeChild(integer2);}
        	}
        	let number1 = document.getElementById('number1');
        	//eliminate thousands separator with the filterNumber
        	number1.value = number1.value.replace(filterNumber, "");
        	number1.value = number1.value.replace(DECIMALS, ".");
        	//to remove the field number1 from submit data if it is empty then:
        	if (!emptyValues) {
        		if(number1.value==="") {number1.parentNode.removeChild(number1);}
        	}
        	let number2 = document.getElementById('number2');
        	//eliminate thousands separator with the filterNumber
        	number2.value = number2.value.replace(filterNumber, "");
        	//replace decimals separator in format number with system decimal separator
        	number2.value = number2.value.replace(DECIMALS, ".");
        	//to remove the field number2 from submit data if it is empty then:
        	if (!emptyValues) {
        		if(number2.value==="") {number2.parentNode.removeChild(number2);}
        	}
        	let number3 = document.getElementById('number3');
        	//eliminate thousands separator with the filterNumber
        	number3.value = number3.value.replace(filterNumber, "");
        	//replace decimals separator in format number with system decimal separator
        	number3.value = number3.value.replace(DECIMALS, ".");
        	//to remove the field number3 from submit data if it is empty then:
        	if (!emptyValues) {
        		if(number3.value==="") {number3.parentNode.removeChild(number3);}
        	}
        	let number4 = document.getElementById('number4');
        	//eliminate thousands separator with the filterNumber
        	number4.value = number4.value.replace(filterNumber, "");
        	//replace decimals separator in format number with system decimal separator
        	number4.value.replace(DECIMALS, ".");
        	//to remove the field number4 from submit data if it is empty then:
        	if (!emptyValues) {
        		if(number4.value==="") {number4.parentNode.removeChild(number4);}
        	}
        	return true;
        }
        //////////////////////////////////////////////////////////////////////////////////
        window.onload = function() {
        	// IT IS EXECUTED AFTER LOADING ALL THE CSS & HTML & JAVASCRIPT CODE
        	//============================================================================
        	// Create the keyup event for each defined class and relate it to the appropriate function
        	//============================================================================
        	document.querySelectorAll(".integerIndistinct").forEach(el => el.addEventListener("keyup", integerFormatIndistinct));
        	document.querySelectorAll(".integerPositive").forEach(el => el.addEventListener("keyup", integerFormatPositive));
        	document.querySelectorAll(".numberIndistinct").forEach(el => el.addEventListener("keyup", numberFormatIndistinct));
        	document.querySelectorAll(".numberPositive").forEach(el => el.addEventListener("keyup", numberFormatPositive));
        	document.querySelectorAll(".numberIndistinctFixed").forEach(el => el.addEventListener("keyup", numberFormatIndistinctFixed));
        	document.querySelectorAll(".numberPositiveFixed").forEach(el => el.addEventListener("keyup", numberFormatPositiveFixed));
        };
        //////////////////////////////////////////////////////////////////////////////////
        </script>
    </body>
</html>
```