2011-11-30 3 views
0

У меня есть веб-страница с различными элементами (список ссылок и два блока выбора), связанный между ними. Нажатие на них может повлиять на один из других элементов, и все их значения способствуют обновлению значения, отображаемого на странице.AJAX JQuery: порядок выполнения событий

Таким образом, код таков:

$(document).ready(function() { 

    var someVar = ''; 

    $("select#size").bind('change', function() { 
     someVar = $(this).val(); 
     console.log('first'); 
    }); 

    my_change(); 
    console.log('second' + someVar); 
}); 

function my_change() { 

    $.getJSON("photos/change_product", {json_stuff}, function(data) { 
     var options = []; 
     for (var i = 0; i < data.length; i++) { 
      options.push('<option value="' + data[i].id + '">' + data[i].label + '</option>'); 
     } 
     $("select#size").trigger('change'); 
     $("select#options").html(options.join('')).trigger('change'); 
    }) 
}; 

}; 

Когда я загружаю страницу функция my_change называется. Он делает кое-что, а затем запускает change event на select-box. Мне нужно обновить значение, используя то, что находится внутри этого окна выбора, и только затем продолжить выполнение. Поэтому мне нужен этот код, чтобы напечатать «first», а затем «second» со значением переменной. На самом деле происходит то, что он печатает «второй» «первый».

Я думаю, это потому, что я выполняю асинхронные вызовы. Что я могу сделать?

ответ

1

«второй» console.log() вызывается первым, так как ожидает асинхронные $.getJSON() вызова для ответа от сервера перед обжигом его функции обратного вызова. Вы можете сохранить объект jqXHR переменной, а затем использовать это, чтобы запустить свой «второй» consone.log() с $.when():

$(function() { 

    var someVar = ''; 

    $("#size").on('change', function() {//on() is the same as bind() here 
     someVar = $(this).val(); 
     console.log('first'); 
    }); 

    //save the jQuery XHR object from your $.getJSON request 
    var jqXHR = my_change(); 

    //when the above jQuery XHR object resolves, it will fire the second console.log 
    $.when(jqXHR).then(function() { 
     console.log('second' + someVar); 
    }); 
}); 

function my_change() { 

    //here we return the jQuery XHR object for the $.getJSON request so we can run code once it resolves 
    return $.getJSON("photos/change_product", {json_stuff}, function(data) { 
     var options = []; 
     for (var i = 0; i < data.length; i++) { 
      options.push('<option value="' + data[i].id + '">' + data[i].label + '</option>'); 
     } 
     $("#size").trigger('change'); 
     $("#options").html(options.join('')).trigger('change'); 
    }) 
}; 

Вот документация $.when(): http://api.jquery.com/jquery.when

Быстрый боковой примечание: это, как правило, медленнее добавить тег-тип в селектор, особенно когда вы выбираете идентификаторы, поскольку это уже очень быстрый метод выбора элементов.

+0

он все еще печатает «второй», а затем «первый». кажется, что даже если событие 'change' запускается вручную внутри функции' my_change', оно затем фиксируется после, не знаю, когда. Мне нужно будет дождаться завершения изменения, чтобы я мог получить значение из выбранного – Carlo

+0

@Carlo. Я только что создал тест и, похоже, работает как ожидалось: http://apexeleven.com/stackoverflow/jquery.when /test.html (щелкните панель в нижней части страницы, чтобы запустить тест, который вы можете сделать несколько раз, если хотите). – Jasper

+0

вздох, действительно не знаю, что сказать. Я проверяю и перепроверяю свой код, и он выглядит (почти) тем же. На данный момент я думаю, что это может быть что-то действительно действительно глупое, но я не могу понять, что. Я вставил здесь весь код: http://jsfiddle.net/4V2RX/2/ Мне это выдает: второй, второй, первый размер, первые варианты 8 – Carlo

0

Любой код, который полагается на отклик getJSON, должен быть отправлен или вызван обратным вызовом getJSON.

Это для обратного вызова.

Следует отметить, что ваша функция my_change не будет иметь доступ к переменной someVar, поскольку она является локальной для обратного вызова ready().

Чтобы исправить это, переместите функцию my_change внутри обратного вызова ready().

или просто передайте функцию непосредственно my_change.

my_change(function() { 
    console.log('second' + someVar); 
}); 

И есть getJSON обратного вызова функции.

function my_change(func) { 

    $.getJSON("photos/change_product", {json_stuff}, function(data) { 
     var options = []; 
     for (var i = 0; i < data.length; i++) { 
      options.push('<option value="' + data[i].id + '">' + data[i].label + '</option>'); 
     } 
     $("select#size").trigger('change'); 
     $("select#options").html(options.join('')).trigger('change'); 

     func(); 
    }); 
} 
+0

Не похоже, что функция 'my_change()' пытается получить доступ к переменной 'someVar'. – Jasper

+0

@ Jasper: Это не так, но в первой строке моего ответа говорится, что любой код, который полагается на ответ, должен быть помещен в ... обратный вызов. Так что если 'call.log ('second' + someVar);' был помещен в обратный вызов, у него больше не будет доступа к 'someVar'. :) – RightSaidFred

2

Существует несколько способов сделать это.

Вы можете использовать jQuery $.when и вызвать console.log после завершения ответа ajax.

$(document).ready(function() { 

    var someVar = ''; 

    $("select#size").bind('change', function() { 
     someVar = $(this).val(); 
     console.log('first'); 
    }); 

    $.when(my_change()).then(function(){ 
      console.log('second' + someVar); 
    }); 
}); 

function my_change() { 

    return $.getJSON("photos/change_product", {json_stuff}, function(data) { 
     var options = []; 
     for (var i = 0; i < data.length; i++) { 
      options.push('<option value="' + data[i].id + '">' + data[i].label + '</option>'); 
     } 
     $("select#size").trigger('change'); 
     $("select#options").html(options.join('')).trigger('change'); 
    }) 
}; 

}; 

Или вы можете добавить аргумент обратного вызова к функции my_change(callback).

$(document).ready(function() { 

    var someVar = ''; 

    $("select#size").bind('change', function() { 
     someVar = $(this).val(); 
     console.log('first'); 
    }); 

    my_change(function(){ console.log('second' + someVar) }); 

}); 

function my_change(callback) { 

    return $.getJSON("photos/change_product", {json_stuff}, function(data) { 
     var options = []; 
     for (var i = 0; i < data.length; i++) { 
      options.push('<option value="' + data[i].id + '">' + data[i].label + '</option>'); 
     } 
     $("select#size").trigger('change'); 
     if(typeof callback !== 'undefined' && typeof callback === 'function') 
      callback(); 
     $("select#options").html(options.join('')).trigger('change'); 
    }) 
}; 

}; 
+0

большое спасибо. все еще не уверен, буду ли я использовать '$ .when' или обратный вызов. во всяком случае, на данный момент, я думаю, что мне больше не нужно связывать событие – Carlo

+0

извините, проверяя снова, что это решение не работает. используя $ .когда случается, что он сначала запускает внутри него код, а затем фиксирует событие «change». – Carlo

Смежные вопросы