coldfusion cfajaxproxy callbackhandler вызывается слишком много раз

Я новичок в использовании cfajaxproxy, я пытаюсь выбрать несколько флажков, затем перебрать все отмеченные флажки и сохранить результаты в базе данных, используя cfajaxproxy и jQuery.

Разметка генерируется циклически по запросу, но вот пример области, которая вызывает у меня проблемы:

<span id="1569_2627_text">I certify that the employee has been trained in the use of the following 
equipment (please check all that apply):</span><br />

<input type="hidden" name="2627_max_length" id="2627_max_length" value="">
<input type="hidden" name="2627_min_value" id="2627_min_value" value="">
<input type="hidden" name="2627_max_value" id="2627_max_value" value="">
<input type="hidden" name="2627_regex_format" id="2627_regex_format" value="">
<input type="hidden" name="2627_system_type" id="2627_system_type" value="">
<input type="hidden" name="2627_app_type_version" id="2627_app_type_version" value="1569">
<input type="hidden" name="2627_question_type" id="2627_question_type" value="CM">


<label>
    <input class="questionChoice" type="checkbox" name="2627" 
    value="8509" data-app_type_version="1569">
        <span>Face Shield<span>
</label><br />

<label>
    <input class="questionChoice" type="checkbox" name="2627" 
    value="8510" data-app_type_version="1569">
        <span>Neoprene Gloves<span>
</label><br />

<label>
    <input class="questionChoice" type="checkbox" name="2627"
    value="8511" data-app_type_version="1569">
        <span>Apron<span>
</label><br />

<label>
    <input class="questionChoice" type="checkbox" name="2627"
    value="8512" data-app_type_version="1569">
        <span>Boots<span>
</label><br />

<label>
    <input class="questionChoice" type="checkbox" name="2627"
    value="8513" data-app_type_version="1569">
        <span>Wizard Glove<span>
</label><br />

<label>
    <input class="questionChoice" type="checkbox" name="2627"
    value="8514" data-app_type_version="1569">
        <span>Insulated Mitt<span>
</label><br />

<label>
    <input class="questionChoice" type="checkbox" name="2627"
    value="8515" data-app_type_version="1569">
        <span>Insulated Glove<span>
</label><br />

<button class="add_answer" value="2627" data-app_type_version="1569" disabled>Add answer</button>

Вот мой прокси-тег cfajax:

<cfajaxproxy cfc="#APPLICATION.cfMapping#.Agency.Agency" 
jsclassname="agency_object">

Вот функция, которую он должен запускать на каждом установленном флажке:

function saveResponses(question_no, answerValue){

  var myagOBJ = new agency_object();
  myagOBJ.setHTTPMethod('POST');
  myagOBJ.setCallbackHandler(function(result) {
    numOfCalls++;
    alert(result+ ", call number: "+ numOfCalls);   
  });   
  myagOBJ.setErrorHandler(null);

  myagOBJ.store_prepopulated_response(
     agency_id = #SESSION.agency_object.get_id()#,
     jQuery("select##site").val(),
     question_no,
     answerValue
  );
}

А вот код jQuery, который проходит через каждый флажок:

$("div##" + div + " [name=" + question_no + "]:checked").each(function() {
    answerText = $(this).next().text();
    answerValue = $(this).val();
    identifier = question_no + "_" + answerValue;
    if(answers["q_" + identifier] ===  undefined) {
    formAppend();
    answers["q_" + identifier] = answerValue;
    alert("From Checkbox");
    saveResponses(question_no, answerValue);
    $("div##saved_answers table").append(
        "<tr id=\"" + identifier + "\"><td><strong>" + formName + 
        "</strong><br>" + questionText + "</td><td>" + answerText + 
        "<br><button data-app_type_version=\"" + div + 
        "\"class=\"remove\" value=\"" + identifier + 
        "\">Remove</button></td></tr>"
    );
    }
});

Метод cfc, который он вызывает:

<cffunction name="store_prepopulated_response" access="remote" returntype="string" verifyclient="true">
<cfargument name="agency_id" type="numeric" required="true">
<cfargument name="site_id" type="numeric" required="true">
<cfargument name="question_no" type="numeric" required="true">
<cfargument name="response" type="string" required="true">



<cfreturn "Agency id: #agency_id#, Site ID: #site_id#, Question No: #question_no#, Resonse: #response#">
</cffunction>

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

Когда я запускаю этот код, он просто вызывает cfc и возвращает результаты, но слишком часто.

Например, если я установлю три флажка, он вызовет метод cfc 7 раз, если я установлю два флажка, он вызовет метод cfc 5 раз. Я проверяю все 7 полей, что метод cfc вызывается 19 раз.

Моя первая мысль: может быть, CFC вызывается в правильном количестве раз, однако callbackhandler слишком часто вызывается, потому что каждый экземпляр будет вызывать свой обработчик ответа при получении результата, поэтому я создал глобальный экземпляр agency_object и просто вызывая метод каждый раз, однако я получил те же результаты.

Кто-нибудь знает, почему это может произойти?

* (Правка) Я только что добавил счетчик к фактическому cfc со счетчиком вызовов, и он на самом деле слишком часто вызывает метод cfc.

1 ответ

Решение

"Поскольку обработчик обратного вызова не знает, какой конкретный ответ он должен обработать, все они обрабатывают все ответы"

Вот как работают обработчики обратного вызова. Они должны обрабатывать все ответы. Проблема в том, что вы создаете несколько обработчиков обратного вызова, которые все делают одно и то же; и каждый ответ отправляется каждому обработчику.

Установив обработчик изнутри вашего saveResponses функция с использованием анонимной функции JavaScript (передача function(){...} в качестве аргумента метода) вы добавляете дополнительные обработчики обратного вызова для этого класса. Это может иметь смысл, если вы создаете и уничтожаете объект для каждого запроса, но, как обсуждалось в комментариях к вашему сообщению, вам лучше создать один экземпляр. При таком подходе вы также должны установить обработчик обратного вызова вне этой функции.

Чтобы проиллюстрировать, что происходит, давайте посмотрим, что происходит, когда вы установите 3 флажка и запустите saveResponses:

saveResponses(...){

  //...

  myagOBJ.setCallbackHandler(function(result) {
    numOfCalls++;
    alert(result+ ", call number: "+ numOfCalls);   
  });

  //...

}

Добавление обработчиков объясняет 3 флажка -> 7 вызовов.

  • При первом вызове у вас 1 обработчик и 1 результат.
  • При втором вызове вы добавили обработчик (2 обработчика), поэтому ваш 1 результат обрабатывается дважды.
  • При третьем вызове вы добавляете третий обработчик, поэтому 1 результат обрабатывается 3 раза.

saveResponse вызывается несколько раз из-за .each() Способ; он быстро перебирает каждый элемент, возвращаемый селектором jQuery, запуская функцию каждого обработчика по одному разу для каждого.

Это только добавляет до 6 звонков, так что что-то все еще не так, но вы можете видеть, как это быстро стало бы огромной проблемой. 7-й, вероятно, приходит из-за асинхронного характера запросов AJAX. То, что на самом деле происходит, вероятно, больше похоже на:

  • saveResponses называется
    1. добавить обработчик обратного вызова
    2. отправить запрос ajax
  • saveResponses называется
    1. добавить обработчик обратного вызова
    2. отправить запрос ajax
  • результат первого запроса возвращается. есть 2 обработчика, поэтому он отправляется обоим.
  • 2 колбэка, замеченного до сих пор
  • результат от второго запроса возвращается. 2 обработчика, отправленные обоим.
  • 4 колбэка, замеченных до сих пор
  • saveResponses называется
    1. добавить обработчик обратного вызова
    2. отправить запрос ajax
  • результат из 3-го запроса возвращается. 3 обработчика, отправлено всем 3.
  • 7 обратных вызовов, замеченных до сих пор

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

Если вы действительно хотите узнать о JavaScript - и вам следует - возьмите копию JavaScript: The Good Parts. Он очень короткий, но очень хорошо написан и облегчает понимание сложных концепций. Некоторые из них могут не иметь особого смысла на вашем текущем уровне навыков, но сначала сфокусируйтесь на том, что находится в пределах досягаемости (например, анонимные функции), а затем, после того, как вы действительно это сделаете, перейдите к сложным вещам, таким как модули.

Другие вопросы по тегам