I have a form in Vue that has some combined inputs for styling reasons for a phone number input.
My problem is that the user has to hit tab in order to go to the next input field of the phone number.
Is there a way to check for the max length of the current and input and when that is met go to the next input?
<div class="combined-input combined-input--phone" :class="{'error--input': phoneInvalid('patientInformation')}">
<div class="open-parenthesis"></div>
<input type="text" id="phoneArea" maxlength="3" #blur="$v.formData.patientInformation.phone.$touch()" v-model.trim="$v.formData.patientInformation.phone.area.$model">
<div class="close-parenthesis"></div>
<input type="text" id="phoneA" maxlength="3" #blur="$v.formData.patientInformation.phone.$touch()" v-model.trim="$v.formData.patientInformation.phone.a.$model">
<div class="dash"></div>
<input type="text" id="phoneB" maxlength="4" #blur="$v.formData.patientInformation.phone.$touch()" v-model.trim="$v.formData.patientInformation.phone.b.$model">
</div>
Pretty sure this is not recommended UX-wise but here is an example on how you can achieve it: https://codesandbox.io/s/move-to-next-input-on-condition-103b5?file=/src/App.vue
The main part of useful code is
focusNextOncePopulated(event, max) {
if (event.target.value.length === max) {
const nextElement = this.$refs?.[`input-${Number(event.target.dataset.index) +1}`]
if (nextElement) nextElement.focus()
}
},
Explanation: each time you input a char, you check if the length of the field reached the maximum you've set on a particular input. If it is and there is a similar input as a sibling, you focus it.
Adding a debounce of a few milliseconds would be nice too, performance-wise.
EDIT: to prevent any issues of trying to find the correct next input in the DOM, we setup some refs on each of the inputs (recommended way in Vue to select some DOM elements). Then, when we have reached the max, we increment our current's input data-index by one, which enables us to go to the next input.
PS: ?. syntax is optional chaining, it prevents ugly code and allows to avoid an error if there is no next input once max is reached.
PS: Not sure if there is a way to directly get the $refs of an element on it's #input event but if there is, I didn't found out how to do it.
Related
I'm trying to figure out a way that I can validate the user inputs on this input that is dynamically rendered roughly 30 separate times,
<form>
<div class="pseudo_table">
<div class="table_div" v-for="(item, index) in inputArray" v-if="index > 0 && index <= 30">
<p class="header thead">Year {{ index }}</p>
<input class="interest_input" type="number" maxlength="6" v-model="inputArray[index]" />
<label for="table_input" class="static_value">%</label>
</div>
</div>
</form>
Below you can find a picture of the code thats pasted in the side scroll above. With the added buttons that are mentioned later in the story.
As you can see I am rendering with v-for and have set a maxlength of 6 but since this a number type input the maxlength does not work.
I added a watch option but this actually doesn't work in real time and isn't doing anything to limit character length in the input. Further I would like to limit the range at which an input number can reach. If the number being entered is x.xxx greater than the old value it should show an error as well as disable the save & continue button.
watch: {
inputArray(newVal, oldVal) {
if (newVal - oldVal > this.settingsAssumptions.indexAverageAnnualIncrease) {
}
if (oldVal - newVal > this.settingsAssumptions.indexAverageAnnualDecrease) {
}
if (newVal.toString().length > 6) {
parseFloat(newVal.slice(0, 6)).toFixed(3)
}
}
}
disabling the save and continue button is likely one of the easier things I can implement but I can't wrap my head around the watch functionality in the docs. Does anyone have any insight?
I've tried a suggestion made on another SO post that recommended using the oninput to validate the length and limit it in real time but unfortunately due to my inputs being text-align:right, when typing in the input field and adding a decimal, it will shift to the left of the number.
I trying to get cursor position inside input field, which is type number
<input type="number" id="myInput">
And I tried standard selectionStart property, but apparently it does not work for number fields.
var start = document.getElementById("myInput").selectionStart;
Is there any why or workaround to get that information inside keypress event?
My end goal is it prevent leading zeros in such input field, for that I need to know is user input coming to start of existing value.
Currently I stripping those zeros in keyup event:
var inputFieldValue = $(this).val();
$(this).val(removeLeadingZeros(inputFieldValue)); // removeLeadingZeros: inputString.replace(/^0+/, "");
But with that solution those zeros became visible for a second before been removed,
that behavior I want to prevent.
Any ideas? How I can get end result string before it provided to user inside input element? Even as selectionStart value not available for number input, browser somehow know where to put those new characters, so there must be some way to capture that and may be prevent some default behavior or stop bubbling.
You can try RegExp
<input type="number" id="myInput">
$("#myInput").on("input", function() {
if (/^0/.test(this.value)) {
this.value = this.value.replace(/^0/, "")
}
});
It was only preventing negative numbers from being entered from up/down arrows, whereas user can type negative number from keyboard.
<div class="col-sm-2">
<label>Quantity</label><br>
{{input type="number" value=quantity min="0" class="form-control-
invoice"}}
</div>
This is a good example for data down, actions up (DDAU) principle. The data should flow down to your component (or element) but only by updated by your application if it matches certain criteria. Sadly the {{input}} helper does not support DDAU principle. But you could easily accomplish your goal without using it:
<input type="number" value={{quantity}} onchange={{action "updateQuantity" value="target.value"}} min="0" >
We are using a standard <input> element and bind it's value property to quantity. We bind a custom action to the change event. In that action we could check if the updated value meets our criteria and if so update quantity. The action may look like the following:
actions: {
updateQuantity(val) {
val = parseInt(val);
if (val >= 0) {
this.set('quantity', val);
} else {
window.alert('number must not be negative');
this.notifyPropertyChange('quantity');
}
}
}
Please note that we have to call notifyPropertyChange() if the new value does not meet our criteria. This will trigger an update of UI to reset the value of the <input> element.
I've written an Ember Twiddle demonstrating the approach: https://ember-twiddle.com/bcf03934667364252e52b21930d664fd?openFiles=templates.application.hbs%2C
Im trying to be as ellaborative as i can with my question....
Scenario:
I have three input fields in my html page Two of them are to accept user inputted values and the third one binds(adds) these two values.
Done so far:
I initially used <input value="{{value1+value2}}" id="value3"/> which took the values as string; solved this issue by substracting the string by 0. But, this calculated values wont go off even using the reset button.
Then someone here on SOF told me to use <input ng-model="(value1-0)+(value2-0)" id="value3"/> which works, but i noticed that even though the values disapper visually the model still holds some value.
(When, i enter some value into the first input field, the third calculated field add the value of the inputted field with the previous value of the second input field(value that the second field had previous to the reset)
NOTE:
Reset method resets the values of the first two user inputted fields, but not that of the third calcualtion field while using <input value="{{value1+value2}}" id="value3"/> OR <input ng-bind="value1+value2" id="value3"/>
While, when using <input ng-model="(value1-0)+(value2-0)" id="value3"/> the calculated field is visually cleared but when i enter some value into one of the user inputted fields(value1 or value2) the calculated field adds the entered number with the previous number that the field ccontained.
I tried many ways to solve this issue, but with no suuccess.... can someone please guide me through?
Thanks in advance.....
Here's a simple fiddle . Follow the link and take a look.
Basically, to have only number values in the user inputed fields, I used HTML5 number inputs, readily available in any newer browser.
<div ng-controller="MyCtrl">
<input type="number" ng-model="value1" />
<input type="number" ng-model="value2" />
<input type="text" ng-model="value1 + value2" />
<button type="button" ng-click="reset()">RESET</button>
</div>
And as for the javascript, here is my controller:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', MyCtrl)
function MyCtrl($scope) {
$scope.value1 = '';
$scope.value2 = '';
$scope.value3 = '';
$scope.reset = function() {
$scope.value1 = '';
$scope.value2 = '';
$scope.value3 = '';
};
}
The three values are first initialized as empty strings, and on ng-click of the RESET button, they are nullified again.
NOTE: For the sake of simplicity I used number inputs instead of trying to implement some kind of javascript validation which I would suggest for production level. The point of my answer was just to explain the principle using the most basic concepts.
Let's say we have 2 input boxes:
num1
num2
When the user inputs a number in any of the 2 input boxes, what we want to happen is automatically set the value of the other input box to the opposite sign of the number.
Examples:
User inputs 1 in num1. The value of num2 should automatically be set
to -1.
User inputs -1 in num1. The value of num2 should automatically be set
to 1.
How can we achieve this when using AngularJS 1.x?
There are a couple ways to do this:
In your controller put a watch on the values of num1 and num2. It might look something like this (assume $scope is injected in your controller)
Example HTML
<input type="number" ng-model="num1">
<input type="number" ng-model="num2">
Example JS
$scope.$watch('num1', function(newVal){
$scope.num2 = - newVal;
}
$scope.$watch('num2', function(newVal){
$scope.num1 = - newVal;
}
This way is preferable if you intend to reuse the controller with several views or there is an inherent relationships between the model data (num1 and num2). The watches will fire if the number are change for any reason (other bindings, explicit changes in javascript, etc).
In on your input have an ng-change set the value in an angular expression
Example HTML
<input type="number" ng-model="num1" ng-change="num2=-num1">
<input type="number" ng-model="num2" ng-change="num1=-num2">
This way is preferable if you only are only care about one number, or this logic only belongs in the view. It can also be more efficient, since it hooks the change event instead of doing and equivalence check every digest cycle. However, this means that if one of the number is changed though any means other than changing that input box the change will not be reflected. Credit to Manatax for pointing most of the benefits out in the comments below.