-1

I have a dashboard site in the works, and it makes use of SpringMVC, FusionCharts, and Bootstrap (to give an architectural overview). When I freshly start up the Tomcat server, the very first time I'm served the index page, a panel of buttons will not render properly. I get the correct number of white circles with question marks as made in the first of 3 javascript functions. If I refresh the page, the intended red and green results immediately come up, generated by the second script function.

As a preamble, the panel with buttons on it is correctly generated with the right count, correct names, correct HREFs and all else. The colors just do not change until the page is refreshed. Back when this project was first constructed, the data was being gathered via http request server-side. It was comparably slow to what is occurring now: loading the data from a file server-side and sending it through in the same format. The old way always produced the correct colors and icons after a 10-second wait. Now, the buttons just remain blank white until I refresh the page, and then I get the right results.

I believe this is just the result of two Javascript functions stepping on each other, even though I know JavaScript is single-threaded. If not, I'm stumped and lost.

Index.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Free Bootstrap Admin Template : Dream</title>
<!-- Bootstrap Styles-->
<link href="css/bootstrap.min.css" rel="stylesheet" />
<!-- FontAwesome Styles-->
<link href="css/font-awesome.css" rel="stylesheet" />
<!-- Morris Chart Styles-->
<link href="js/morris/morris-0.4.3.min.css" rel="stylesheet" />
<!-- Custom Styles-->
<link href="css/custom-styles.css" rel="stylesheet" />
<!-- Google Fonts-->
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css' />

<script type="text/javascript" src="js/fusioncharts/core/fusioncharts.js"></script>
<script type="text/javascript" src="js/fusioncharts/themes/fusioncharts.theme.fint.js"></script>


</head>
<body> 

...

<!-- this is where the button panel is correctly created on every load
     but only correctly modified on the 2nd load and later -->
<div class="row"> <div id="AppStatusTable"></div> </div>

...

<script src="js/jquery-1.10.2.js"></script>
<!-- Bootstrap Js -->
<script src="js/bootstrap.min.js"></script>
<!-- Metis Menu Js -->
<script src="js/jquery.metisMenu.js"></script>
<!-- Morris Chart Js -->
<script src="js/morris/raphael-2.1.0.min.js"></script>
<script src="js/morris/morris.js"></script>


<!-- Custom Js -->
    <!--
<script src="js/custom-scripts.js"></script>  -->
<script>

    $(document).ready(function(){
        $.get("/buttoninfo", function(data, status) {
            tableMaker(data, "AppStatusTable");
        });

        $.get("/appstatus", function(data, status) {
            appStatus(data);
        });

        $.get("/stackstatus", function(data, status) {
            stackUpdater(data);
        });

    });
</script>
</body>

These last 3 functions fill out the html of a panel to contain a dynamic number of buttons, modify the inner html of those buttons, and then update other panels. The third currently takes a while and always produces correct results. I don't suspect it is the issue.

dashboard.js

function templateLoader(appTag) {
    //$.get('/app/' + appTag);
    window.location = "/app/" + appTag;
}

function appStatus(data){

    for(var i = 0; i < data.length; ++i) {
        if(data[i][1] == "up"){
            $("#" + data[i][0] + "-appcheck").removeClass("btn-default");
            $("#" + data[i][0] + "-appcheck").addClass("btn-success");
            $("#" + data[i][0] + "-appcheck-icon").removeClass("fa-exclamation-circle");
            $("#" + data[i][0] + "-appcheck-icon").addClass("fa-check");
        } else if(data[i][1] == "down"){
            $("#" + data[i][0] + "-appcheck").removeClass("btn-default");
            $("#" + data[i][0] + "-appcheck").addClass("btn-danger");
            $("#" + data[i][0] + "-appcheck-icon").removeClass("fa-exclamation-circle");
            $("#" + data[i][0] + "-appcheck-icon").addClass("fa-close");
        }
    }
}

function tableMaker(data, tableID) {

    /* vars used below as the skeleton of the injected buttons*/

    var i = 0, j = 0, colLimit = 12;
    for(; i < data.length;){
        for (var j = 0; j < colLimit && i < data.length; ++j, ++i) {
            mytable +=  colStart + data[i][2] + titleEnd + '\n' + buttonStart + data[i][2] + buttonMiddle1 +
                    data[i][2] + buttonMiddle2 + data[i][2] + buttonMiddle3 + '><i id="' + data[i][2] +
                    buttonEnd + colEnd;
        }
    }

    panel += mytable + panelEnd;

    document.getElementById(tableID).innerHTML = panel;
}

function stackUpdater(data){
    for(var i = 0; i < data.length; ++i){
        var curStack = data[i][0];
        for(var j = 1; j < data[i].length; j++) {
            if(data[i][j] == null) {
                break;
            } else {
                $("#" + curStack + j).removeClass("progress-bar-info");
                if(data[i][j] == "up") {
                    $("#" + curStack + j).addClass("progress-bar-success");
                } else {
                    $("#" + curStack + j).addClass("progress-bar-danger");
                }
            }
        }
    }
}

I understand browsers cache the results of javascript functions, but the third function is run on every refresh, so why wouldn't the first two be? And thus, why would the results of the second function only appear after refreshing?

What needs to be changed to make sure the buttons modify correctly the FIRST time this page is loaded?

UPDATE 1

After inserting alerts between the function calls, the rendering works on the first try, so what's the correct way to ensure synchronization without this?

Bottom of Index.html:

    $(document).ready(function(){
        $.get("/buttoninfo", function(data, status) {
            tableMaker(data, "AppStatusTable");
        });

        alert("Button table made!");

        $.get("/appstatus", function(data, status) {
            appStatus(data);
        });

        alert("Button Data Updated!");

        $.get("/stackstatus", function(data, status) {
            stackUpdater(data);
        });

        alert("Stack Data Updated!");

    });
</script>
patrickjp93
  • 399
  • 4
  • 20
  • You may as well remove this question. You've done a massive code dump. – Derrops Dec 08 '16 at 04:20
  • I would not call under 70 lines massive, and it's well-formatted and easily readable. Some of the C++ questions are 300 lines of junk for cripes sake. Further, seriously, no ideas? – patrickjp93 Dec 08 '16 at 04:32
  • Code dump is more about that you have allot of stuff not related with your problem. Before you ask a question you need to take the time to strip down all the code into a minimal amount which demonstrates your problem. What does this have to do with Spring anyway? – Derrops Dec 08 '16 at 04:37
  • This is minimal. All I have posted is where the JavaScript is called on the html page, what other javascript libraries are being used and in what order, and what my javascript code is. That is minimal. I don't know if the Spring MVC is part of the problem or not, and that's part of why I'm asking if it might be. – patrickjp93 Dec 08 '16 at 04:39
  • There, trimmed enough for you Snickers? – patrickjp93 Dec 08 '16 at 05:04

1 Answers1

0

Instead of using $.get try using $.ajax with cache set to false. If $.get is absolute necessary try adding a timestamp with each request. You may refer to How to set cache: false in jQuery.get call.

Hope that help.

Community
  • 1
  • 1
  • I'm as much about the why as the how. Why would this solve the problem? It's not necessarily necessary. I'm just a complete JavaScript and web development novice with a task I'm trying to make the most of. As the JS code style probably shows, I come from a backend background. – patrickjp93 Dec 08 '16 at 05:03
  • I've implemented a temporary fix by putting a 90ms delay on the appstatus function. Hopefully after modifying stackstatus to load from files I can just change the function call order and this race problem will resolve itself. It may also just resolve itself once it's deployed on AWS and we have propagation delays ANYWAY. – patrickjp93 Dec 08 '16 at 06:01
  • Not sure but since the 3 functions are getting executed in the document.ready event, and each of them involves an ajax call with a callback, there needs to be re-initialization of the callbacks. – Suman Banerjee Dec 08 '16 at 06:05
  • And me not being JS savvy in the slightest have no clue what you mean and would greatly appreciate a link to an example. And thank you for the reply! – patrickjp93 Dec 09 '16 at 00:09