Javascript Wait for Ajax Content Load - javascript

I am newbie to javascript and am writing to traverse a DOM . The page uses Checkboxes to filter results. Results are displayed using Ajax. There are 4 level of checkboxes.
Grand Parent
Parent
Child
Grand Child .
For each level, I want the javascript to click the checkbox and WAIT for the content to load.
Right now it checks and traverses the whole DOM , but does not wait .
What I want is , that when the element is CLICKED , next function decideread() should be called only when Ajax results have been refreshed.
I have tried using setTimeOut and other delay methods, but they say it's single threaded so that won't work. Any ideas ?
for (i = 0; i < mgtNode.length; i++) {
mgtNode[i].click();
for (j = 1; j < stateNode.length; j++)
{
stateNode[j].click();
var read = decideRead();
if (read)
{
alert('we have read the data, now skip further reading below');
stateNode[j].click(); // we have read the data, now skip further reading below.
continue;
}
for (k = 0; k < inTypeNode.length; k++) {
inTypeNode[k].click();
var read = decideRead();
if (read)
{
alert('we have read the data, now skip further reading below');
inTypeNode[k].click();
continue;
}
for (l = 0; l < jobNode.length; l++)
{
jobNode[l].click();
while (true) {
if (new Date() - startTime >= 5000) {
break;
}
}
saveData();
jobNode[l].click();
}
inTypeNode[k].click();
}
stateNode[j].click();
}
mgtNode[i].click();
}

You should use the onreadystatechange for this. Check this http://www.w3schools.com/ajax/ajax_xmlhttprequest_onreadystatechange.asp

Related

Displaying DOM elements on the web-page while looping over them

I am working on a landing page. I have 3 article elements, each of them has the property “display: none” and a class 'art'. I want to display each of them while looping over them. They should appear successively: the previous ones must disappear at each iteration, that is why I have used var j in the code below. But JS code displays them after the whole process of looping is completed. How to deal with it? Here: https://codepen.io/user_jacob/pen/oNjqWGg.
Currently, I am doing it like this (which is not working):
function makeAppear() {
var j = list.length-1;
for (var i = 0; i < list.length; i++) {
list[i].style.setProperty('display', 'block');
list[j-1].style.setProperty('display', 'none');
}
}
In set interval don put () just write function name . For looping create one global index then hide all first then show indexed one.
let j=0;
function makeAppear() {
for (var i = 0; i < list.length; i++) {
list[i].style.setProperty('display', 'none');
}
list[j].style.setProperty('display', 'block');
if(j<2){ j++;}
else {j=0}
}
setInterval(makeAppear, 2000);

Javascript Performance improvement

I am Using Jquery plugin to show a dropdown which looks like this
Now in the edit page, this drop-down opens with checked checkboxes, I do this with the help of Javascript which is as below
var setValues = $("#SelectedFrameworks").val().split(",");
for (var i = 0; i < setValues.length; i++) {
var selectedElement = $("#frameworksDropDown").find('*[data-id="' + setValues[i] + '"]');
selectedElement.find("i").addClass("fa-check-square-o").removeClass("fa-square-o");
SelectParent(selectedElement);
}
function SelectParent(_element) {
var count = 0;
for (var i = 0; i < $(_element).parent().children().length; i++) {
if ($(_element).parent().children().eq(i).find("i").attr("class") == "fa select-box fa-check-square-o") {
count++;
}
}
if (count == $(_element).parent().children().length) {
$(_element).closest("ul").siblings("i").click();
}
}
I store this value first in the hidden field then use it to Check the checkboxes. (as shown in the code)
Now the problem is, it takes too much time when data is a lot. this causes the page to hang.
I found that operation
selectedElement.find("i").addClass("fa-check-square-o").removeClass("fa-square-o");
takes too much time. how can I optimize this code to have a better result
EDIT
Here is the HTML for this dropdown.
Note: this HTML is autogenarated.
Thanks.
So one of the big issues with this code is the amount of times you're calling the DOM. Everytime you do $(el) you're calling document.getElementByClassName or id etc. Which is gonna be slow and is unnecessary to make that many calls.
So you can change
function SelectParent(_element) {
var count = 0;
for (var i = 0; i < $(_element).parent().children().length; i++) {
if ($(_element).parent().children().eq(i).find("i").attr("class") == "fa select-box fa-check-square-o") {
count++;
}
}
if (count == $(_element).parent().children().length) {
$(_element).closest("ul").siblings("i").click();
}
}
To this, which accesses the DOM once, stores a reference to the element. This will cut down on the amount of DOM calls you make. The biggest advantage to this is of course, speed. I always make a point of naming jquery variables beginning with $ so that it's much easier and quicker to tell what that variable is in the future, or if someone else comes to work on your code.
function SelectParent(_element) {
var count = 0;
var $element = $(_element);
var $children = $element.parent().children();
for (var i = 0, length = $children.length; i < length; i++) {
if ($children.eq(i).find("i").attr("class") == "fa select-box fa-check-square-o") {
count++;
}
}
if (count == $children.length) {
$element.closest("ul").siblings("i").click();
}
}
Now of course you can refactor the rest to speed it up ;)

Break and Continues

I wonder if someone can clarify something for me. I have a bit of code to check an array for overlapping values depending on different values. Basically its the contents of a google sheet in rows and comumns for this is specifically GAS. What I have at the moment is
var e = [[2,4,3,4,2],[1,5,3,6,2],[2,4,3,4,1],[1,4,3,6,1],[2,4,3,6,5]];
var i; //id of entry to check
var j; //id of element to check
var k; //id of entry to compare
for (i in e){ //2D ARRAY ARRAY
for (k in e){ //ELEMENT TO COMPARE
if (e[i][2] === e[k][2] && e[i][3] === e[k][3] && e[i][0] && e[i][0] >= e[k][0] && e[i][1] <= e[k][1] && e[i][4] <= e[k][4] && i !=k){
e.splice(i,1);
continue;
}
}
}
return e;
I had to add the continue; as otherwise if the last array checked was also marked for splice the code failed. But I assumed break would also work in place of continue but for some reason it does not. I thought break would return to the outside loop but does it permanently break that bit of code?
Thanks people
EDIT: spoke too soon. code still fails even with continue. head scratching continues
continue jumps directly to the next iteration, so:
while(true) {
console.log("a");
continue;
console.log("b");
}
will only log a as it will jump back to the beginnig of the loop if it reaches continue.If you however move continue to the last line of the loop (just as in your code) it does nothing as it would jump to the begining to the loop one line later, so it just skips an empty line.
I thought break would return to the outside loop
Yup, thats what happens and that is actually a good thing as if you removed the element already, it won't make sense to check for other dupes as you don't want to remove it twice.
Now the real problem is that splice changes the indexes, so if you splice out the fourth element, the fith element becomes the fourth element, but the loop continues to the fith element without checking the fourth element again (which is now a different one). Therefore you have to go back by one element before you break:
for(let i = 0; i < e.length; i++) {
for(let k = 0; k < e.length; k++) {
if(i === k) continue; // < good usecase
if(/* equality checks */) {
e.splice(i, 1); // remove the element
i--; // go back by one as we changed the order
break; // exit the inner loop
}
}
}
IMO:
1) I would favor for(const [i, value] of arr.entries() over for..in
2) you will forget what arr[i][2] is very soon, giving proper names to the indexes makes it way more readable:
const [idA, someValueA] = e[i];
const [idB, someValueB] = e[k];
if(idA === idB && someValueA <= someValueB // ...
3) e is a bad name.
You can use a labelled break to break out of nested loops.
eg
var num = 0;
outermost:
for(var i = 0; i < 10; i++){
for(var j = 0; j < 10 ; j++){
if(i == 5 && j == 5){
break outermost;
}
num++;
}
}

Using .push stops for loop from executing

I have a for loop that suddenly stops working when I try to push to an array. The best way to describe what's going on is just to show my code and try an explain what's going on.
for (var i = 0; i < childs.length; i++) {
if (childs[i].length > 0) {
for (var j = 0; j < amountsValue[i].options.custValues.length; j++) {
var label = amountsValue[i].options.custValues[j].label;
var value = amountsValue[i].options.custValues[j].value;
for (var k = childs[i].length - 1; k >= 0; k--) {
if (childs[i][k].attributes[label] != value) {
childBackup.push(childs[i][k]);
childs[i].splice(k, 1);
}
}
}
amountsValue[i].id = childs[i][0].attributes.internalid;
childs.push(childBackup);
}
}
What's happening is I am looping through an array of items which may or may not have custom options available such as different sizes or colours. The loop will check to see if there are any then get the value and label from the array.
After this, we then loop again to try and match up the values with option values stored within a separate model. The plan is to check if the value is the same as the one stored and if not then splice it from the array. The process of elimination should eventually leave only one option left and that will be used to get the internalid.
During this a back up of the spliced objects is kept so that they can be appended to the array again so that the user can change the option they want. The problem is using childs.push(childBackup) stops the browser form reading the options on amountsValue. This works if the code is removed or it is pushed into another index so I'm really not sure why it isn't working.
Does anyone have any suggestions on how to get this working? I'm sorry if this doesn't make much sense, I've tried to explain it as best I can but let me know if anything needs to be cleared up.
EDIT: I have fixed the issue. Thank you to everyone who suggested ways to solve the problem. As others said, I was trying to manipulate the array I was looping through and changing the length on it. So that part of the code was taken outside the loop and after the initial loop another loop was set up which contained the following code:
for (var i = 0; i < childBackup.length; i++) {
childs[0].push(childBackup[i]);
}
It now works as intended. Thank you.
You are manipulating the array you are looping through.
var count = childs.length;
for (var i = 0; i < count; i++) {
if (childs[i].length > 0) {
for (var j = 0; j < amountsValue[i].options.custValues.length; j++) {
var label = amountsValue[i].options.custValues[j].label;
var value = amountsValue[i].options.custValues[j].value;
for (var k = childs[i].length - 1; k >= 0; k--) {
if (childs[i][k].attributes[label] != value) {
childBackup.push(childs[i][k]);
childs[i].splice(k, 1);
}
}
}
amountsValue[i].id = childs[i][0].attributes.internalid;
childs.push(childBackup);
}
}

Open PHP without breaking JavaScript loop

I'm iterating over a table's values to modify them if any changes have been made by the user.
Currently I have something similar to:
for (var i = 0; i < rows.length - 1; i++) {
if (item[5]) {
window.open("modify.php?id=" + id + "&delete=true");
}
}
My question is how I can connect to my modify.php file without breaking the for loop. I tried with
window.location("modify.php?id=" + id + "&delete=true");
too but that's the same story.
I considered using window.open and setting the new windows dimension's to something very small so it appears hidden and closing it again after my PHP has finished executing.
This however seems ridiculously dumb hence why I'm wondering what a/the better approach would be?
It sounds like you want to be using AJAX here. For conciseness, I'll show you what I mean using jQuery.ajax:
for (var i = 0; i < rows.length - 1; i++) {
if (item[5]) {
$.ajax("modify.php?id=" + id + "&delete=true");
}
}
This sends an asynchronous HTTP GET request to the URL provided.
AJAX can be done in vanilla JavaScript too but for reasons of convenience and compatibility I would recommend using a library.
As with any other code, why not simply copy the instructions for later use?
var openItems = [], i;
for (i = 0; i < rows.length - 1; i++) {
if (item[5]) {
openItems.push(id); // Don't open the window just yet, just copy to array
}
}
for (i = 0; i < openItems.length; i++) {
window.open("modify.php?id=" + openItems[i] + "&delete=true");
}
And if you consider that you'd only be opening one window anyway (and you want the first item to be it), then simply do the following:
var openID, i;
for (i = 0; i < rows.length - 1; i++) {
if (item[5]) {
openID = i;
break; // No need to continue iterations
}
}
if (openID) {
window.open("modify.php?id=" + openID + "&delete=true");
}
If you want the last item to be the one you open, simply remove the break; statement.

Categories

Resources