Form freezes/crashes - javascript

I have some jQuery that resets selects/dropdowns if the user changes the option selected in the previous dropdown. But when I include this jQuery it causes my form to freeze/crash sometimes - it happens after about 30 seconds of clicking around the form.
Can anyone spot anything wrong with this code? This is the jQuery code that seems to be causing the issues:
// 1. Resetting Fields
age_select.on("change", function() {
let currentCol = jQuery(this).val();
// When age is changed reset other dropdown (by setting value to the default one)
// and trigger change for the event handler to be called
subject_select.attr("data-column", currentCol).val('subject-fill');
area_select.attr("data-column", currentCol).val('location-fill');
});
//2. Resetting Fields - BELOW PART IS CAUSING THE FORM TO CRASH SOMETIMES
// if subject is changed reset location and trigger change
subject_select.on("change", function() {
area_select.val('location-fill').trigger('change');
});

My guess is you have some issue with the area_select event handler such that you might be triggering another change that creates an infinite loop (if for example that one triggers a change event on subject_select).
Your post is too ambiguous without a working(broken) example though.

Related

Is there a jquery event the runs just before focus leaves an element or just before the next element gains focus?

I have a form with two input elements that are somewhat intertwined. In element#1 (element #2 is right after element#1 in the tabindex order), once the user tries to leave that field, I run an ajax call to check if the value entered is already in the database and if so, use the javascript confirm dialog to ask the user a question. The second element, upon gaining focus, automatically pops up a modal window with choices the user can make. I am using Jquery.
I would like to run the "Does this data exist" ajax call as soon as the user leaves the first element. the Blur event seemed to be what I wanted as this existing data check is needed whether the user made a change or not.
My problem using blur, though, is that its handler runs AFTER the first element loses focus and focus jumps to element#2. So, the blur handler from element #1 pops up the confirm screen at the same time element #2's focus handler pops up the choices modal and I now have 2 popups open at the same time.
I would like to give the user the chance to answer the question in the confirmation alert before the choices for the element#2 pop up.
Is there a Jquery event similar to blur, but that runs just BEFORE focus is actually lost? Or, is there a way to prevent the next element from gaining focus until the blur handler from the first element completes?
Trying to stop propagation or preventDefault() in the Blur handler does nothing because the focus on element#2 has already happened before the blur handler runs.
I've tried setting the tabindex of element#2 to -1 and then programmatically focusing on that element when needed, but tabbing away from this element becomes a problem, and reverse tabbing skips it (jumping straight to element#1) - I still want that element in tabindex ordering, but just don't want it to gain focus until element#1 completes its handler that needs to run when it loses focus.
I have tried setting status variables as well but when I add code to handle the transition between the two elements, I end up with similar issues and it presents additional edge cases complexity. I've also tried messing with mousedown and keydown events and trying to prevent the default processing, but that added significant complexity and room for error as well.
Any ideas would be welcome. Thank you.
This solution is a bit of a hack, but accomplishes your goal. The trick is to place what amounts to a "no-op" element that accepts the focus on blur. Then controlling the tab after the AJAX request.
Upon each "blur" event, we test to ensure we capture the correct <input> element (I'll leave those details to you).
After the AJAX request has completed, then focus on the next <input>.
For this demo, type 2 in the second input, then tab. I added a short delay so you can see that it works.
$("input").on('blur', function(e){
if(this.value == 2) {
console.log("do ajax request");
setTimeout((function(){
$(this).next().next('input').focus();
}).bind(this), 500);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input tabindex="1" />
<input tabindex="2" />
<div tabindex="3"></div>
<input tabindex="3" />
Would something like this do the trick?
Have a variable that indicates if it's okay to show the second popup
let allowSecondPopup = true;
Have a variable that indicates whether showing the second popup was postponed
let secondPopupPostponed = false;
Set the variable when the first input receives focus
$("#input1").on("focus", fuction () {
allowSecondPopup = false;
});
Send ajax on blur
$("#input1").on("blur", function () {
//$("#input1").disabled(true);
//$("#input2").disabled(true);
$.post("https://example.com", { }, fuction (response) {
if (secondPopupPostponed) {
// Only show second popup after the ajax-call has finished
showSecondPopup();
allowSecondPopup = true;
secondPopupPostponed = false;
}
});
});
And when the second input receives focus, check the variable
$("#input2").on("focus", fuction () {
if (allowSecondPopup) {
showSecondPopup();
} else {
// We're still waiting for the ajax-call to complete.
// When the ajax-call completes, the callback will show the second popup.
secondPopupPostponed = true;
}
});

How do I run a change event after dynamically updating a value in a form using JavaScript/jQuery?

Each time my form is updated, multiple calculations are run. This is within an on change event listener:
form.addEventListener('change', function (event) {
I want a button that resets the value of a field in the form, then updates the calculations. The click function below changes the value but doesnt update the form calculations. I wrapped my on change event in a function, then called it within the onclick, but didnt work. Is there a way to trigger a form change using an on click like below?
$("#s2q12_reset").click(function(){
$("#s2q12").val(0);
});
Your best bet here by far is to move the code doing the calculations into its own function, and then call that function from the change handler and from your click handler (after changing the value):
function updateCalculations() {
// ...
}
// If all that your `change` event does is that, you can use the funttion directly:
form.addEventListener('change', updateCalculations);
$("#s2q12_reset").click(function(){
$("#s2q12").val(0);
updateCalculations();
});
As a very-much-second-best solution, you can trigger the change event after updating the value via form.change().

Javascript click event listener fires only once

I have a Chrome extension that intercepts and checks tweets before they get posted. To do this, I've add an event listener to the Tweet button. Sine the content is dynamic, I use the solution proposed in this thread:
initialize : function() {
let that = this;
let jsInitChecktimer = setInterval(checkForJsFinished, 111);
function checkForJsFinished () {
if (document.querySelector("div[data-testid='tweetButtonInline']")) {
clearInterval (jsInitChecktimer);
console.log("Button found");
that.addSubmitNewTweetClickHandler();
}
}
},
addSubmitNewTweetClickHandler : function() {
let that = this;
let buttonSubmitTweet = document.querySelector("div[data-testid='tweetButtonInline']");
buttonSubmitTweet.addEventListener('click', function(e) {
console.log("CLICK");
// Stop default event from happening
e.preventDefault();
e.stopImmediatePropagation();
// Do stuff
});
},
If the tweet passed the checks alright, it gets submitted by programmatically triggering the event using .trigger('click').
This works fine, but only once. After a tweet has been submitted and posted, the event listener on the Tweet button is gone, and I cannot intercept the next tweet to check it. I've tried calling initialize() after submitted again -- maybe the button gets removed and newly added to the DOM (it actually disappears fire a moment when submitting a tweet) -- but the querySelector finds the button immediately. But even after calling initialize() again, no click even on the Tweet button fires.
What could be the issue here? My problem is that I don't even know where to look for and how to debug this.
After many more hours, I've finally figured it out. The problem was essentially the highly dynamic content of the new Twitter website. After submitting a tweet, the Tweet button gets indeed removed and added again. In needed to do a serious of changes:
Use a MutationObserver to keep track of any changes. Every time there's a change, call the initialize() function. To avoid too many calls, I do this in case of certain changes (unnecessary detail here)
Change the addSubmitNewTweetClickHandler() method so that the event listener first gets removed in order to avoid duplicate listeners (please note that I use objects hence the use of this compared to my original question)
addSubmitNewTweetClickHandler : function() {
let that = this;
let buttonSubmitTweet = document.querySelector("div[data-testid='tweetButtonInline']");
buttonSubmitTweet.removeEventListener('click', this.handleSubmitNewTweetClick );
this.handleSubmitNewTweetClick = this.handleSubmitNewTweetClick.bind(this)
buttonSubmitTweet.addEventListener('click', this.handleSubmitNewTweetClick );
},
This change required to create the reference function handleSubmitNewTweetClick
Overall, it's still not a perfect solution since I call initialize() many unnecessary time. However, I failed to reliably identify when the Tweet button was added to the document. When I used the MutationObserver none of the added nodes had the attribute data-testid which I need to identify the correct button. I have node idea why this attribute was not there. Maybe the attribute is added some times after added to button, but even with an additional MutationObserver looking for attribute changes I could detect this.
Anyway, it works now and it's only for a prototype.

How to detect the difference between a change made by a user and a change made programmatically?

I have an onChange event handler that is being triggered twice; once for a change made by a user, and a second time for a change made programmatically as a result from the original user's change. The event should only be triggered once, for the former. How do you discern between a changed made by a user and one by a script?
If you just change the value with el.value = x, the change event is not triggered. For example, this won't log anything to the console:
var el = document.getElementById('el')
el.onchange = function(){
console.log('changed');
};
el.value = 'asasassasa';
So, if you're seeing it's being triggered twice, it's either because:
You're manually triggering it with el.onchange(). In this case, just remove the this call.
Or:
The event handler is bound to the element more than once. You have to locate where that's happening.
One good approach to catch such issues and sometimes work around them is to always check the older value with the present value in the onchange handler.
function onChange_handler(e){
if(this.old_value==this.value){
return; // no change detected - check why was it called twice.
}
this.old_value=this.value;
// the real change handling code
}

jQuery selector "memory"

I have a form with multiple fields, and each time the user changes a field the form is submitted (via hidden iframe), and the response is placed within an appropriate div on the page via a callback. The first time this works fine. But on each subsequent field change and submission, the response is shown in every div that has been filled with a response (so they all show the same thing, not the desired behavior).
Can anyone tell me why this is happening? It seems that there is some retention of the selectors that have been called before (since last page load)... but I'm not sure. Here's my code:
$(function ()
{
$('#ImageAddForm input').change(function (){
form = $('#ImageAddForm');
var fldDiv = $(this).parent().attr('id'); // eg Image11
var thDiv = fldDiv.replace('Image', 'Thumb'); // eg Thumb11
$(form).iframePostForm({
post : function (){
var msg = 'Uploading file...';
$("#" + thDiv).html(msg);
},
complete : function (response){
$("#" + thDiv).html(response);
$(':input', '#ImageAddForm').not(':hidden').val('');
}
});
form.submit();
});
});
I'm not familiar with that plug-in, but I have a suspicion about what might be causing your problem. You are attaching some functionality to your form with the plug-in inside of your change event. This means that on every change you are attaching again, which is likely to cause some problems. Two solutions suggest themselves:
1) If the plug-in has some kind of call to unbind or destroy itself, call that right before binding the plug-in to the form. This should prevent any weird behavior caused by multiple binding.
2) Better solution: bind the plug-in to the form outside your change event, and scope your variables (fldDiv, tdDiv) such that they will be accessible to both your change event (so that they can be modified based on what changed) and the functions used by the plug-in (for post and complete). This way you will only bind the plug-in once, but can still pass and receive different data based on what field changed.

Categories

Resources