Вернуть значение GET и сохранить его в переменной в JS - PullRequest
2 голосов
/ 26 февраля 2020

Обратите внимание, что я новичок в JS, поэтому ожидайте любую аберрацию, которую вы можете себе представить.

При этом я пытаюсь создать функцию в JS. Он состоит из трех частей, но конечной целью является заполнение select некоторыми внешними данными.

Первая - это GET. Здесь я вызываю внешний API, запрашивая общее количество профилей. Кажется, все работает нормально, но всякий раз, когда я делаю console.log(totalProfiles) вне функции, его значение кажется неопределенным. Я попытался добавить return в конце, но это не было решением.

var billingArray = [];
var billingProfiles = [];
var billingSelect = document.getElementById('billingSelect');
(function(){
    $.ajax({
        url: url,
        method: 'GET',
        crossDomain: true,
        withCredentials: true,
        dataType: 'JSON',
        headers: {
            'Authorization': 'Basic '+token,
        }
    })
    .done(function(response) { billingArray.push(response); var totalProfiles = billingArray[0]['total_count']; return totalProfiles; })
    .fail(function(jqXHR, textStatus, errorThrown) { console.log(textStatus); });
});

С помощью totalProfiles я бы назвал один и тот же URL, на этот раз, чтобы все профили сохранялись в массиве:

(function(totalProfiles){
    $.ajax({
        url: url+totalProfiles,
        method: 'GET',
        crossDomain: true,
        withCredentials: true,
        dataType: 'JSON',
        headers: {
            'Authorization': 'Basic '+token,
        }
    })
    .done(function(response) { billingProfiles.push(response); })
    .fail(function(jqXHR, textStatus, errorThrown) { console.log(textStatus); });
});

Последняя часть состоит из заполнения select с помощью for:

function(billingprofiles) {
    for (var i = 0; i < billingProfiles.length(); i++) {
        var billingProfileId = billingProfiles[i]["ngcp:billingprofiles"]["id"];
        var billingProfileName = billingProfile[i]["ngcp:billingprofiles"]["name"];

        var opt = document.createElement("option");
        opt.value() = billingProfileId;
        opt.textContent() = billingProfileName;
        dropdown.appendChild(opt);
    }
});

Проблема здесь в том, что я не знаю, как вывести totalProfiles из функции, поэтому всякий раз, когда процесс достигает второго, происходит сбой из-за переменная не определена.

Это все, и где вы можете ожидать те аберрации, о которых я говорил ранее. Я думал, что это сработает, но я начинаю подозревать, что то, как я собираюсь это сделать, тоже может быть частью проблемы:

var billingArray = [];
var billingProfiles = [];
var billingSelect = document.getElementById('billingSelect');
var totalProfiles;

//Fetch total number of profiles
(function() {
  $.ajax({
    url: url,
    method: 'GET',
    crossDomain: true,
    withCredentials: true,
    dataType: 'JSON',
    headers: {
      'Authorization': 'Basic ' + token,
    }
  }).done(function(response) {
    billingArray.push(response);
    var totalProfiles = billingArray[0]['total_count'];
    return totalProfiles;
  }).fail(function(jqXHR, textStatus, errorThrown) {
    console.log(textStatus);
  });
})().done(function(totalProfiles) {
  $.ajax({
    url: url + totalProfiles,
    method: 'GET',
    crossDomain: true,
    withCredentials: true,
    dataType: 'JSON',
    headers: {
      'Authorization': 'Basic ' + token,
    }
  }).done(function(response) {
    billingProfiles.push(response);
  }).fail(function(jqXHR, textStatus, errorThrown) {
    console.log(textStatus);
  });
})().done(function(billingprofiles) {
  for (var i = 0; i < billingProfiles.length(); i++) {
    var billingProfileId = billingProfiles[i]["ngcp:billingprofiles"]["id"];
    var billingProfileName = billingProfile[i]["ngcp:billingprofiles"]["name"];

    var opt = document.createElement("option");
    opt.value() = billingProfileId;
    opt.textContent() = billingProfileName;
    billingSelect.appendChild(opt);
  }
}).fail(function(jqXHR, textStatus, errorThrown) {
  console.log(textStatus);
});

Несколько замечаний, чтобы лучше объяснить, что и почему я это сделал: 1 Перед каждым .done мне приходилось писать (), чтобы избежать этой ошибки

(промежуточное значение). Не является функцией

Ошибка, которую я получаю прямо сейчас, возникает в .done(function(totalProfiles) {:

Uncaught TypeError: Невозможно прочитать свойство 'done' из неопределенного

Ответы [ 2 ]

2 голосов
/ 26 февраля 2020

Вы описываете цепочку асинхронных операций. Обещания отлично подходят для этого. Deferred объект, который вы получаете от ajax, является обещанием (сейчас), поэтому вы можете сделать это, возвращая цепочку от каждой функции к следующей:

$.ajax({
    // ...
})
.then(billingArray => billingArray[0]['total_count']) // *** Return the count
.then(totalProfiles => $.ajax({ // *** Return the promise for the billing profiles
     // ...options using `totalProfiles`...
})
.then(billingProfiles => {
    // ...use the billing profiles here
})
.catch(() => {
    // ...handle/report failure
});

Примечание как каждый обработчик then преобразует то, что проходит через него, и в ситуации, когда ему нужна информация, доступная только асинхронно, он возвращает обещание из ajax; результат будет передан следующему then обработчику.

1 голос
/ 26 февраля 2020

Это приблизит вас:

const billingSelect = document.getElementById('billingSelect');

// This is an IIFE that gets executed immediately on page load

(function(){
    $.ajax({
        url: url,
        method: 'GET',
        crossDomain: true,
        withCredentials: true,
        dataType: 'JSON',
        headers: {
            'Authorization': 'Basic '+token,
        }
    })

  // call your function in the done handler, and pass the data in

    .done(response => 
       build({billingprofiles: response, totalProfiles: response['total_count']}))
    .fail(function(jqXHR, textStatus, errorThrown) { console.log(textStatus); });
});

// your function gets called from the .done handler
// with the data it needs

function build({billingprofiles, totalProfiles}) {

    // use const everywhere. You rarely need variables.
    // use map to transform the data to get the shape you need

    // console.log(billingprofiles) // uncomment to check the shape

    const profiles = billingprofiles.map(profile => ({
        id: profile["ngcp:billingprofiles"]["id"],
        name: profile["ngcp:billingprofiles"]["name"]
    }))

   // console.log(profiles) // uncomment to check the shape

   // Use forEach when you need a side-effect, like DOM element creation
   // but only for that. For data transform, use map, filter and reduce.

   profiles.forEach(profile => {
     const opt = document.createElement("option");
     opt.value() = profile.id;
     opt.textContent() = profile.name;
     dropdown.appendChild(opt);
   })
}
...