-2

I am trying to multiply two arrays. One array is getting its values by $('#element').val();, the other one by fetching the results of a GET Request.

Console output:

enter image description here

Here is my code:

$("#sendeS1").click(function() {
  var i = 1;
  var Q_Values = [];
  var G_Values = [];
  var R_Values = [];

  for (i; i <= 20; i++) {
    $.get("bewertung/get/weight/" + i, function(weight) {
      Q_Values[i - 1] = $('#startup_1').find('.' + i).val();
      G_Values[i - 1] = weight;
      R_Values[i - 1] = Q_Values[i - 1] * G_Values[i - 1];
      console.log("Q:" + Q_Values);
      console.log("G:" + G_Values);
      console.log("R:" + R_Values);
    });

    $.ajax({
      url: '/bewertung/1',
      type: 'POST',
      data: {
        startup_id: '1',
        user_id: localStorage.getItem("userid"),
        question_id: i,
        wert: G_Values[i - 1]
      }
    });
  }
});
chazsolo
  • 7,873
  • 1
  • 20
  • 44
Aleks
  • 101
  • 1
  • 12
  • Values returned via `val()` are always strings. You need to make them numbers if you want to do math with them. The way to do that is explained in [the answers to this question](https://stackoverflow.com/q/1133770/215552). – Heretic Monkey Jun 21 '17 at 19:28
  • There is an asynchronous race condition among the `$.get's` that are all executing at the same time. A loop will not space them out. It is OK to execute all the gets simultaneously but you need to wait until all gets have finished for the data to be "ready". Reading some asynchronous and/or ajax programming tutorials may help, as would using Promises and `Promise.all`. – Paul Jun 21 '17 at 19:31

1 Answers1

1

Do it like this:

  • Use let for the variable i in the for block, so it is a separate variable that can still be referenced when the loop has completed and you are only then getting the responses from the get calls

  • Use + to convert val() to a number (although in your case it is not absolutely necessary, since the multiplication with the the conversion on-the-fly)

Code:

$("#sendeS1").click(function () {
    var Q_Values = [];
    var G_Values = [];
    var R_Values = [];

    for(let i = 1; i <= 20; i++){
        $.get("bewertung/get/weight/"+i, function (weight) {
            Q_Values[i-1] = +$('#startup_1').find('.'+i).val();
            G_Values[i-1] = weight;
            R_Values[i-1] = Q_Values[i-1] * G_Values[i-1];
            console.log("Q:"+Q_Values);
            console.log("G:"+G_Values);
            console.log("R:"+R_Values);
        });
        //...etc

Warning: the arrays will not yet have values when the for loop has completed, so don't assume you have all data right after the loop. See How do I return the response from an asynchronous call? on several ways to deal with that.

One way that is not the nicest code, but the easiest to understand, is to use a count down, so you know when you have all data, and then call a function that will do the further processing:

$("#sendeS1").click(function () {
    var Q_Values = [];
    var G_Values = [];
    var R_Values = [];
    var countDown = 20;

    for(let i = 1; i <= 20; i++){
        $.get("bewertung/get/weight/"+i, function (weight) {
            Q_Values[i-1] = +$('#startup_1').find('.'+i).val();
            G_Values[i-1] = weight;
            R_Values[i-1] = Q_Values[i-1] * G_Values[i-1];
            console.log("Q:"+Q_Values);
            console.log("G:"+G_Values);
            console.log("R:"+R_Values);
            countDown--;
            if (countDown == 0) processResults(Q_Values, G_Values, R_Values);
        });
        //...etc

But I would really advise to look into Promises. That really is the way to go. Luckily jQuery $.get returns a promise, and those promises can be passed to $.when, which will call its then method when all these promises have been fulfilled. (See also What does $.when.apply($, someArray) do?).

$("#sendeS1").click(function () {
    var Q_Values = [];
    var G_Values = [];
    var R_Values = [];
    var promises = [];

    for(let i = 1; i <= 20; i++){
        promises.push($.get("bewertung/get/weight/"+i, function (weight) {
            Q_Values[i-1] = +$('#startup_1').find('.'+i).val();
            G_Values[i-1] = weight;
            R_Values[i-1] = Q_Values[i-1] * G_Values[i-1];
            console.log("Q:"+Q_Values);
            console.log("G:"+G_Values);
            console.log("R:"+R_Values);
        }));
        //...etc
    }
    $.when.apply($, promises).then(function() {
        // all is done, process the results here ...
    });

This code could be further improved so that each promise would resolve to its own value, and not yet push the product into an array, but that is something you can maybe look into yourself as an exercise.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • What about the async race condition? As shown it isn't too bad, but if he wants to use these arrays for anything important, he needs to have a way to know that the array is "ready". And his posted code doesn't do that. – Paul Jun 21 '17 at 19:34
  • Indeed that is also an issue. But since the question does not deal with that... I just added a warning at the end. – trincot Jun 21 '17 at 19:36
  • This does the job. Thanks trincot! But now the async race is the pain. Have you got a quick solution for this? I am struggling to understand your links. – Aleks Jun 21 '17 at 19:49
  • You're welcome. I added some code examples on how to treat the asynchronous result. – trincot Jun 21 '17 at 20:41