For work, I built an educational software tool for radiologists. The application provides radiologists a dashboard for viewing their exams. They are able to cycle through each exam and see all the exam data in a popup (modal) window.

The problem that I ran into is that the application had a 2-3 second delay on the staging/production server. The logic behind the exam pop-up window uses a single AJAX call that queries the exam data and then passes that data from the controller and into a view. From everything I’ve learned, this is as straight forward, simple as it gets far as AJAX calls go.

The reason for the delay is unknown. I think it had to do with the vendor’s rabbitMQ’s messaging bus, however, I am not certain. While the groups scratch their heads trying to figure the speed disreprency, I set out to implement a work-around.

Since a lot of the exam data is already being used in the dashboard, I figured I could eager load the rest of the exam data into hidden fields. With all the data there, I then use the code below to dynamically create the exam pop-up windows without ever doing any AJAX calls, thus fixing the speed issue.

/* User selects an exam */
function openExam(examId) {
    openExamModal(examId);
    populateExamModal(examId, null);
}

/* User clicks on the Left (previous) arrow */
function openPrevExam(examId) {
    openExamModal(examId);
    populateExamModal(examId, 'prev');
}

/* User clicks on the Right (next) arrow */
function openNextExam(examId) {
    openExamModal(examId);
    populateExamModal(examId, 'next');
}

/* Dynamically populate the modal */
function populateExamModal(examId, action) {

    var arrayOfExamIds = getExamIdsFromDashboard();
    var index = getExamIndex(examId, arrayOfExamIds);

    if (isValidExam(index)) {

        var isOpeningNewExam = isPrevOrNextButtonClicked(action);

        if (isOpeningNewExam) {
            index = getNextExamIndex(index, action);
            examId = arrayOfExamIds[index];
        }

        showCurrentIndex(examId, index, arrayOfExamIds.length);

        displayReportAndDiff(examId, null, null);

        displayLevenshteinDistance(index, examId);

        if (isOpeningNewExam) {
            openExamModal(examId);
        }
    }
}

function displayReportAndDiff(examId, reportOneId, reportTwoId) {

    var prelimId = getReportOneId(examId);
    var finalReportId = getReportTwoId(examId);

    reportOneId = reportOneId === null ? prelimId : reportOneId;
    reportTwoId = reportTwoId === null ? finalReportId : reportTwoId;

    var reportImpression1 = getReportImpression(reportOneId);
    var reportImpression2 = getReportImpression(reportTwoId);

    var reportBody1 = getReportBody(reportOneId);
    var reportBody2 = getReportBody(reportTwoId);

    if (isThereTwoReports(reportOneId, reportTwoId)) {

        displayReport(examId, reportOneId, reportImpression1.html(), reportBody1.html(), 'Div1');
        displayReport(examId, reportTwoId, reportImpression2.html(), reportBody2.html(), 'Div2');

        var reportDiff = getTheDiff(reportBody1.text(), reportBody2.text());
        var impressionDiff = getTheDiff(reportImpression1.text(), reportImpression2.text());

        var reportDiffDiv = outputTheReportBodyDiff(examId);
        var impressionDiffDiv = outputTheReportImpressionDiff(examId);

        reportDiffDiv.html(reportDiff);
        impressionDiffDiv.html(impressionDiff);
    }
}

/* Get all exam ids listed in table */
function getExamIdsFromDashboard() {

    var table = getTheDashboardTable();
    var examIdColumn = null;
    var examIds = [];

    for (var r = 0, n = table.rows.length; r < n; r++) {
        for (var c = 0, m = table.rows[r].cells.length; c < m; c++) {

            var value = table.rows[r].cells[c].innerHTML;

            // find the exam id column
            var isExamIdColumn = r == 0 && value == "Hidden Exam Id";

            // get the index for exam id column
            if (isExamIdColumn) {
                examIdColumn = c;
            }

            // use index to reference the exam id value to access its value
            if (r > 0 && c === examIdColumn) {

                if (value != "" && !isNaN(value)) {
                    examIds.push(value);
                }
            }
        }
    }

    return examIds;
}

function displayReport(examId, reportId, reportImpression, reportBody, div) {

    /* form elements containing report information */
    var getTheStatus = getTheReportStatus(reportId);

    var outputTheStatus = outputTheReportStatus(examId, div);
    var outputTheImpression = outputTheReportImpression(examId, div);
    var outputTheBody = outputTheReportBody(examId, div);

    /* populate the placeholder fields */
    outputTheStatus.html(getTheStatus.text());
    outputTheImpression.html(reportImpression);
    outputTheBody.html(reportBody);
}

/* show user the # of exams they have iterated through */
function showCurrentIndex(examId, index, totalExams) {
    var displayInfo = getTheIndexOfTheExam(examId);
    displayInfo.innerText = (index + 1) + "/" + totalExams;
}

function openExamModal(examId) {
    var examModal = $('#examModal' + examId);
    examModal.modal('toggle');
}

function isThereAnExam(inputValue) {
    return inputValue != null && inputValue != "";
}


function isThereTwoReports(reportOneId, reportTwoId) {
    return reportOneId != null
        && reportTwoId != null
        && reportOneId !== ""
        && reportTwoId !== ""
        && reportOneId !== reportTwoId;
}

/* make sure the current exam exists */
function isValidExam(index) {
    return index != -1;
}

function isPrevOrNextButtonClicked(action) {
    return action === "next" || action === "prev";
}

/* Increment the index + or - 1 */
function getNextExamIndex(index, action) {

    switch (action) {
        case "next":
            index = index + 1;
            break;
        case "prev":
            index = index - 1;
            break;
        default:
            break;
    }

    return index;
}

/* Increment the index - 1 */
function getPrevExamId(index, examIdArray) {
    return examIdArray[index - 1];
}

/* find location examId exists in the Exam ID array */
function getExamIndex(selectedExamId, examIdArray) {
    return jQuery.inArray(selectedExamId, examIdArray);
}

function getTheIndexOfTheExam(examId) {
    return document.getElementById('currentIndex' + examId);
}

function getReportOneId(examId) {
    return $('.' + examId + ' .left-side .fa-check-circle-o .reportId').text();
}

function getReportTwoId(examId) {
    return $('.' + examId + ' .right-side .fa-check-circle-o .reportId').text();
}

function getReportImpression(reportId) {
    return $('#impression' + reportId);
}

function getTheDashboardTable() {
    return document.getElementById('dashboard-table');
}

function getReportBody(reportOne) {
    return $('#report' + reportOne);
}

function getTheReportStatus(reportId) {
    return $('#reportStatus' + reportId);
}

function outputTheReportBodyDiff(examId) {
    return $('#reportDiff' + examId);
}

function outputTheReportImpressionDiff(examId) {
    return $('#impressionDiff' + examId);
}

function outputTheReportStatus(examId, div) {
    return $('#examModal' + examId + ' .reportStatus' + div);
}

function outputTheReportImpression(examId, div) {
    return $('#examModal' + examId + ' .reportImpression' + div);
}

function outputTheReportBody(examId, div) {
    return $('#examModal' + examId + ' .reportBody' + div);
}

function toggleArrow(examId) {
    $('#expand-details-icon-' + examId).toggleClass("fa-arrow-circle-up fa-arrow-circle-down");
}

/* Googles diff match patch */
function getTheDiff(string1, string2) {
    var dmp = new diff_match_patch();
    dmp.Diff_Timeout = 0;
    dmp.Diff_EditCost = 4;

    var ms_start = (new Date()).getTime();
    var d = dmp.diff_main(string1, string2);

    var ms_end = (new Date()).getTime();
    dmp.diff_cleanupEfficiency(d);
    return dmp.diff_prettyHtml(d);

}

/* dynamically populate the side by side reports and the diff text */
function selectReportLeftSide(examId, reportOneId) {

    var selectedReport = $('#leftIconLink' + reportOneId);

    if (isValidReportLink(selectedReport)) {
        var reportTwoId = getReportTwoId(examId);
        removeCheckedIcon(examId, '.left-side');
        addCheckedIcon(selectedReport);
        displayReportAndDiff(examId, reportOneId, reportTwoId);
    }
}

/* dynamically populate the side by side reports and the diff text */
function selectReportRightSide(examId, reportTwoId) {

    var selectedReport = $('#rightIconLink' + reportTwoId);

    if (isValidReportLink(selectedReport)) {
        var reportOneId = getReportOneId(examId);
        removeCheckedIcon(examId, '.right-side ');
        addCheckedIcon(selectedReport);
        displayReportAndDiff(examId, reportOneId, reportTwoId);
    }
}

function removeCheckedIcon(examId, className) {

    var checkedIcon = $('.' + examId + ' ' + className + ' .fa-check-circle-o');

    checkedIcon.removeClass('fa-check-circle-o');
    checkedIcon.addClass('fa-circle-o');
}

function addCheckedIcon(selectedReport) {
    selectedReport.removeClass("fa-circle-o");
    selectedReport.addClass("fa-check-circle-o")
}

function isValidReportLink(selectedReport) {
    return selectedReport.hasClass("fa-circle-o");
}

function copyToClipboardClickHandler(inputId) {

    var input = $("#" + inputId);

    if (isThereAnExam(input.val())) {
        input.focus();
        input.select();
        document.execCommand("copy");
    }
}

Conclusion

This is not an ideal solution. I much rather off-load the exam business logic into a separate controller action and view. To me, that would make the code far more readible and easier to maintain. However, sometimes a developer doesn’t have the luxury of ideal solutions.