I am trying to add ng-change to input which runs datetimepicker but it triggers on change function on page load. below is the code
<input datetimepicker ng-model="startDate"
ng-change="testFunction()"
options="cOptions"
placeholder="Select Date"/>
any idea how to prevent this ?
edit:
$scope.testFunction = testFunction;
function testFunction(){
console.log('on change')
}
loadData();
function loadData(){
//this is where startDate is set
}
Hi the change in input field where you're using the directive is triggered by the plugin, it's explicitly setting it to null. So you can have the validation like until input field in filled don't execute logic you written on ng-change function. There're two ways to do that:
<div class="input-group">
<input class="form-control" datetimepicker ng-model="vm.date" options="vm.options"
ng-change="vm.date && vm.changed()"/>
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar">
</span></span>
</div>
Now here ng-change will not trigger until something you inserted in the field. So onload it'll not triggered.
Other way is like instead of anding this scope variable with its ng-change function, you can check in that function if the value is null or not. If it's non-null then only run the implementation written on ng-change.
Here's plunker showing both conditions:
http://plnkr.co/edit/uCf2vpmoYIYzxTjmFVcX?p=preview
Update: If you're editing value onload but still you don't want to execute implementation you written on ng-change then have separate variable, toggle its value on first ng-change, which's triggering automatically because of directive, next change onwards your ng-change function will run.
http://plnkr.co/edit/FogYzmDBd1gIolvjP7yl?p=preview
Related
I've got a field for a product that its quantity is dependant on another product's quantity (cant be less than 70%, or more than 100%). Thing is, it evaluates it so quiclky that if the main field is '100', I cant enter 75 on the other field, because I first need to enter the '7', and my code considers it less than 70% and instantly changes it to the 70% value.
I've already tried using a self-made 'sleep' function, that makes a promise take some time to resolve.
setInterval and setTimeout also do not work as I intend for some reason (only evaluates the dependent field when I press enter, and it is not after the stablished time). This is not consistent with the rest of the table, so it is not a suitable solution.
This is the angular bit that controls this input
<div class="input-field">
<input class="input" type="number" [integerInput] ="true"
[disabled] ="item.deshabilitado( ) || !editable"
[(ngModel)] ="item.cantidad"
[ngModelOptions]="{standalone: true}"
(keyup) ="setCantidad( item, $event.target.value )"
max="9999" min="1" value="1" >
</div>
Sadly I cant get a minimal and working example. I need the dependent field to be able to evaluate its value automatically (without pressing enter or clicking on another field) without automatically correcting my input when I press only one character.
Use blur() method instead of keyup(). I guess you are validating the input with keyup() and each time you enter value it validates. For instance you are trying to enter 70 but when you enter first character, 7 it is invalid. The blur() fires your method and validates your input when you are done with inputting value.
<div class="input-field">
<input class="input" type="number" [integerInput]="true"
[disabled]="item.deshabilitado( ) || !editable"
[(ngModel)]="item.cantidad"
[ngModelOptions]="{standalone: true}"
(focusout)="setCantidad( item, $event.target.value )"
max="9999" min="1" value="1" >
</div>
In addition, you can use keyup.enter if a user is done with inputting value and presses enter. The value updates when the enter key is pressed or clicked somewhere else.
UPDATE:
I was able to solve this and get it to work like I intended at the beginning. The resulting code for the field I tried to validate would be
debounce (afterValueChanged)="setCantidad( item )"
It behaves in a way that does not need me to click outside the field for it to start validating, instead of the (blur) or (focusout)
Try to use the debounce function
Import debounceTime from rxjs and use it to add some delay :)
Check out this example
In the other field where you are trying to enter 75, you can add an ngModelOptions configuration to update only on blur.
[ngModelOptions]="{ updateOn: 'blur' }"
By default it updates on 'change', which explains the current behavior.
Update
You could also debounce the input using RXJS. This is probably closer to what you were trying to do with setInterval / setTimeout. This is also a use case where Reactive Forms really shines over Template Driven Forms imo, since you'll need to use RXJS operators.
For reactive driven forms, you just pipe an operator before subscribing to the valueChanges observable of the formControl
this.myInput.valueChanges
.pipe(
debounceTime(1000), // add 1 second of delay
distinctUntilChanged() // optional but recommended - only trigger for new values
)
.subscribe(val=> {
console.log('value', val);
});
It is possible to accomplish the same behavior in template driven forms but there is some setup involved. See this SO question/answer
As per the information given, you might want to debounce your function call.
Debounced functions do not execute when invoked, they wait for a pause of invocations over a configurable duration before executing; each new invocation restarts the timer.
<div class="input-field">
<input class="input" type="number" [integerInput] ="true"
[disabled] ="item.deshabilitado( ) || !editable"
[ngModel] ="item.cantidad"
[ngModelOptions]="{standalone: true}"
(keyup) ="setCantidad( item, $event.target.value )"
max="9999" min="1" value="1" >
</div>
In your component class:
timer;
setCantidad(item,value){
if(this.timer){
clearTimeout(this.timer);
}
this.timer = setTimeout(() => {
this.item.cantidad = value;
//perform any operations here
console.log(item, value);
},1000);
}
This will wait for the user to stop typing and execute the operation after the specified time in the timeout.
Note: One additional change, if you want to render the value in the same input field where you are typing, consider changing the [(ngModel)] -> [ngModel].
This will just perform a property binding and not event binding.
Demo stackblitz link : https://stackblitz.com/edit/angular-cu9gss
I have applied ng-model and ng-change directives on input type text, that shows color in hexa that can be changed from color panel as shown.
<input type="text" ng-model="colors.primary_color"
ng-change="colorChanged()" class="input-control"
placeholder="Primary Color"
color-picker
color-picker-model="primaryColorModel"
color-picker-position="{{colorPickerPosition}}">
<button class="btn-sidebar">
<svg width="20px" height="21px">
<path ng-style="{fill: primaryColorModel}" d="M10.000,3.429 C5.865,3.429 2.500,6.793 2.500,10.928 C2.500,15.063 5.865,18.427 10.000,18.427 C10.000,14.550 10.000,7.089 10.000,3.429 M10.000,0.929 C15.523,0.929 20.000,5.406 20.000,10.928 C20.000,16.450 15.523,20.927 10.000,20.927 C4.477,20.927 -0.000,16.450 -0.000,10.928 C-0.000,5.406 4.477,0.929 10.000,0.929 L10.000,0.929 Z"
/>
</svg>
</button>
Now when I open color panel and change colors, new hexa code shows up in input type text, but colorChanged function doesn't trigger. It only triggers when I click on text box and write some thing.
I want it to be triggerd when I remove any character or value is changed from color panel.
I have tried with $watch like so
$scope.colors = {
primary_color: "#008fff",
secondary_color:"#008fff",
text_color: "#008fff"
}
$scope.$watch('colors', function (nval, oval) {
console.log(nval);
});
$scope.colorChanged = function() {
$rootScope.$broadcast('color-change', {colors: $scope.colors});
}
But it doesn't trigger either.
If I use $apply, it says you are already in digestive cycle.
If you place the relevant markup inside a <form> element and give the <input> a name :
<form name="form">
<input name="primary_color" type="text" ng-model="colors.primary_color"
ng-change="colorChanged()" class="input-control"
placeholder="Primary Color"
color-picker color-picker-model="primaryColorModel"
color-picker-position="{{colorPickerPosition}}">
...
</form>
Then you can programmatically trigger the ng-change directive by using $setViewValue() with no params :
$scope.form.primary_color.$setViewValue()
Will trigger ng-change as the ng-model was changed without actually changing it.
demo -> http://plnkr.co/edit/PmthIfblkPkbKgRInLBc?p=preview
If you are using this plugin, then the variable you specify in color-picker-model attribute is treated as the binding variable for the color picker. So to detect changes to the color picked, you can watch that variable. In your case:
$scope.$watch('primaryColorModel', function(nval, oval) {
//your code here
});
I can't tell which plugin you used for, but regardless unless it was built with angular you'll likely have to wire up a callback that runs a $rootScope.$apply(). The reason being is that the piece of code is happening outside angulars eco-system and it needs to be notified to re-run. See my similar answer here: AngularJS: ng-repeat list is not updated when a model element is spliced from the model array
I am developing an application in Angularjs. I am using ng-keypress event in input type=text. While typing value in text I'm getting wrong values in the keypress function. For example, the first time if I type "1" I am getting undefined. Second time, typing any other value gives the first value
<input ng-model="NodeId_1" type="text" ng-keypress="getValue()"/>
var angularapp = angular.module('nameapp', []);
angularapp.controller('NameCtrl', function ($scope) {
$scope.getValue = function () {
alert($scope.NodeId_1);//Here first time undefined is coming and second what ever we enter first value will come
}
}
)
You'll want to use ng-keyup instead.
ng-keypress happens as the key is pressed, and BEFORE the value populates the input. This is why you're not getting any value on the first keypress, but on subsequent presses you will.
Use ng-keyup and your problem is solved, as it happens once the value has already populated the input.
<input ng-model="NodeId_1" type="text" ng-keyup="getValue()" />
ng-keypress is working as intended, but it is not the directive applicable to your requirements.
Working plunkr: http://plnkr.co/edit/OHWDZo68siDlcrXnLyzJ?p=preview
The keypress event is fired when a key is pressed down and that key
normally produces a character value (use input instead).
https://developer.mozilla.org/en-US/docs/Web/Events/keypress
So neither the input field value nor the scope value(apply/digest loop etc.) will reflect the expected input value.
Solution is depending on your requirements. Here are some:
1) Use another event on the inputfield: change, keyup, ...
2) Use the $event object in your listener method:
<input ng-model="NodeId_1" type="text" ng-keypress="getValue($event)"/>
$scope.getValue = function (event) {
console.log(event)
}
3) Create a watcher for your NodeId_1 value within your scope:
$scope.$watch('NodeId_1', function(newVal) {
...
});
The watcher function work for me, I attached my example
$scope.$watch('itemm.montoAmodificar', function (newValue) {
$scope.fnActualizarNuevoSaldoDependencia(parseFloat(newValue));
});
The html code is the following
<input ng-model="itemm.montoAmodificar" my-focus class="form-control" type="text" placeholder="Ingrese el monto" ng-keypress="fnActualizarNuevoSaldoDependencia($event);" />
I have an input file element within an angular view/form. I'm using ng-upload like this:
<input id="img" type="file" name="image" onchange="angular.element(this).scope().setFile(this)">
<input id="imgname" type="hidden" value=""></div>
Since I can't tell angular to listen for changes on input[type="file"] element, I've created the method that updates the hidden input that just holds the current filename. That way I can run my validator on the second field.
Another field I have has some sort of validator, like this:
<input ng-model="other" ng-change="chg()"/>
Now, the trouble is, if I trigger the validator, $scope.chg(), from setFile() method, I think I don't get the same scope - chg() runs, but it's as if the validator is in another scope and doesn't set my actual submit button to enabled. I tried logging from the chg() - it shows different scope then what I actually see on the view.
And if I later trigger the ng-change by changing the regular input field ("other"), it picks up the changes, or actually, it sets the submit button state correctly.
Now, I suspect this has to do with me calling the angular.element(this).scope().setFile(this) from my form instead of direct, $scope-bound method. But I cannot call $scope-bound method because it does not trigger - if I understood correctly, that's due to Angular not (yet) working with input type=file fields.
What can I do here?
I simply want to detect if there is a file or not so I can enable/disable the submit button appropriately.
I used followed flow that works for me:
<input type="file"
ng-model="upFile"
onchange="angular.element(this).scope().setFileEventListener(this)"
/>
From controller:
$scope.setFileEventListener = function(element) {
$scope.uploadedFile = element.files[0];
if ($scope.uploadedFile) {
$scope.$apply(function() {
$scope.upload_button_state = true;
});
}
}
Hope it will help.
I am trying to do some experiment. What I want to happen is that everytime the user types in something in the textbox, it will be displayed in a dialog box. I used the onchange event property to make it happen but it doesn't work. I still need to press the submit button to make it work. I read about AJAX and I am thinking to learn about this. Do I still need AJAX to make it work or is simple JavaScript enough? Please help.
index.php
<script type="text/javascript" src="javascript.js"> </script>
<form action="index.php" method="get">
Integer 1: <input type="text" id="num1" name="num1" onchange="checkInput('num1');" /> <br />
Integer 2: <input type="text" id="num2" name="num2" onchange="checkInput('num2');" /> <br />
<input type="submit" value="Compute" />
</form>
javascript.js
function checkInput(textbox) {
var textInput = document.getElementById(textbox).value;
alert(textInput);
}
onchange is only triggered when the control is blurred. Try onkeypress instead.
Use .on('input'... to monitor every change to an input (paste, keyup, etc) from jQuery 1.7 and above.
For static and dynamic inputs:
$(document).on('input', '.my-class', function(){
alert('Input changed');
});
For static inputs only:
$('.my-class').on('input', function(){
alert('Input changed');
});
JSFiddle with static/dynamic example: https://jsfiddle.net/op0zqrgy/7/
HTML5 defines an oninput event to catch all direct changes. it works for me.
Checking for keystrokes is only a partial solution, because it's possible to change the contents of an input field using mouse clicks. If you right-click into a text field you'll have cut and paste options that you can use to change the value without making a keystroke. Likewise, if autocomplete is enabled then you can left-click into a field and get a dropdown of previously entered text, and you can select from among your choices using a mouse click. Keystroke trapping will not detect either of these types of changes.
Sadly, there is no "onchange" event that reports changes immediately, at least as far as I know. But there is a solution that works for all cases: set up a timing event using setInterval().
Let's say that your input field has an id and name of "city":
<input type="text" name="city" id="city" />
Have a global variable named "city":
var city = "";
Add this to your page initialization:
setInterval(lookForCityChange, 100);
Then define a lookForCityChange() function:
function lookForCityChange()
{
var newCity = document.getElementById("city").value;
if (newCity != city) {
city = newCity;
doSomething(city); // do whatever you need to do
}
}
In this example, the value of "city" is checked every 100 milliseconds, which you can adjust according to your needs. If you like, use an anonymous function instead of defining lookForCityChange(). Be aware that your code or even the browser might provide an initial value for the input field so you might be notified of a "change" before the user does anything; adjust your code as necessary.
If the idea of a timing event going off every tenth of a second seems ungainly, you can initiate the timer when the input field receives the focus and terminate it (with clearInterval()) upon a blur. I don't think it's possible to change the value of an input field without its receiving the focus, so turning the timer on and off in this fashion should be safe.
onchange only occurs when the change to the input element is committed by the user, most of the time this is when the element loses focus.
if you want your function to fire everytime the element value changes you should use the oninput event - this is better than the key up/down events as the value can be changed with the user's mouse ie pasted in, or auto-fill etc
Read more about the change event here
Read more about the input event here
use following events instead of "onchange"
- onkeyup(event)
- onkeydown(event)
- onkeypress(event)
Firstly, what 'doesn't work'? Do you not see the alert?
Also, Your code could be simplified to this
<input type="text" id="num1" name="num1" onkeydown="checkInput(this);" /> <br />
function checkInput(obj) {
alert(obj.value);
}
I encountered issues where Safari wasn't firing "onchange" events on a text input field. I used a jQuery 1.7.2 "change" event and it didn't work either. I ended up using ZURB's textchange event. It works with mouseevents and can fire without leaving the field:
http://www.zurb.com/playground/jquery-text-change-custom-event
$('.inputClassToBind').bind('textchange', function (event, previousText) {
alert($(this).attr('id'));
});
A couple of comments that IMO are important:
input elements not not emitting 'change' event until USER action ENTER or blur await IS the correct behavior.
The event you want to use is "input" ("oninput"). Here is well demonstrated the different between the two: https://javascript.info/events-change-input
The two events signal two different user gestures/moments ("input" event means user is writing or navigating a select list options, but still didn't confirm the change. "change" means user did changed the value (with an enter or blur our)
Listening for key events like many here recommended is a bad practice in this case. (like people modifying the default behavior of ENTER on inputs)...
jQuery has nothing to do with this. This is all in HTML standard.
If you have problems understanding WHY this is the correct behavior, perhaps is helpful, as experiment, use your text editor or browser without a mouse/pad, just a keyboard.
My two cents.
onkeyup worked for me. onkeypress doesn't trigger when pressing back space.
It is better to use onchange(event) with <select>.
With <input> you can use below event:
- onkeyup(event)
- onkeydown(event)
- onkeypress(event)
when we use onchange while you are typing in input field – there’s no event. But when you move the focus somewhere else, for instance, click on a button – there will be a change event
you can use oninput
The oninput event triggers every time after a value is modified by the user.Unlike keyboard events, it triggers on any value change, even those that does not involve keyboard actions: pasting with a mouse or using speech recognition to dictate the text.
<input type="text" id="input"> oninput: <span id="result"></span>
<script>
input.oninput = function() {
console.log(input.value);
};
</script>
If we want to handle every modification of an <input> then this event is the best choice.
I have been facing the same issue until I figured out how to do it. You can utilize a React hook, useEffect, to write a JS function that will trigger after React rendering.
useEffect(()=>{
document.title='fix onChange with onkeyup';
const box = document.getElementById('changeBox');
box.onkeyup = function () {
console.log(box.value);
}
},[]);
Note onchange is not fired when the value of an input is changed. It is only changed when the input’s value is changed and then the input is blurred. What you’ll need to do is capture the keypress event when fired in the given input and that's why we have used onkeyup menthod.
In the functional component where you have the <Input/> for the <form/>write this
<form onSubmit={handleLogin} method='POST'>
<input
aria-label= 'Enter Email Address'
type='text'
placeholder='Email Address'
className='text-sm text-gray-base w-full mr-3 py-5 px-4 h-2 border border-gray-primary rounded mb-2'
id='changeBox'
/>
</form>
Resulting Image :
Console Image
try onpropertychange.
it only works for IE.