0

I'm relatively new to web development, so this is probably a simple misunderstanding. I'm using an AJAX request to gather a list of used values within a specific range and then comparing it to a generated list of all possible values within that range to find the unused values.

I've tried using Lodash's _.difference() and the JavaScript Array filter() method, but they return the same results -- all values within the generated range -- which is leading me to believe it's related to the differing structures of the 2 arrays. These methods work when I create a test array like var used = ["0000000030000", "0000000030001"].

This is what the array's look like in the console: https://i.stack.imgur.com/ErwFC.jpg

The first array shows as [] until expanded; whereas, the other one shows the length of the array and values within?

// Will be set dynamically by subdepartment choice, used for testing at the moment.
var startRange = 30000;
var endRange = 39999;

// Pads the startRange and endRange to 13 digits with 0's for the AJAX request.
var startUPC = pad(startRange, 13);
var endUPC = pad(endRange, 13);

// AJAX request function to get all used UPC's within in range of numbers.
function GetNewPLU(callback) {
    $.ajax({
        url: "api/GetNewPLU",
        type: "GET",
        dataType: "json",
        data: { 'startUPC': startUPC, 'endUPC': endUPC },
        success: callback,
        error: function (error) {
            console.log(`Error ${error}`)
        }
    });
}

function SetNewPLU() {

    // Executes GetNewPLU AJAX request function
    var used = [];
    GetNewPLU(function (data) {
        for ($i = 0; $i < data.data.length; $i++) {
            used.push( data.data[$i].OBJ_TAB.F01 );
        }
    });

    var range = [];
    // Generates array of all numbers between range.
    for ($i = startRange; $i < endRange; $i++) {
            range.push( '00000000' + $i );
    };

    //var unused = used.filter(function (n) { return !this.has(n), new Set(data) });
    var unused = _.difference(range.toString(), used);

    console.log(used);
    console.log(range);
    console.log(unused);
}

SetNewPLU();

  • `used` is filled by the `GetNewPLU` callback and still empty when comparing `_.difference(range.toString(), used)` and logging `console.log(used);`. Have a look at [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) and/or the [MDN Using Promises guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises). – 3limin4t0r Aug 05 '19 at 20:21
  • I've checked out that first link before, which is where I got the idea to try and use call backs. I just thought maybe I was generating the array incorrectly, but I tested with async: false and it works, so I guess I'll have to look into promises. I was hoping it'd be as simple as implementing calls backs. Thank you! – user9430840 Aug 06 '19 at 14:38

1 Answers1

0

The reason all values are returned is simply due to the fact that used is still empty at the time of checking the difference. Moving the logic into the callback should resolve this issue.

function SetNewPLU() {
    GetNewPLU(function (data) {
        var used = [];
        for ($i = 0; $i < data.data.length; $i++) {
            used.push( data.data[$i].OBJ_TAB.F01 );
        }

        var range = [];
        for ($i = startRange; $i < endRange; $i++) {
            range.push( '00000000' + $i );
        };

        var unused = _.difference(range.toString(), used);

        console.log(used);
        console.log(range);
        console.log(unused);
    });
}

To avoid callback hell you are better of returning promises from your own functions.

function GetNewPLU() {
    return $.ajax({
        url: "api/GetNewPLU",
        type: "GET",
        dataType: "json",
        data: { 'startUPC': startUPC, 'endUPC': endUPC },
        error: function (error) {
            console.log(`Error ${error}`);
        }
    });
}

function SetNewPLU() {
    return GetNewPLU().then(function (data) {
        var used = [];
        for ($i = 0; $i < data.data.length; $i++) {
            used.push( data.data[$i].OBJ_TAB.F01 );
        }

        var range = [];
        for ($i = startRange; $i < endRange; $i++) {
            range.push( '00000000' + $i );
        };

        var unused = _.difference(range.toString(), used);

        console.log(used);
        console.log(range);
        console.log(unused);
    });
}

You could also use the ES6 syntax of async/await, to reduce the indention of the SetNewPLU function. Keep in mind that marking a function as async will result in a return value that is always a promise.

async function SetNewPLU() {
    var data = await GetNewPLU();

    var used = [];
    for ($i = 0; $i < data.data.length; $i++) {
        used.push( data.data[$i].OBJ_TAB.F01 );
    }

    var range = [];
    for ($i = startRange; $i < endRange; $i++) {
        range.push( '00000000' + $i );
    };

    var unused = _.difference(range.toString(), used);

    console.log(used);
    console.log(range);
    console.log(unused);
}

Note: The return value of $.ajax is an jqXHR object, that implements behaviour of a (jQuery) promise object. This object is thenable, meaning that the object implements the then method, accepting two callbacks. The first one for the success scenario and the second for failure. For this reason it should work when using await on the jQuery object. If this for some reason doesn't work, try to wrap the return value of the AJAX call in GetNewPLU into Promise.resolve before returning. This should convert the jQuery promise to a native JavaScript promise.

For more information about promises and async/await have a look at the following pages:

3limin4t0r
  • 19,353
  • 2
  • 31
  • 52