Automated Form Filling - javascript

I’m looking for a way to automate a form.
Here are the details:
Extract a certain number (displayed in its html)
Do some calculations on the extracted number (percentage of that number)
Then automatically fill the remaining input fields with the result instead of typing it out.

This is a common occurrence in forms. The solution depends on what framework / libraries you're using. Assuming you're using none, here is how you might go about it:
https://jsfiddle.net/f52h1smj/1/
rough HTML:
<form>
<label for="number">Number: </label>
<input id="number" type="number" />
<br /> <br />
<label for="calculatedNumber">Calculated Number (50%): </label>
<input id="calculatedNumber" type="number" disabled="true" />
</form>
JS:
(() => {
//get the form element nodes
const $number = document.getElementById("number");
const $calculatedNumber = document.getElementById("calculatedNumber");
//add an event listen to the value you're going to use to pre calculate the other fields
$number.addEventListener("keyup", (e) => {
//it's value is available like so
const value = e.target.value;
//do some validation so that you're calculations don't throw exceptions
if (Number(value) !== 0 && !Number.isNaN(value)) {
//set the value of the other inputs to whatever you like by setting the 'value' property of the node.
$calculatedNumber.value = value / 2;
} else {
$calculatedNumber.value = null;
}
});
})();
These things become a lot simpler in frameworks like React and Angular.

Related

How to properly control data input?

There is a task to supervise input in . It is necessary to give the ability to enter only strings of numbers ([0-9]) into the entity input. At the same time, if something else is entered, then do not overwrite value and do not display incorrect input in the input. I can't find a solution for my case. Validity check ( target.validity.valid ) didn't work either because I have control over the minimum and maximum lengths. At the same time, I have a universal function for several inputs, but only the entity needs to be checked. Please tell me how to correctly implement the check for input [0-9] and so that nothing else can be entered.
The examples that are on the resource are not suitable because they do not take into account the control of the minimum-maximum length
Below is a shortened code example
const [inputState, setInputState] = useState({title : "", entity: ""})
const handleChangeInputValue = (event) => {
const { target } = event;
const { name, value } = target;
// Need to check for numbers
setInputState({ ...inputState, [name]: value });
};
<input
required
minLength={5}
type="text"
placeholder="Enter name"
name="title"
value={inputState.title}
onChange={handleChangeInputValue}
/>
<input
required
minLength={13}
maxLength={15}
type="text"
placeholder="Enter entity"
name="entity"
value={inputState.entity}
onChange={handleChangeInputValue}
/>
you can use HTML 5
<input type="number" name="someid" />
This will work only in HTML5 complaint browser. Make sure your html document's doctype is:
<!DOCTYPE html>
if(name==='entity' && !value.match(/^\d+$/)) {
return
}

How to limit multiple input fields (which use v-model) to only accept numbers in Vue.js (without repeating code for every input field)?

I have multiple input fields and I want to limit them to accept numbers only in Vue.js.
I want do disable user from typing any characters except digits from 0-9.
I already did that successfully by doing this(this solution copy-paste proof):
Code in Vue.js template:
<input type="text" name="priceMax" class="input" #input="correctNumberInput" />
Method that removes everything except numbers:
correctNumberInput: function(event){
event.target.value = event.target.value.replace(/[^0-9]/g, "");
}
This worked perfectly fine on multiple fields.
Here comes the problem: For different reason, I needed to use v-model on these input fields. After adding v-model my method doesn't work anymore. I guess it's because v-model also uses input event under the hood. So only adding "v-model", stops it from working:
<input type="text" name="priceMax" class="input" #input="correctNumberInput" v-model="priceMax" />
I have few possible solutions in mind, but all of them include a lot of repeated code.
For example, I could add watchers for every input field, but that would be a lot of repeated code (because I would need to do it for every input field). I have 5 input fields, so basically I would need to write 5 almost identical watchers. I would like to avoid that if that is possible... For example:
watch:{
number(){
this.priceMax = this.priceMax.replace(/[^0-9]/g, "");
}
}
Is there any way I can solve it and make it as simple as my solution was without repeating code? It would be nice to also have solution that is copy-paste proof. All suggestions are welcome! Thanks in advance!
I've tried to test some code. Here what I have (link to the example):
<template>
<div>
<div>
<input
type="text"
name="priceMin"
class="input"
v-model="priceMin"
#input="correctNumberInput"
>
<label v-html="priceMin"></label>
</div>
<div>
<input
type="text"
name="priceMax"
class="input"
v-model="priceMax"
#input="correctNumberInput"
>
<label v-html="priceMax"></label>
</div>
</div>
</template>
<script>
export default {
name: "MyInput",
data: () => {
return {
priceMin: "",
priceMax: ""
};
},
methods: {
correctNumberInput: function(event, data) {
const name = event.target.name;
let value = String(this[name]).replace(/[^0-9]/g, "");
if (value) {
this[name] = parseInt(value, 10);
} else {
this[name] = "";
}
}
}
};
</script>
<style scoped>
input {
border: 1px solid black;
}
</style>
This is the code:
correctNumberInput: function(event, data) {
const name = event.target.name;
let value = String(this[name]).replace(/[^0-9]/g, "");
if (value) {
this[name] = parseInt(value, 10);
} else {
this[name] = "";
}
}
So I used your function, but I am not changing the event.target.value, I am changing the data. So I need to know the name of that data, that's why I use name attribute from input fields (const name = event.target.name;)
Update
If we have input type=number, then it has strange (empty) value inside #input callback. So it seems, better use keyboard filter (example here):
The main idea to have keyboard filter:
filterDigitKeys: function(event) {
const code = window.Event ? event.which : event.keyCode;
const isSpecial =
code === 37 ||
code === 39 ||
code === 8 ||
code === 46 ||
code === 35 ||
code === 36;
const isDigit = code >= 48 && code <= 57;
const isKeypad = code >= 96 && code <= 105;
if (!isSpecial && !isDigit && !isKeypad) {
// if not number or special (arrows, delete, home, end)
event.preventDefault();
return false;
}
}
And attach it to inputs:
<input type="number" min="0" name="numberInput" class="input"
v-model.number="numberInput" #keydown="filterDigitKeys">
Note: if we keep only #keydown handler, then we will not filter text insert into our inputs (but ctrl+v is not working anyway, only by mouse).
Maybe you can try this:
<input type="number" name="priceMax" class="input" #input="correctNumberInput" v-model.number="priceMax" />
From that site: click.

HTML input type=number step prevents form from submitting

I have this code in HTML:
<input type="number" step="0.1" class="form-group">
I want the user to be able to enter a 3-digit decimal number like 1.234 but step needs to be 0.1 and it throws an error and prevents the form from submitting.
I've already tried step="0.100" but the result was the same.
I also need to validate other inputs so I can't use no validate in the <form> tag.
What needs to be done?
I'd write a small customized built-in custom element doing just that:
class MyInput extends HTMLInputElement {
constructor(step = 0.1, value = '') {
super();
this.type = 'number';
this.step = this.getAttribute('step') || step;
this.value = this.getAttribute('value') || value;
this.addEventListener('input', (e) => {
this.value = parseFloat(this.value) + 0.034;
})
}
}
customElements.define('my-input', MyInput, { extends: 'input' });
let input = new MyInput(0.1, 1);
document.body.appendChild(input);
<!-- if you want to use declaratively: -->
<input is="my-input" step="0.1" value="2" />
<hr />
This definitely needs some tweaking, e.g. if the user types in the input, but this should serve you well as a starting point.
One thought is you could remove the step attribute, disable the +/- slider buttons, and implement your own +/- buttons. Then, when a user clicks those buttons, a JavaScript function is called that retrieves the value in the input area, converts it to a number, and performs the desired step.
You might run into precision issues with using a step like 0.1. In the below snippet I just fixed the number of decimal places to two.
function stepUp(step) {
let num = Number(document.getElementById('value').value);
document.getElementById('value').value = (num + step).toFixed(2);
}
function stepDown(step) {
let num = Number(document.getElementById('value').value);
document.getElementById('value').value = (num - step).toFixed(2);
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
<button onclick="stepDown(0.1)">-</button>
<input id="value" type="number" value="0.00">
<button onclick="stepUp(0.1)">+</button>
You can use novalidate and write your own validation in js for other form fields
<form novalidate>
<input type="number" step="0.1" class="form-group" >
<button>submit</button>
</form>

Number with decimal input in React?

I have a number input within a React component, and it needs to accept numbers with a decimal point. Usually, entries will be in the fractions of a cent, like 0.0073, that kind of thing.
<div className="form-group">
<label htmlFor="rate" className="col-sm-6 control-label">Rate:</label>
<div className="col-sm-2">
<input type="number"
title="Rate"
id="rate"
className="form-control"
value={this.props.rate}
min="0.00"
step="0.001"
max="1.00"
onChange={()=>{
console.log('page rate changed');
this.props.setrate($('#rate').val());
}} />
</div>
</div>
The issue is that with every keystroke, it's resetting the rate for the app, and then putting that value into the input. So it goes like this:
User types 0, the value is set to 0, and 0 is displayed.
User types ., 0. isn't a valid number, so the input is cleared.
Can anyone think of a workaround? I know I could just use a normal input, but type="number" leads to some nice stuff in various browsers.
<input
type="text"
value={this.props.rate}
onChange={this.onAmountChange}
/>
type should be text and input value should be defined by regex.
onAmountChange = e => {
const amount = e.target.value;
if (!amount || amount.match(/^\d{1,}(\.\d{0,4})?$/)) {
this.setState(() => ({ amount }));
}
};
regex here means: start with a number and add as many as you want. then optionally end with decimal numbers up to 4 decimals.
You can do something like this
const floatRegExp = new RegExp('^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$')
const handleValidationOnChange = (e, v, onChange) => {
const { value } = v
if (value === '' || floatRegExp.test(value)) {
onChange(e, v)
}
}
const InputFloat = props => {
if (typeof props.onChange !== 'function') {
return <Form.Input { ...props } />
}
const { onChange, ...parentProps } = props
return <Form.Input
{ ...parentProps }
onChange={(e, v) => handleValidationOnChange(e, v, onChange)}
/>
}
Form.Input can be any Component that has a value.
You will have to later check for '', that is unavoidable.
<input type="number"
title="Rate"
id="rate"
className="form-control"
value={this.props.rate}
min="0.00"
step="0.001"
max="1.00"
presicion={2} //very important
onChange={()=>{
console.log('page rate changed');
this.props.setrate($('#rate').val());
}} />
{(text) => this.setState({ value: text.replace( /^[-+]?[0-9]+\.[^0-9]+$/, ''), })}
This will replace any input on runtime if there is any input except decimal number
I had a similar issue where I had decimal numbers in a database and reading them into React. By default, the decimal would show up with trailing zeroes when displaying in React. Trying to display without the trailing zeroes gave me the issue that you describe above. My issue may be slightly different from what you are looking for, but I think it would help others. What I had to do:
Pull the data from the database with the desired formatting. For example: instead of select mynumber from mytable I did select (TRIM(mynumber)+0) as mynumber from mytable. This automatically removes the trailing zeroes.
I then read these values into the React JS script and set in state. These become the value of the input fields.
Then rather than preventing users from entering a non-number value I simply change the background color of the input field to red if the value is not a number.
if (isNaN(mynumber)) {
bgcolor = "#fdd" //Add this to your input style
}
I found the red background above good enough for my purposes but you can also implement an additional check when the user clicks the save button.
I've tried your code and wasn't really affected by your issue, the value is indeed empty when you type the last dot, but the input is not reset.
The thing I changed from your implementation is that I get the input value from the onChange event rather than use jQuery.
<input onChange={e => this.props.setrate(e.target.value)} />
But I doubt your issue comes from that though.
What you could do is not to call your setrate function when you detect an ending dot in your string. Your state will not be modified until the user types a valid number, so one keystroke after the 0..
<input onChange={e => {
const str = e.target.value
if (str.charAt(str.length - 1) === '.') { return }
this.props.setrate(str)
}} />

Enable submit when all form items are valid

I need some help with something... say I have the following form...
<form name="" id="" method="" action="">
<input type="text" id="text1" name="text1" />
<br />
<br />
<input type="text" id="text2" name="text2" />
<br />
<br />
<input type="text" id="text3" name="text3" />
<br />
<br />
<input type="text" id="text4" name="text4" />
<br />
<br />
<input type="submit" value="let's go" disabled="disabled" />
</form>
Now I want to have a simple script to enable the submit when the values of the text boxes are not an empty string or null...
So I have something like this.. which I will bind to the window.onload
function enableButton(){
var formitemsArray = ['text1','text2','text3','text4'],
i;
// Loop through all items
for(i=0;i<formitemsArray.length;i++){
// validate the length on the keypress...
formitemsArray.onkeypress = function(){
// loop through all the items again
for(j=0;j<formitemsArray.length;j++){
if(formitemsArray[j] == "" || formitemsArray[j] == null ){
// return false or something???
}else{
document.getElementById("submitButton").disabled = false;
}
}
}
}
}
Now I think I'm on the right lines to a solution but I'm getting lost when trying to make sure that all the items are greater than a zero length string as I'm returning false too soon. Can someone set me straight please?
Welcome to event bubbling!
This does the following: listen to an event (onkeypress) on the whole element and all its children! Which means you can do the following:
document.getElementById('form-id').onkeypress = function(e) {
var text1 = document.getElementById('text1'),
text2 = document.getElementById('text2'),
text3 = document.getElementById('text3'),
text4 = document.getElementById('text4')
if (text1.value.length > 0 &&
text2.value.length > 0 &&
text3.value.length > 0 &&
text4.value.length > 0) {
document.getElementById('submit-button').disabled = false
}
// As an aside, for later: if you want to get the element
// that triggered the event, you have to do the following
// to be cross-browser:
var evt = e || window.event, // IE doesn't get the event passed by argument
target = e.target || e.srcElement // 'target' is official, old versions of FF used 'srcElement'
// With the 'target' variable, you can now play.
}
There is another more generic solution, but it might not fit your needs (note that it requires a forEach shim:
// Declare a counter variable
var count = 0
document.getElementById('form-id').onkeypress = function(e) {
// Get all the inputs!
var inputs = this.getElementsByTagName('input')
// Now loop through all those inputs
// Since a NodeList doesn't have the forEach method, let's borrow it from an array!
[].forEach.call(inputs, loopThroughInputs)
}
function loopThroughInputs(input) {
// First check the type of the input
if (input.type === 'text') {
// If the value is correct, increase the counter
if (input.value.length > 0) {
count++
}
// If the 4 inputs have increased the counter, it's alright!
if (count === 4) {
document.getElementById('submit-button').disabled = false
}
}
}
And now this code was proposed by #Esailija, and it is way better and cleaner. However, it also requires ES5-Shim (for the every method):
document.getElementById('form-id').onkeypress = function(e) {
var inputs = [].slice.call( this.querySelectorAll( '[type=text]') );
document.getElementById('submit-button').disabled = !inputs.every(function(input){
return !!input.value;
});
}
(This guy is brillant, just don't tell him)
There are a few ways you can do this... One would be to keep the button enabled but use javascript to check the validity of the form data upon submission. The benefit to this is that the validation code is only run once, when the user clicks submit and is expecting his data to be validated (at least I do) .
function validateForm() {
var formElement = document.forms[0]; // you didn't give me a name
for(var i = 0, l = formElement.elements.length; i < l; i++ ) {
if( formElement.elements[i].value.length === 0 ) {
return false;
}
return true;
}
}
The other way is live validation, which would validate each input onBlur (focus lost). This method has the benefit of showing the user in real time what values are bad, however this can be very resource heavy depending on the number of form elements and the way you introduce the check.
Personally I would go with my first suggestion; however with that said if you choose to validate each element, I would do so like this:
var formElement = document.forms[0]; // you didn't give me a name
for(var i = 0, l = formElement.elements.length; i < l; i++ ) {
formElement.elements[i].addEventListener('blur', function() {
if( this.value.length === 0 ) {
alert('this input is invalid');
}
}, false);
}
The latter method also requires you hold onto a 'state' variable to determine whether or not the form is valid upon submission, or check all the values again.
Hope this sheds some light, and I hope my code examples help some.
If possible use jquery validation plugin instead of re-inventing the code, http://docs.jquery.com/Plugins/Validation its so easy to use.
In this jsfiddle you'll find a way to monitor the progress of form contents. If all the field conditions are fulfilled, a submit button is shown. Maybe it's useful for you. Bare in mind that client side checking of a form may be tampered with, so you always need a server side check too, if your data need to adhere to certain requirements. In other words: client side form checks are merely usability enhancements.

Categories