Как ограничить вызов ajax в области с предоставленным параметром? - PullRequest
0 голосов
/ 25 апреля 2020

Я пытаюсь «заполнить» выбор в форме на основе сохраненного значения (массива): city_selector_vars. Это сохраненное значение показывает правильные значения (см. Код ниже).

I l oop через этот массив и попытайтесь получить города (get_states) для определенного stateCode. Я передаю stateCode в качестве значения в функцию.

Если я зарегистрирую state_data.country_code до $.post, я получу ожидаемый доход. Если я регистрирую state_data.country_code внутри $.post, это не всегда совпадает с переданным кодом страны. Я думаю, что это как-то связано с областью действия, но мои знания недостаточно хороши, чтобы понять это.

/**
 * city_selector_vars
 * [
 *      'countryCode' => 'NL',
 *      'stateCode' => 'NL-FL',
 *      'cityName' => 'A name'
 * ]
 * [
 *      'countryCode' => 'BE',
 *      'stateCode' => 'BE-BR',
 *      'cityName' => 'Another name'
 * ]
 */
if ( true === Array.isArray(city_selector_vars) ) {
    for (i = 0; i < city_selector_vars.length; i++ ) {
        get_states(city_selector_vars[i].countryCode, (response)=> {
            // console.log(response);
        });
    }
}

function get_states(countryCode, callback) {
    const state_data = {
        action: 'get_states_call',
        country_code: countryCode
    };
    // console.log(state_data.country_code) shows correct country code
    $.post(ajaxurl, state_data, (response)=> {
        // here the wrong response first shows
        // state_data.country_code is not always the same as state_data.country_code
        callback(response);
    });
}
function get_states_call( $country_code = false ) {
    // $country_code = always false, even though it is passed
    if ( false == $country_code ) {
        if ( isset( $_POST[ 'country_code' ] ) ) {
            // here it sometimes picks up the incorrect value
            $country_code = $_POST[ 'country_code' ];
        }
    }
    // code removed, since depends on code above
    $items = [];
    echo json_encode( $items );
    die();
}

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

Ответы [ 2 ]

1 голос
/ 25 апреля 2020

Из вашего кода кажется, что вы реализуете функцию для запроса Wordpress данных.

Я не думаю, что ваша проблема связана с переменной областью действия - это скорее проблема asyn c функции . Вы отправляете один AJAX запрос на страну - каждый запрос отправляется на сервер «индивидуально», обрабатывается сервером, и ответ возвращается. Ничто не гарантирует , что ответ приходит в том же порядке, в котором были отправлены запросы.

Учтите это:

const arr = []

function getSingleItem(id) {
  fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
    .then(response => response.json())
    .then(json => {
      console.log(json.id)
    })
}

function getAllItems() {
  for (let i = 1; i < 10; i++) {
    getSingleItem(i)
  }
}

getAllItems()

В консоли видно, что ответы не приходят в том порядке, в котором были отправлены запросы (json.id на самом деле является действующим числом от 1 до i - они должны быть в порядке).

Вы должны позаботиться о заказе:

const arr = []

function getSingleItem(id) {
  return fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
    .then(response => response.json())
    .then(json => {
      return json.id
    })
}

async function getAllItems() {
  for (let i = 1; i < 10; i++) {
    const r = await getSingleItem(i)
    arr.push(r)
  }
  console.log(arr)
}

getAllItems()

Установив async await в функциях, я могу быть уверен, что ответы отображаются в том порядке, в котором были отправлены запросы. (await не «пропускает» for() l oop до go дальше, пока не придет ожидаемый ответ - что-то вроде синхронного кода.)

In в этом случае я использую функцию fetch(), которая возвращает объект Promise - объект, который можно ожидать редактировать в другой моей функции.

ВАШ КОД

Ваш Javascript код можно изменить:

/**
 * city_selector_vars
 * [
 *      'countryCode' => 'NL',
 *      'stateCode' => 'NL-FL',
 *      'cityName' => 'A name'
 * ]
 * [
 *      'countryCode' => 'BE',
 *      'stateCode' => 'BE-BR',
 *      'cityName' => 'Another name'
 * ]
 */
async function get_all_state(city_selector_vars) {
  if (true === Array.isArray(city_selector_vars)) {
    // preparing the response array
    const response_states = []
    for (i = 0; i < city_selector_vars.length; i++) {
      // try - catch to handle errors
      try {
        // await the response
        const d = await get_states(city_selector_vars[i].countryCode);
        // add response to the response array
        response_states.push(d)
      } catch (err) {
        // handle error
        console.log(err)
      }
    }
    // return the array - in order!
    return response_states
  }
}

function get_states(countryCode, callback) {
  const state_data = {
    action: 'get_states_call',
    country_code: countryCode
  };
  // console.log(state_data.country_code) shows correct country code

  // returning a Promise object, so await works in the other function
  return new Promise((resolve, reject) => {
    $.post(ajaxurl, state_data, (response) => {
      // here the wrong response first shows
      // state_data.country_code is not always the same as state_data.country_code
      // resolving the Promise when the response arrives
      resolve(response)
    });
  })


}

В вашем измененном коде Promise должен был быть явно создан (помните - fetch() возвращает Promise?), Поэтому он может быть обработан asyn c -await .

Я думаю, что фрагмент должен работать как есть, но если нет, то требуется только небольшая отладка:)

WORDPRESS NOTE

Если вы отправляете JSON с Wordpress, рекомендуется использовать функцию wp_send_json().

Подробнее: https://developer.wordpress.org/reference/functions/wp_send_json/

0 голосов
/ 27 апреля 2020

Что касается функции admin_post_edit_load_states, я думаю, Promise.all является правильным подходом:

function admin_post_edit_load_states() {
    if (true === Array.isArray(city_selector_vars)) {
        // preparing the response array
        const response_states = []
        for (i = 0; i < city_selector_vars.length; i++) {
            // try - catch to handle errors
            try {
                // await the response
                const d = get_states(city_selector_vars[i].countryCode);
                // add response to the response array
                response_states.push(d)
            } catch (err) {
                // handle error
                console.log(err)
            }
        }
        console.log(response_states);

        Promise.all(response_states).then(function(jsonResults) {
            var instance_count = 0;
            for (i = 0; i < jsonResults.length; i++) {
                var obj = JSON.parse(jsonResults[i]);
                var len = obj.length;
                var $stateValues = '';
                var select_state = $('select[name*="row-' + instance_count + '"][name*="stateCode"]');
                var stored_state = city_selector_vars[instance_count].stateCode;
                select_state.fadeIn();
                for (j = 0; j < len; j++) {
                    $selected = '';
                    var state = obj[j];
                    var current_state = state.country_code + '-' + state.state_code;
                    if (current_state === stored_state) {
                        $selected = ' selected="selected"';
                    }
                    var selected = $selected;
                    $stateValues += '<option value="' + state.country_code + '-' + state.state_code + '"' + selected + '>' + state.state_name + '</option>';
                }
                select_state.append($stateValues);
                instance_count++;
            }
        });
    }
}

Это должно сохранить исходный порядок, будучи асинхронным. Обратите внимание, что мы здесь делаем:

Сначала мы заполняем массив response_states обещаниями (каждый вызов get_states возвращает обещание). Затем Promise.all(response_states) создает новое обещание, которое будет разрешено после разрешения всех обещаний в массиве response_states. Наконец, параметр jsonResults представляет собой массив, содержащий соответствующее значение для каждого разрешенного обещания в массиве response_states.

Давайте посмотрим, работает ли оно.

...