Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Data is being cleared in the wrong order

So this has got me stuck all day, I’m building out a simple noticeboard due to a infrastructure change and I won’t be able to access a database directly. Fortunately the application (ManageEngine ServiceDesk) has an API that allows me to get the data I need. Unfortunately, I can’t use Javascript to access the API because the just don’t support it (I have tried) so I’m using python. The python side of this works fine, I am able to get all the data I need on that side.

The problem is I need to make several calls to the python side of things because the first call gets me the list of jobs according to my criteria, this works fine. Then I have to iterate over these jobs to make another call because I need to get approval status of each of the jobs. This also works fine, I console.log() the the info I need and it is displayed perfectly. If I don’t clear the data fields (midCollectionData, etc) the site works fine but it keeps doubling up. So I need to clear them, but when I do the data either doesn’t display at all or it doesn’t display on the first run, but the second run works fine. Without requesting the approval data this all works fine (and is the current version being run) but we want to have an icon showing approval status and I believe that the issue is that I need to use async/await (otherwise the data is mixed up and isn’t sorted correctly or the returned approval data is the promise and not the data, it has taken me a while since I’m not a professional).

Does anyone know what I need to do to make sure the data is cleared at the start of each run and that the data is written at the end of each run? Any help will be greatly appreciated. Also if you have any tips for improving code readability/efficiency that would be wonderful!

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Thanks!

"use strict";

// Set up some empty variables for the list of jobs (as HTML divs) are put in. This needs to be global for all the relevant functons to access.
let midCollectionData = "";
let senCollectionData = "";
let midApprovalData = "";
let senApprovalData = "";

// Same as above, but for the information at the bottom of the screen.
let infoArray = new Array;

// After the page is fully loaded, start all the functions.
$(document).ready(function() {
    startApp();
});

// Start all the functions required to run the page.
function startApp() {
    updateClock();
    getData();
}

// The clock at the top right
function updateClock() {
    var d = new Date(); // Get the date (from the system clock).
    var s = ""; // Var to write a time into in a human readable format.
    s += ((d.getHours() + 11) % 12 + 1) + ":"; // Get just the hours, add 11 and devide all that by 12. Take what is left over and add one. This converts 24hr time to 12hr time. Don't worry I did the math, it checks out.
    s += (10 > d.getMinutes() ? "0" : "") + d.getMinutes(); // Get the minutes and make it always display a leading zero.
    $("#clock").text(s); //bMake the clock element display the time we just formatted.
    $("#date").text(d.toDateString()); // Make the date element display the date we just formatted.
    setTimeout(updateClock, 1000); // do it all again in 1000 milliseconds.
}

// Get the data from helpdesk using fetch()
function getData() {
    fetch('/get-data') // Call the "get-data" function on the serverside python script
        .then(response => response.json()) // Take the full response and store it in an object in a json structure
        .then(data => populate(data))
        .catch(error => console.error(error)); // Log any errors to the console
    setTimeout(getData,10000) // Do it all again in 10 seconds
}

// Get the approval status of each job as this information is not provided when getting info on all jobs.
async function getApproval(jobid) {
    let response = await fetch(`get-approval/${jobid}`);
    let data = await response.json();
    if (data.request.approval_status != null) {
        return new Promise((resolve, reject) => {
            resolve(data.request.approval_status.name);
        })
    }
    else {
        return new Promise((resolve, reject) => {
            resolve("null");
        })
    }
}

// Populate the tables with the data from getData()
async function populate(data) {
    await clearData();
    await $.each(data.requests, async function(i, item) { // Loop through ONLY the requests items of the response data from the server
        let approvalData;
        await getApproval(item.id)
            .then(function (result) {
                approvalData = result;
            });
        makeItem(item.site.name, item.status.name, item.requester.name, item.id, approvalData); // Call makeItem() and pass the site, status, requester, and ID of the current item as arguments
    });
    await updateData(); // After the jobs are written (as html) to the variables, write them into the grid
}

function makeItem(campus, type, name, id, approval) { // Add the job's information to the correct list
    let icon = "";
    switch (approval) {
        case "null":
            icon = "";
            break;
        case "Approved":
            icon = "<span class='material - symbols - outlined'>done</span>";
            break;
        case "Pending Approval":
            icon = "<span class='material - symbols - outlined'>schedule</span>";
            break;
        case "Rejected":
            icon = "<span class='material - symbols - outlined'>close</span>";
            break;
    }
    // Check the site and status and then add to the data to that list as a div in html format
    if (campus == "site1" && type == "Collection") {
        midCollectionData += `<div class='grid-item'>${name} (${id})</div>`;
        return;
    }
    if (campus == "site2" && type == "Collection") {
        senCollectionData += `<div class='grid-item'>${name} (${id}) ${icon}</div>`;
        return;
    }
    if (campus == "site1" && type == "Leadership") {
        midApprovalData += `<div class='grid-item'>${name} (${id})</div>`;
        return;
    }
    if (campus == "site2" && type == "Leadership") {
        senApprovalData += `<div class='grid-item'>${name} (${id}) ${icon}</div>`;
        return;
    }
    console.log(`${name}, ${id}, ${campus}, ${type}, ${approval}, ${icon} slipped through the cracks`); // Log any items to console that don't get sorted and display all infomation so we can investigate
    return;
}

function clearData() { // Clear the data variables to stop double-ups of data
    midCollectionData = "";
    senCollectionData = "";
    midApprovalData = "";
    senApprovalData = "";
}

// Find the correct grid using the div's id and write the html data to it
function updateData() {
    $("div.grid-item").remove(); // Clear the grids to stop double-ups of data
    $("#Middle-Collection").html(midCollectionData);
    $("#Senior-Collection").html(senCollectionData);
    $("#Middle-Approval").html(midApprovalData);
    $("#Senior-Approval").html(senApprovalData);
}

I have tried moving the clearData() function around to diffrent places and making it an async (though I didn’t expect this to actually work) but I can’t find how to make it run in a certain order.

>Solution :

Most likely this function is the culprit:

// Populate the tables with the data from getData()
async function populate(data) {
    await clearData();
    await $.each(data.requests, async function(i, item) { // Loop through ONLY the requests items of the response data from the server
        let approvalData;
        await getApproval(item.id)
            .then(function (result) {
                approvalData = result;
            });
        makeItem(item.site.name, item.status.name, item.requester.name, item.id, approvalData); // Call makeItem() and pass the site, status, requester, and ID of the current item as arguments
    });
    await updateData(); // After the jobs are written (as html) to the variables, write them into the grid
}

When working with async functions, it’s best to avoid functions as ‘each’ or ‘foreach’ because they don’t really do what you think.

Usually you just want for..of loops:

async function populate(data) {
  await clearData();

  for(const item of data.requests) {   
    const approvalData = await getApproval(item.id);
    makeItem(
      item.site.name,
      item.status.name,
      item.requester.name,
      item.id,
      approvalData
    );
  }

  await updateData();
}

I’d also really recommend you don’t use makeItem to update a global variables and consume them from updateData. Things will work more obvious and predictable if makeItem returns data, and updateData receives data as an argument.

Lastly you’re doing some strange stuff in the getApproval function. Avoid new Promise as much as you can. It can be rewritten this way:

async function getApproval(jobid) {
    const response = await fetch(`get-approval/${jobid}`);
    const data = await response.json();
    if (data.request.approval_status !== null) {
       return data.request.approval_status.name;
    } else {
       return null;
    }
}

Or even more compact

async function getApproval(jobid) {
    const response = await fetch(`get-approval/${jobid}`);
    const data = await response.json();
    return data.request.approval_stats?.name ?? null;
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading