I have a problem with the javascript code I am trying to work with. I am trying to call a function to set an event handler and within that event handler also remove it when the event is called. In this particular instance I am trying to ADD an event handler whenever I want input, then a callback is passed to the function and the code is run when the input is ready. Also at this stage I try to remove it so the callback doesn't get triggered more than once, but there seems to be a problem with this. Here is the code:
this.validateInput = function(NaN, callback) {
// Wait for the user to click submit or press
// enter, then if the input is a valid number
// return true. If it is not valid return false
$(document).keydown(function(e) {
// If the enter key is pressed, if the box is focused and if
if (e.which == 13 && $("#inputBox").is(":focus")) {
// Print the user's input regardless of whether it is a
// number or not.
var newOutput = $("#inputBox").val()
$("#output").append(newOutput + "<br>");
// If the user wants the input to be a number then
// the program checks if the input is not numerical.
if (NaN && !isNaN($("#inputBox").val())) {
// Get input from screen
var newInput = $("#inputBox").val();
// Remove this handler
this.removeKeyhandler();
// Call the code passed to the function
callback(newInput);
// Return from the function.
return;
// This checks if the user wants non-number input
// and runs the following code IF the input is not numerical
} else if (!NaN && isNaN($("#inputBox").val())) {
// Get input from screen
var newInput = $("#inputBox").val();
// Remove this handler
this.removeKeyhandler();
// Call the code passed to the function
callback(newInput);
// Return from the function
return;
}
}
});
}
For reference, #inputBox is an input box, #output is the <div> I am trying to output to, and removeKeyHandler() simply contains the code $(document).off("keydown", document);. If you want to see the full file/project, it is here.
The only thing that seems not to be working is the event handler not removing, it keeps going as many times as you add input. If you download the project and open up index.html you should see what I mean.
I see your problem.. your 'this' you refer to in your code is not in the right scope..
simply do this:
function display() {
var ref = this;
}
Now replace these:
this.removeKeyhandler();
with this:
ref.removeKeyhandler();
Also in your removing function change it to this:
$(document).off("keydown");
good luck!
Related
I realise similar questions have been asked before but still dont understand what is happening with my code. I want to access the variable seq outside of the jQuery function after the user has inputed their sequence into the textarea. The console.log inside the jquesry function returns the inputed sequence but the console.log outside of the jQuery function(where I eventually want to put some other code to analyse the sequence) runs before the jquery function and returns an empty string. How can I make the code that uses the var seq only run after the submit button is clicked? Thanks!
var seq = "";
$("#subSeqType").on("click", function() {
if ($("#proteinButton").is(":checked")) {
$("#newTextArea").append("<textarea name = 'sequence' rows = '10' cols = '80' placeholder = 'Enter Protein Sequence here' > < /textarea><br>");
}
if ($("#dnaButton").is(":checked")) {
$("#newTextArea").append("<textarea name = 'sequence' rows = '10' cols = '80' placeholder = 'Enter DNA Sequence here' > < /textarea><br>");
}
$("#subSeqType").remove();
$("#newTextArea").append("<input id = 'subSeq' type='Submit'>");
$("#subSeq").on("click", function() {
seq = $("textarea:input[name=sequence]").val();
console.log(seq);
});
});
console.log("The sequence " + seq);
Im gonna try to explain this but you should read a little about how a code works and runs.
Lets state to types of code statement:
Run time code
Run time code is every line of code that run when it is loaded by the browser
Run when call code
Run when call code is the code that will run after an event has occured.
Uniting this concepts:
When you create a listener, the rule that creates that listener is a run time code. But the code inside that listener will only run when called for.
I made a small example of this bellow, your problkem is not at changing the variable but when you are printing.
The printer button will print the var value
The cahnge calue will change that value one time
Hope this helps :)
let myVar = "before";
console.log(myVar);
function myFun(){
myVar = 'after';
}
function printer(){
console.log(myVar);
}
console.log(myVar);
<button onclick="myFun()">change value</button>
<button onclick="printer()">print</button>
You seem to using "click" event inside another "click" event.
An event action triggers and performs its operation and does not wait for another event inside or outside.
If you want variable value after certain operation of event, you need to assign it to variable and work when the event is triggered and operating.
I'm using a request header with a key and a value to read from the AngularJS controller. If that header, in this case, is AppHeaders is valid and has a custom value, I need to trigger a click from that controller. The code that I have, if something like this:
$scope.$applyAsync(function() {
if (appHeaders != null && appHeaders['header-name'] != null) {
if (appHeaders['header-name'] == "custom-value") {
$('.class-name').click();
}
}
});
What's wrong? I make a deep debug into this and the conditional works fine. I guess that the problem is because the element on the DOM doesn't exist when the click is fired.
Thanks for your help guys! The final solution results on apply the $broadcast event on the functions declared and use a counter to validate the last cycle of the calls to trigger the click on the element.
// Here we declare an empty array to store each request
var requests = [];
// Our first function
$scope.firstFunction = function() {
// Execute broadcast event with the name of the function
$scope.$broadcast('requestEnded',requests.push('firstFunction'));
};
// Our last function
$scope.secondFunction = function() {
// Execute broadcast event with the name of the function
$scope.$broadcast('requestEnded', requests.push('secondFunction'));
};
// This listener is executed each time that requestEnded is fired
$scope.$on('requestEnded', function(event, countRequests) {
// Here we validate that the count of requests is the desire
if (countRequests == 2) {
// Trigger Click
$('.class-selector').click();
}
});
I write a post with the entire research explaining this:
https://jbrizio.github.io/2017/10/20/Trigger-click-when-determinate-requests-finish-using-AngularJS.html
I am trying to get a value from a textbox and I'm only returning [object Object].
var key = $('body').on('click', '#ReportReferenceElectrical',function() {
$('#ReportReferenceElectrical').val();
});
var REPORTS_KEY = key;
I have tried the usual:
var key = $('#ReportReferenceElectrical').val();
The JS is in an iife and the value needs to retrieved when I submit the form to save but using this way its empty as the value was empty when the form loaded, I though the top code snippet might return me the value, but not.
The callback will get executed only when it is triggered. In this case, manually $.fn.triggering isn't an option, I suppose as it will be ""(Empty)
What you need is a callback.
function callback(key) {
alert(key);
// do something with the key now
}
And then call it in the event handler. I'd suggest going for the blur event rather than click
$('body').on('blur', '#ReportReferenceElectrical',function() {
callback($('#ReportReferenceElectrical').val());
});
Using jquery I've added a change handler to a form.
This works when any input is changed BUT only if the user manually changes an input and not when some other code changes the input.
Is there any way to detect if a form has changed even if its inputs are changed by code?
Yes, there seems to be some confusion over this. In an ideal world you would expect the onchange event to happen whenever the inputs change but thats not what happens. I'm sure for good reasons to - maybe not.
One way I've overcome this obstacle is to capture the form state into a variable just after displaying it and then just before submitting it to check if the state has changed and to act accordingly.
An easy state to store is what the serialize function returns. An easy place to store the state is using the data functionality. Both serialize and data are available with jquery.
Of course you can use other different forms of state (some form of hash) or storage for this state (standard global variable for example).
Here is some prototype code:
If your form id is 'xform' then you can call the following code when the form has displayed:
$('#xform').data('serialize',$('#xform').serialize());
And then, when you need to check, for example just before a button submit you can use:
if($('#xform').serialize()!=$('#xform').data('serialize')){
// Form has changed!!!
}
You could wrap all this up into a copy & paste javascript snippet that will give you a formHasChanged() function to call wherever you need it (NOT TESTED):
$(function() {
$('#xform').data('serialize',$('#xform').serialize());
});
function formHasChanged(){
if($('#xform').serialize()!=$('#xform').data('serialize')){
return(true);
}
return(false);
}
But I'll stop here otherwise I'll create yet another jquery plugin.
Serializing the form is certainly an option, but it will not work if:
you want to know which fields have changed
it only needs to check a subset of the fields
dynamically adding or removing fields.
Fortunately, every form element has a default value associated with its object:
input, textarea : defaultValue
checkbox, radio : defaultChecked
select: defaultSelected
for ex: to ckeck if input or textarea has changed:
var changed = false;
$(":text,textarea").each(function(){
changed = this.value != this.defaultValue;
return !changed; // return if at least one control has changed value
});
This is easily achieved in JavaScript without jQuery. initChangeDetection() can be called multiple times:
function initChangeDetection(form) {
Array.from(form).forEach(el => el.dataset.origValue = el.value);
}
function formHasChanges(form) {
return Array.from(form).some(el => 'origValue' in el.dataset && el.dataset.origValue !== el.value);
}
Test on JS Bin
For older browsers that don't support newer arrow/array functions:
function initChangeDetection(form) {
for (var i=0; i<form.length; i++) {
var el = form[i];
el.dataset.origValue = el.value;
}
}
function formHasChanges(form) {
for (var i=0; i<form.length; i++) {
var el = form[i];
if ('origValue' in el.dataset && el.dataset.origValue !== el.value) {
return true;
}
}
return false;
}
Not in a regular way.
You can change with input and then trigger the change event.
$('#inputId').val('foo').trigger('change');
or with this:
$('#inputId').val('foo').change();
Here is what i did (i found my solution using zaf's answer)
$("form").change(function() {
$(this).data("changed","true");
});
$("input[type='submit']").click(function() {
if($("form").data("changed") == "true") {
var discard = confirm("Some unsaved changes. Discard them ?");
if(!discard) return false;
}
});
Try onchange attribute
According to W3c it should trigger anytime the content of an element, the selection, or the checked state have changed.
In my form I have a set of input boxes where a user can input a value.
On change of one of these boxes, the form automatically gets submitted.
The problem now is however that a user stays in the last field, takes the mouse and presses the OK button (of another form) without leaving the textbox first. The change event doesn't get triggered and the old, incorrect values get passed to the next page.
I want to trigger the onchange event after a few miliseconds of inactive keyboard. Just like most autocomplete plugins do.
I think I could implement a timer that starts timing the moment you enter an input field and gets resetted everytime a keystroke is handled and then when it reaches zero the onchange event gets triggered.
I'm not up for re-inventing the wheel and was wondering if such a function is available somewhere.
Suggestions?
I had a similar problem and created a jQuery plugin currently in use in an internal application. It should trigger the change event after the user is done typing.
If you are not using jQuery, the code is still adaptable to anything else.
jQuery.fn.handleKeyboardChange = function(nDelay)
{
// Utility function to test if a keyboard event should be ignored
function shouldIgnore(event)
{
var mapIgnoredKeys = {
9:true, // Tab
16:true, 17:true, 18:true, // Shift, Alt, Ctrl
37:true, 38:true, 39:true, 40:true, // Arrows
91:true, 92:true, 93:true // Windows keys
};
return mapIgnoredKeys[event.which];
}
// Utility function to fire OUR change event if the value was actually changed
function fireChange($element)
{
if( $element.val() != jQuery.data($element[0], "valueLast") )
{
jQuery.data($element[0], "valueLast", $element.val())
$element.trigger("change");
}
}
// The currently running timeout,
// will be accessed with closures
var timeout = 0;
// Utility function to cancel a previously set timeout
function clearPreviousTimeout()
{
if( timeout )
{
clearTimeout(timeout);
}
}
return this
.keydown(function(event)
{
if( shouldIgnore(event) ) return;
// User pressed a key, stop the timeout for now
clearPreviousTimeout();
return null;
})
.keyup(function(event)
{
if( shouldIgnore(event) ) return;
// Start a timeout to fire our event after some time of inactivity
// Eventually cancel a previously running timeout
clearPreviousTimeout();
var $self = $(this);
timeout = setTimeout(function(){ fireChange($self) }, nDelay);
})
.change(function()
{
// Fire a change
// Use our function instead of just firing the event
// Because we want to check if value really changed since
// our previous event.
// This is for when the browser fires the change event
// though we already fired the event because of the timeout
fireChange($(this));
})
;
}
Usage:
$("#my_input").handleKeyboardChange(300).change(function()
{
// value has changed!
});
Does it not work to do an onBlur, so both when the user moves to the next field or clicks something else, the value is saved?
I don't know that such a solution would be considered "re-inventing" anything. As you said, it sounds to be nothing more than a simple setTimeout once the page loads. After about 3,000 milliseconds, it runs form.submit().
I would probably restart the count-down with each keystroke too, to give the user enough time to make their entry.