0

I've seen many topics like this, some with pretty much the exact same title, but I'm still not finding a solution for what I'm attempting.

I basically have an HTML table that is getting data from 10 different sources. 9 of the sources I'm trying to push to an array and fund the sum, which will be one column in the table. And the other source is just a single external query result.

I'm running into problems when they take too long to load and the table has already populated.

I tried a timeout function but it doesn't seem to work even then. I'm also having issues with the table showing 10 commas separated values and not a sum, even when I add a variable =0 and then do source1+= variable for each of the sources.

Heres what I have so far, I Some of the letterers in the code are just random and a placeholder to show the structure. But this is the basic setup. I've only included 2 out of the 9 functions to save space, but its pretty much similar to the first two, 3..4..5 etc.

At a loss here, any help would be awesome and I thank you all for your valuable time.

 /* HTML */

<table id="AA"> <caption>title<span id="totalValue">0</span></caption>
<tr>
<th>L</th>
<th>L Qty.</th>
<th>W</th>
<th class="value">Value</th>
<th>some text</th>
<label for="CD">
    </label>
    <input id="img" type="hidden" value="somedatahere" size="60" />
   </tr>
</table>

//and heres the separate js 
var sumqholder = 0;

$('#Form').submit(function(event) {
   event.preventDefault();

   $('#results').html('loading...');

   var AB = $('#CD').val();

   A.H.call(function(err, J) {
  A.I.call(function(err, K) {

   var EF = $('#EF').val();


   A.G.call(EF, function(err, G) {
    var results = '<b>--:</b> ';
    results += G.round(5);
    sumq += G;
    $('#results').html(results);

   });
  });

  $('#results2').html('loading...');

  var AB = $('#CD').val();

  A.H.call(function(err, J) {

     A.I.call(function(err, K) {

      var EF = $('#EF').val();


      A.G.call(IA, function(err, G) {
       var results2 = '<b>--:</b> ';
       results2 += G.round(5);
       sumq += G;
       $('#results2').html(results2);

      });
     });

     var sumq = sumqholder;
     var L = [{
      M: O,
      quantity: sumq
     }, {
      P: " ",
      quantity: x
     }];
     var totalValue = 0;
     $(document).ready(function() {
      refresh();
     });

     function refresh() {
      $("#AA").find("tr:gt(0)").remove();
      totalValue = 0;
      L.forEach(function(L) {
       sendRequest(L.M, L.quantity);
      });
     }

     function sendRequest(M, L) {
      var url = " " + M + "/";
      $.get(url, function(data) {
       addRow(data[0], quantity);
      });
     }

     function addRow(data, quantity) {
      var value = data.W * quantity;
      totalValue += value;
      var row = '<tr>';
      row += '<td>' + data.I + '</td>';
      row += '<td>' + quantity + '</td>';
      row += '<td>' + data.I + '</td>';
      row += '<td>' + value.toFixed(2) + '</td>';
      row += '<td>' + data.O + '</td>';
      row += '</tr>';
      $('#AA tr:last').after(row);
      updateTotalValue();
     }

     function updateTotalValue() {
      $("#totalValue").text(totalValue.toFixed(6));
     }
JDOE
  • 43
  • 5

2 Answers2

0

If i got this right, you're having problems processing data because the source is coming from 10 different async calls right? If that's the case, have each call finish off by calling a checking function.

var flag = 0;

function checkLoaded()
{
    if(flag == 9){
        doDataProcessing();
    }else{
        flag++;
    }
}

This way, each call will end calling checkLoaded(); and if its the 10th one, flag will have incremented 9 times therefore we can already assume we can proceed to data processing.

  • oh, derp ya know what that might just work. when i get back to my desktop I will try this. Ill make sure to mark this as answered if it works. thank you. – JDOE Dec 25 '17 at 19:25
0

This is precisely the kind of scenario that promises were designed to simplify. They will help you avoid "callback hell" and manage errors.

First, with reference to How do I Convert an Existing Callback API to Promises?, promisify all methods that accept a callback :

A.G.callAsync = function(val) {
    return new Promise(function(resolve, reject) {
        A.G.call(val, function(err, x) {
            err ? reject(err) : resolve(x);
        });
    });
};
A.H.callAsync = function() {
    return new Promise(function(resolve, reject) {
        A.H.call(function(err, x) {
            err ? reject(err) : resolve(x);
        });
    });
};
A.I.callAsync = function() {
    return new Promise(function(resolve, reject) {
        A.I.call(function(err, x) {
            err ? reject(err) : resolve(x);
        });
    });
};

jQuery's $.get() already returns a promise therefore doesn't need to be promisified.

Then, everything else can be done inside a $(document).ready(function() {...}) structure, something like this :

$(document).ready(function() {
    $('#Form').submit(function (event) {
        event.preventDefault();

        $('#results').html('loading...');
        // promise chain for the first A.H(), A.I(), A,G() sequence.
        var promise1 = A.H.callAsync().then(function(J) {
            return A.I.callAsync();
        }).then(function(K) {
            return A.G.callAsync($('#AB').val());
        }).then(function(G) {
            $('#results').html('<b>--:</b> ' + G.round(5));
            return G; // the chain delivers this value
        });

        // promise chain for the second A.H(), A.I(), A,G() sequence.
        var promise2 = promise1.then(function() {
            $('#results2').html('loading...');
            return A.H.callAsync().then(function(J) {
                return A.I.callAsync();
            }).then(function(K) {
                return A.G.callAsync($('#EF').val());
            }).then(function(G) {
                $('#results2').html('<b>--:</b> ' + G.round(5));
                return G; // the chain delivers this value
            });
        });

        Promise.all([promise1, promise2]) // aggregate promise1 and promise2
        .then(function(G_values) { // G_values is an array containing the `G` values delivered by promise1 and promise2.
            var sumq = G_values.reduce(function(runningTotal, val) {
                return runningTotal + val;
            }, 0);
            var L = [
                { 'M': O, 'quantity': sumq }, // what is O?
                { 'P': ' ', 'quantity': x } // where's 'M'? what is 'x'
                // ...
            ];
            $("#AA").find("tr:gt(0)").remove();
            return Promise.all(L.map(sendRequest)) // aggregate all the promises returned by sendRequest()
            .then(function(values) { // `values` is an array of values delivered by the promises returned from sendRequest().
                var totalValue = values.reduce(function(runningTotal, val) {
                    return runningTotal + val;
                }, 0); // ie values[0] + values[1] + ...
                $("#totalValue").text(totalValue.toFixed(6));
            });

            function sendRequest(item) {
                var url = ' ' + item.M + '/';
                var $tr = $('<tr/>').insertAfter('#AA tr:last'); // inserting here ensures the <tr>s are in the same order as the objects in `L`.
                return $.get(url)
                .then(function(data) {
                    return addRow(data[0], item.quantity, $tr); // deliver addRow's return value to Promise.all() above
                });
            }
            function addRow(data, quantity, $tr) {
                var value = data.W * quantity;
                var cells = '<td>' + data.I + '</td>'
                + '<td>' + quantity + '</td>'
                + '<td>' + data.I + '</td>'
                + '<td>' + value.toFixed(2) + '</td>'
                + '<td>' + data.O + '</td>';
                $tr.html(cells);
                return value; // for on-screen consistency, you may choose to `return Number(value.toFixed(2))`
            }
        }).catch(function(err) {
            console.error(err);
        });
    });
});

I'm not sure that's 100% what you want but it should give you a good idea how to solve an asynchronous javascript problem.

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
  • Wow you put a TON of effort and quality into that post that I sadly dont know if Ill be able to replicate haha. The code Im using now is something Ive modified from something else with my very limited JS knowledge. .. Regardless, I will put just as much effort into trying to implement your suggestion and make sure your effort is not in vain.. THANK YOU! – JDOE Dec 26 '17 at 12:16
  • Well it looks like all I really need to do is something like, if m >0{ execute the table function. I tried wrapping it in that but it still didnt work. then i tried doing if m ! => 0 { do timeout refresh. but it still not working. and roamer, i only showed about 5% of the code, i have so many other calls in there i dont think your fix would work. this code isnt exactly the best. – JDOE Dec 26 '17 at 13:47
  • EDIT looks like I got it all to load fine in the table, but now its not doing the sum correclty, im adding multiple values togeth (A+B+C+D..) and making a variable for the table to call. var x = (A+B+C+D..) , but when the table loads it, its not a sum its all of the values together in a line. – JDOE Dec 26 '17 at 14:12
  • @JDOE, what I have given you here isn't so much *a* way but *the* way, these days, to handle asynchronism. A large code base will indeed take some time to convert, more so if you are learning about Promises as you go. I assure you, it will be a good investment. – Roamer-1888 Dec 26 '17 at 14:13
  • If `A+B+C+D` concatenates instead of adding, then A, B, C, D are likely to be strings. – Roamer-1888 Dec 26 '17 at 14:14
  • ok wow, i think i finally got it, had to add Number() so they they didnt concat. Still dont think i could have done it without you guys. – JDOE Dec 26 '17 at 14:21
  • And yes roamer, you're definitely right, as this page is taking exponentially longer to load the more i add, even though its now working. – JDOE Dec 26 '17 at 14:58