Input field not updating with ng-keydown event - javascript

In this piece of code I want to add validation to input field, if the value is 0 but I don't know why I am not able to update and enter new value in the input field. Simply I am not able to change the input field value.
Value remain same if I delete existing value and add something in existing value.
Here is HTML code:
<input ng-model="lineitemDetailsCtrlAs.lineItems.orderedQuantity" type="text" class="col-md-6 text-right panel-row-spacing"
ng-keydown="valueChanged($event)" required
/>
and angular code is:
$scope.valueChanged = function (event) {
var quantityRequire={};
if (event.keyCode === 48 || lineitemDetailsCtrlAs.lineItems.orderedQuantity == 0) {
quantityRequire = {
"messageId": "ORDERED_QUANTITY",
"params": [],
"severity": "ERROR"
};
lineitemDetailsCtrlAs.errorMessages.push(quantityRequire);
}
else{
event.preventDefault();
}
};

you are stopping event by "event.preventDefault();", because only keycode 48 (only number 0) is acceptable others keyevents are falling down on else condition and stop updating input value.

I think Rameshkumar Arumugam is right about what's wrong with your code, below is a working example
angular.module("myApp", [])
.controller("MainCtrl", function($scope) {
$scope.lineItems = {
orderedQuantity: 12
};
$scope.errorMessages = [];
$scope.valueChanged = function(event) {
var quantityRequire = {};
if (event.keyCode === 48 || $scope.lineItems.orderedQuantity == 0) {
quantityRequire = {
"messageId": "ORDERED_QUANTITY",
"params": [],
"severity": "ERROR"
};
alert(quantityRequire["messageId"]);
$scope.errorMessages.push(quantityRequire);
}
};
})
<div ng-app="myApp">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-controller="MainCtrl">
<input ng-model="lineitemDetailsCtrlAs.lineItems.orderedQuantity" type="text" class="col-md-6 text-right panel-row-spacing" ng-keydown="valueChanged($event)" required />
</div>
</div>

Related

tab key focus next empty input in a grid

What I'm trying to achieve is that when tab key is pressed, the cursor will be focused on the next empty input in a grid component. Input field that has value will be skipped. If the cursor currently is in input field 2, and input field 3 has value, when tab is pressed, the cursor will jump to input field 4. This is to speed up the form entry time.
Below is the html grid component that I have created
<div class="col-md-6" id="dcNonRetainValue">
<fieldset class="ES-border frame-height-collapsed">
<legend class="ES-border">{{ 'Data Collection' }} </legend>
<collect-paged-data data="ui.dataCollectionItems" currentPage="ui.dataCollectionItemsCurrentPage" pageSize="ui.dataCollectionPageSize">
</collect-paged-data>
</fieldset>
Trying to focus next input element with js.
setTimeout(function () {
$('#dcNonRetainValue *:input:empty').focus();
}, 50);
It does not seem to work correctly. Any feedback is appreciated.
You can use filter function to select all the empty inputs. Then use eq function to select first input and use focus function. You can do like below Example:
$(document).ready(function() {
$('input').on( 'keydown', function( e ) {
if( e.keyCode == 9 ) {
const allEmptyInput = $('input').filter(function() {
return $(this).val() === "";
});
// Return if there is no Empty Input
if (allEmptyInput.length === 0) return;
e.preventDefault();
const currentInput = $(e.target);
const nextAllEmptyInput = currentInput.nextAll('input').filter(function() {
return $(this).val() === "";
});
// Focus on first input if last is focus
if (nextAllEmptyInput.length === 0) {
allEmptyInput.eq(0).focus();
return;
}
const firstEmptyInput = nextAllEmptyInput.eq(0);
firstEmptyInput.focus();
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<label>First Input</label><br/>
<input type="text"/>
<br/>
<label>Second Input</label><br/>
<input type="text"/>
<br/>
<label>Third Input</label><br/>
<input type="text"/>
Using id will only give you the first element with that id. Use class instead.

Form Validation (Angular)

I am using angular reactive form and making distance input fields which has two input boxes called From and To.
HTML:
<form [formGroup]="form">
<button (click)="addRow()">Add</button>
<div formArrayName="distance">
<div
*ngFor="let item of form.get('distance').controls; let i = index"
[formGroupName]="i"
style="display: flex"
>
<input type="number" placeholder="From" formControlName="from" />
<div><input type="number" placeholder="To" formControlName="to" /></div>
</div>
</div>
<br /><br />
<button type="submit" [disabled]="!form.valid">Submit</button>
</form>
TypeScript:
ngOnInit() {
this.form = this.fb.group({
distance: this.fb.array([]),
});
this.addRow()
}
addRow() {
const control = this.form.controls.distance as FormArray;
control.push(this.fb.group({
from: ['',Validators.required],
to: ['',Validators.required]
}));
}
Here you could able to see the two input boxes in default as from and to.
There is an add button at top and upon clicking add button the rows with same input fields gets added and forms as array.
Here i am in the need of restriction that user should not allowed to enter the previous row to value and also not the value lesser than that.
For eg.,
In the first row, if user enters the below values like 0 and 5 for from and to respectively,
"distance": [
{
"from": 0,
"to": 5
}
]
After clicking add and in second row in From input box user needs to be restricted on adding the values of 5 and lesser than that (which means those values were already entered).
So like this is invalid,
{
"distance": [
{
"from": 0,
"to": 5
},
{
"from": 5,
"to": 10
}
]
}
Here "from": 5, or "from": 4(or)3(or)2(or)1, anything is invalid in second row..
Only 6 and greater than 6 is valid.
Likewise for each row it needs to check for previous row to value and validation needs to be done.
Kindly help me to achieve this type of validation of restricting the user not to enter previous row to value (or) lesser than that in current row's from value.
Working Example: https://stackblitz.com/edit/disable-group-control-value-on-another-control-value-for-j58atx
Edit:
Tried with input change like,
<input type="number" (input)="onInputChange($event.target.value)" placeholder="From" formControlName="from">
in the link https://stackblitz.com/edit/disable-group-control-value-on-another-control-value-for-ymfpkj but not sure whether i am going correct..
Kindly change if this procedure is wrong.
Finally I decided divide the two conditions. see new stackblitz
ngOnInit() {
this.form = this.fb.group({
distance: this.fb.array([], this.distanceValidator()),
});
this.addRow()
}
addRow() {
const control = this.form.controls.distance as FormArray;
control.push(this.fb.group({
from: ['', Validators.required],
to: ['', Validators.required]
}, { validator: this.greaterValidator() }));
}
setDefault() {
const control = this.form.controls.distance as FormArray;
this.default.forEach(data => {
control.push(this.fb.group({
from: [data.from, Validators.required],
to: [data.to, Validators.required]
}, { validator: this.greaterValidator() }));
});
}
greaterValidator() {
return (fa: FormGroup) => {
return fa.value.to && fa.value.to < fa.value.from ? { error: "from greater than to" } : null;
}
}
distanceValidator() {
return (fa: FormArray) => {
let ok = true;
for (let i = 1; i < fa.value.length; i++) {
ok = (!fa.value[i].from || fa.value[i].from > fa.value[i - 1].to) && (!fa.value[i].to || fa.value[i].to > fa.value[i - 1].from);
if (!ok)
return { error: "from/to yet included", index: i }
}
return null
}
}
And the .html
<form [formGroup]="form">
<button (click)="addRow()">Add</button>
<div formArrayName="distance" >
<div
*ngFor="let item of form.get('distance').controls; let i = index"
[formGroupName]="i"
style="display: flex">
<input type="number"
placeholder="From"
formControlName="from">
<div>
<input type="number"
placeholder="To"
formControlName="to">
</div>
<span *ngIf="item.errors">*</span>
<span *ngIf="form.get('distance')?.errors && form.get('distance')?.errors.index==i">**</span>
</div>
</div>
<div *ngIf="form.get('distance')?.errors">{{form.get('distance')?.errors.error}}</div>
<br><br>
<button type="submit" [disabled]="!form.valid"> Submit </button>
</form>
<button (click)="setDefault()"> Set Default Values </button>
Update:Actually only when find an error not control more.
Moreover, if the from and to before is empty, don't give an error. For avoid this we can "convert" to number, writing
let ok = (!fa.value[i].from || fa.value[i].from > +fa.value[i - 1].to)
&& (!fa.value[i].to || fa.value[i].to > +fa.value[i - 1].from);
(see the "+" in +fa.value[i-1].to and +fa.value[i-1].from
Well, As we decided the error we send, imagine you has 6 rows and the line in position 0, in position 3 and in position 4 (0 is the first row) send a error like
{error:"there are errors",indexError:",0,3,4,"}
This allow inside the *ngFor write some like
<span *ngIf="form.get('distance')?.errors &&
form.get('distance')?.errors.indexError.indexOf(','+i+',')>=0">
**
</span>
Well, our distanceValidator becomes like
distanceValidator() {
return (fa: FormArray) => {
let indexError:string="";
for (let i = 1; i < fa.value.length; i++) {
let ok = (!fa.value[i].from || fa.value[i].from > +fa.value[i - 1].to) && (!fa.value[i].to || fa.value[i].to > +fa.value[i - 1].from);
if (!ok)
indexError+=','+i;
}
return indexError?{error:"there are errors",indexError:indexError+','}:null
}
Someone can think that it's better return an array of errors, but this not allowed as to know in a easy way the row with errors. some like errors.find(x=>x.id==i) not work because we can not use find in a interpolation.
It's true that only compare one row with the inmediaty before. It's possible to check over all before -using a for (let j=i-1;j>0;j++){ok=ok && ...}-, but I think it's not necesary and we must be stingy in code. Remember that the function distanceValidator are executed several times
See another stackblitz
Just use a customValidation (I choose the validation in the same component
ngOnInit() {
this.form = this.fb.group({
distance: this.fb.array([], this.distanceValidator()),
});
this.addRow()
}
distanceValidator() {
return (fa: FormArray) => {
let ok = true;
let ok2 = fa.value.length ? (!fa.value[0].to || !fa.value[0].from) || fa.value[0].to > fa.value[0].from : true;
if (!ok2)
return { error: "from greater than to" }
for (let i = 1; i < fa.value.length; i++) {
if (fa.value[i].from && fa.value[i].to )
{
ok = (fa.value[i].from > fa.value[i - 1].to || fa.value[i].to < fa.value[i - 1].from);
ok2 = (fa.value[i].to > fa.value[i].from);
if (!ok)
return { error: "from/to yet included" }
if (!ok2)
return { error: "from greater than to" }
}
}
return ok && ok2 ? null : !ok?{ error: "from yet included" }:{ error: "from greater than to" }
}
}
You can see the error like another
<div *ngIf="form.get('distance')?.errors">
{{form.get('distance')?.errors.error}}
</div>
see [stackblitz forked][1]

Filter input text to enter only number and not even decimal

My goal is for the user to only enter number from [0-9] not even decimal is allowed
How to do that?
The code
<b-input expanded
type="number"
v-model="amount"
#input="updateValue()"
placeholder="{{ amount }}">
</b-input>
The <b-input> is from buefy https://buefy.github.io/documentation/input/
From the Beufy doc, I get that <b-input> is essentially an extension of native <input> field so it accepts attribute that the native input would accept.
As of now, it is not possible to completely filter out specific characters using pure HTML attributes like pattern="\d+".
What you can do is to use a "keydown" event listener to filter out these characters using native event.preventDefault() by respective keys. Of course, we could use the native <input type="number"> to help in general.
const app = new Vue({
el: '#app',
methods: {
filterKey(e){
const key = e.key;
// If is '.' key, stop it
if (key === '.')
return e.preventDefault();
// OPTIONAL
// If is 'e' key, stop it
if (key === 'e')
return e.preventDefault();
},
// This can also prevent copy + paste invalid character
filterInput(e){
e.target.value = e.target.value.replace(/[^0-9]+/g, '');
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input
type="number"
step="1"
min="0"
#keydown="filterKey"
// OR
#input="filterInput"
>
</div>
I have just started using vue js so i don't have much knowledge but i think you can add an event listener and use reg ex in your function
<input type="number" #input="checknum">
export default{
methods: {
checknum: function (event) {
this.value = this.value.replace(/[^0-9]/g, '');
}
}
}
You can call a function on keyup event and check all the non-numeric characters and remove from the value.
For Example:
// In template add this line
<input type="text" v-model="inputNumber" #keyup="onlyNumeric" />
// Define inputNumber in data.
// In Methods add onlyNumeric function
onlyNumeric() {
this.inputNumber = this.inputNumber.replace(/[^0-9]/g, '');
}
Template
<input type="number"
v-model="amount"
#input="updateValue"
placeholder="amount" />
Script
<script>
export default {
data() {
return {
amount: null,
}
},
methods: {
updateValue(e) {
e.target.value = e.target.value.replace(/[^0-9]+/g, '')
}
}
}
</script>
I don't know sometime people doesn't understand, what needed is buefy input which type is text, because on default it must empty string, but when input value its only accept number, this is my answer:
Input tag:
<b-input
type="text"
v-model="onlyNumber"
:placeholder="'Input only number example: 345678'"
#keypress.native="isNumber($event)"
/>
script:
data() {
return {
onlyNumber: '',
};
},
methods: {
isNumber(evt) {
evt = (evt) ? evt : window.event;
var charCode = (evt.which) ? evt.which : evt.keyCode;
if (charCode > 31 && (charCode < 48 || charCode > 57)) {
evt.preventDefault();
}
return true;
},
},
Pros : default is empty string, but only accept number
Const : accepted number will settled as string of number example : "333214234", just convert to number if you have need on number form
Sample code
$('#numberfield').on('input', function(event) {
console.log(parseInt(event.target.value))
event.target.value = parseInt(event.target.value);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="numberfield" type="number" />
If you are using Vuetifyjs, you could use rules directive as below:
Template
<v-textfield type="number" v-model="amount"
:rules="theForm.myRules" placeholder="{{amount}}"> </v-textfield>
Script
export default {
data() {
return {
amount: null,
theForm: {
myRules: [
v => /[^0-9]/.test(v) || 'Input Invalid'
]
}
};
}
};

How can I fire the Tab keypress when the Enter key is pressed?

This is what I have and it works fine.
But I want to return the tab key instead of just nothing happening.
$(document).on("keypress", ":input:not(textarea):not([type=submit])", function(event) {
if (event.keyCode == 13) {
event.preventDefault();
}
});
What I want is:
if (event.keyCode == 13) {
event.preventDefault();
return event.keyCode = 9; <<= or something similar and simple
}
This seems like a duplicate but I don't see anything to substitute enter for tab code... Tab key already knows to skip hidden and use tab orders.
I suspect what you really want is to move to the next field in the form.
If so, you can easily find the next form field and use .focus() to focus it. For instance:
var fields = $(this).closest("form").find("input, textarea");
var index = fields.index(this) + 1;
fields.eq(
fields.length <= index
? 0
: index
).focus();
Example:
$(document).on("keypress", ":input:not(textarea):not([type=submit])", function(event) {
if (event.keyCode == 13) {
event.preventDefault();
var fields = $(this).closest("form").find("input, textarea");
var index = fields.index(this) + 1;
fields.eq(
fields.length <= index
? 0
: index
).focus();
}
});
<form>
<div>
<label>
Field 1:
<input type="text">
</label>
</div>
<div>
<label>
Field 2:
<input type="text">
</label>
</div>
<div>
<label>
Field 3:
<input type="text">
</label>
</div>
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
If you're using tabindex to put fields in a different order than document order, you'll have to do a bit more work, basically sorting the result of find on tabindex and working from there. But that should get you going the right way.
I got the accepted answer to work for me, but I needed to figure out where to stick the code exactly:
$(document).on("keypress", ":input:not(textarea):not([type=submit])", function(event) {
if (event.keyCode == 13) {
var fields = $(this).closest("form").find("input, textarea");
var index = fields.index(this) + 1;
fields.eq(
fields.length <= index
? 0
: index
).focus();
event.preventDefault();
}
});

inject HTML when enter key pressed on input

I have an input field and when people press enter I'd like the field to be emptied and its value printed below with an 'x' icon to delete it afterwards just like the 'search' field on angel.co: https://angel.co/jobs
Here is my HTML:
<form ng-submit="searchAds(searchInput)">
<input id="search-field" type="search" placeholder="Start typing your search..." ng-change="searchRequest()" ng-model="searchInput"/>
</form>
<div id="search-tags"></div>
And my JS in my controller:
$scope.searchAds = function(item){
if (item === "") return;
$scope.searchInput = "";
$('#search-tags').append('<div ng-show="showDetails">' + item + '<div ng-click="showDetails = ! showDetails"> (my DVG icon here) </div></div>');
}
I have 2 problems here:
1 - I believe the code is not compiled when printed so the 'ng-show' and 'ng-click' are so working - how can I make this work?
2 - How can I make sure that when there are several tags, when clicking on my delete icon it hide only this specific tag?
Many thanks
Why not angular instead of jQuery?
You can add a directive to manage the "enter" key:
angular.module('yourModule').directive(
'ngEnter',
function () {
'use strict';
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
scope.$apply(function (){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
And then change a bit your code:
<form ng-submit="searchAds(searchInput)">
<input type="search" placeholder="Start typing your search..." ng-enter="add(searchInput)" ng-model="searchInput"/>
</form>
<div ng-repeat="tag in tags">
<div>{{tag}}<div ng-click="delete(tag)">(my DVG icon here)</div></div>
</div>
Your controller:
$scope.add = function(item) {
$scope.tags.push(item);
$scope.searchInput = "";
}
$scope.delete = function(item) {
var index = $scope.tags.indexOf(item);
$scope.tags.splice(index, 1);
}

Categories