Динамически добавленные кнопки (с использованием jQuery) нужно дважды щелкнуть, чтобы запустить событие щелчка, уже связанное с кнопкой - PullRequest
1 голос
/ 21 июня 2011

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

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

Кстати, в текущей версии функции я связываю событие щелчка с телом документа для каждой динамической кнопки, а затемПосмотрите, является ли цель события соответствующей динамической кнопкой, и в этот момент я запускаю нужную функцию для возврата выбранного контакта.Я переключился на этот подход по совету, который был дан кому-то другому, испытывающему то же самое, что я здесь описываю.До этой реализации у меня был очень традиционный $ J ("# btnId"). Bind ('click', {....}, function (event) {...});подход к привязке события щелчка, который привел к тому же опыту необходимости дважды щелкнуть, прежде чем событие щелчка запустится на динамических кнопках.Я также пришел к этому с других точек зрения, используя jQuery .bind, .live, .delegate подходы, и во всех случаях мне приходилось дважды щелкать, прежде чем событие нажатия кнопки фактически сработало.

function PickContacts() {
    if ($J("#tblCp").length > 0) {
        var broad = $J("#chkCpBroad").prop("checked");
        var contactType = GetCheckBoxListValues("divCpContactType");
        var contactId = "";
        if ($J("#txtCpContactId").length > 0) {
            contactId = $J("#txtCpContactId").val();
        }
        var contactName = $J("#txtCpContactName").val();
        var firstName = $J("#txtCpFirstName").val();
        var lastName = $J("#txtCpLastName").val();
        var email = $J("#txtCpEmail").val();
        var allMatches = $J("#chkCpAllMatches").prop("checked");
        var rows = ParseInts($J("#txtCpRowsReturned").val(), 10);
        if (rows === 0) {
            rows = 15;
        }
        var crmSeatsOnly = false;
        if (cpCrmSeatsOnly !== null && cpCrmSeatsOnly === "Y") {
            crmSeatsOnly = true;
        }
        var tbl = $J("#tblCpResults");
        tbl.empty();
        if (contactId !== "" || contactName !== "" || firstName !== "" || lastName !== "" || email !== "") {
            $J.ajax({
                type: "POST",
                url: "/ClientBin/Contact.asmx/ContactPicker",
                data: "{'broad':" + broad + ",'contactType':'" + contactType + "','contactId':'" + contactId + "','contactName':'" + contactName + "','firstName':'" + firstName + "','lastName':'" + lastName + "','email':'" + email + "','allMatches':" + allMatches + ",'crmSeatsOnly':" + crmSeatsOnly + ",'rows':" + rows + "}",
                contentType: "application/json; charset=utf-8",
                context: tbl,
                success: function (result) {
                    if (result.d !== "TIME OUT") {
                        var JObject = ParseJson(result.d);
                        if (JObject !== null) {
                            if (JObject.RESULT[0].SUCCESS) {
                                var alternatingRow = false;
                                var c = JObject.CONTACT;
                                for (i = 0; i < c.length; i++) {
                                    var trStyle = "rowstyleNoBorder";
                                    if (alternatingRow) {
                                        trStyle = "alternatingrowstyleNoBorder";
                                        alternatingRow = false;
                                    }
                                    else {
                                        alternatingRow = true;
                                    }

                                    this.append('<tr class="' + trStyle + '"><td><span id="lblCpContactId' + i + '">' + c[i].CONTACT_ID + '</span></td><td><span id="lblCpContactName' + i + '">' + c[i].CONTACT_NAME + '</span></td><td><span id="lblCpFirstName' + i + '">' + c[i].FIRST_NAME + '</span></td><td><span id="lblCpLastName' + i + '">' + c[i].LAST_NAME + '</span></td><td valign="top"><input type="submit" id="btnCpSelect' + i + '" value="' + $J("#hdnCpTransSelect").val() + '" title="' + $J("#hdnCpTransSelectContact").val() + '" /></td></tr>');

                                    $J("body").bind('click', { index: i, contactId: c[i].CONTACT_ID, contactName: c[i].CONTACT_NAME, firstName: c[i].FIRST_NAME, lastName: c[i].LAST_NAME }, function (event) {
                                        if ($J(event.target).is("#btnCpSelect" + event.data.index)) {
                                            SelectContact(event.data.contactId, event.data.contactName, event.data.firstName, event.data.lastName);
                                            return false;
                                        }
                                    });
                                    // Copy button css styling from an existing on page button by passing the IDs for both buttons to the CopyBtnStyle fn.
                                    CopyBtnStyle("btnCpSelect" + i, "btnCpClose");
                                }
                            }
                            else {
                                this.append('<tr><td><span id="lblCpNoRows">' + JObject.RESULT[0].FEEDBACK + '</span></td></tr>');
                            }
                        }
                    }
                    else {
                        TimeOut();
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    WsFail(XMLHttpRequest, textStatus, errorThrown);
                }
            });
        }
    }
}

Ответы [ 2 ]

2 голосов
/ 22 июня 2011

Хорошо ... Я докопался до сути вещей здесь. Технически я не уверен, почему это проблема, и, возможно, один из наиболее осведомленных участников мог бы объяснить это мне, но моя проблема с необходимостью дважды щелкнуть эти динамические кнопки, чтобы вызвать событие нажатия, была вызвана тем, что Я подключил свою JS-функцию «PickContacts» для вызова событий keyup и blur моих полей ввода текста в форме.

Хотя это, очевидно, немного избыточно, я просто не уверен, почему это может быть проблемой, так как перед вызовом метода WS для получения списка контактов я очищаю таблицу, в которой отображаются результаты, возвращаемые методом WS. , Таким образом, я бы предположил, что наряду с удалением строк таблицы и их элементов из DOM, событие клика, связанное с динамической кнопкой при нажатии клавиши вверх или при размытии (в зависимости от того, что наступит раньше).

Все, что я могу с уверенностью сказать, - это то, что я могу наблюдать, и это то, что после того, как я удаляю одно из событий из полей ввода текста, оставляя одно из двух на месте, моя проблема необходимости дважды щелкнуть, прежде чем получить событие нажатия кнопки для запуска разрешено.

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

В любом случае, я еще раз благодарю за внимание, уделенное как PetersonDidIt, так и DarthJDG.

1 голос
/ 22 июня 2011

Есть много вещей, которые вы можете сделать, чтобы сделать эту работу лучше. Я немного переработал код и добавил множество комментариев, чтобы попытаться объяснить, почему я внес изменения: http://jsbin.com/ipuki5/2/edit

или массовый кодовый блок:

// Create an easy to edit template for our row
var contactsRowtmpl = '<tr class="%trStyle%"><td><span id="lblCpContactId%index%">%CONTACT_ID%</span></td>'+
    '<td><span id="lblCpContactName%index%">%CONTACT_NAME%</span></td>'+
    '<td><span id="lblCpFirstName%index%">%FIRST_NAME%</span></td>'+
    '<td><span id="lblCpLastName%index%">%LAST_NAME%</span></td>'+
    '<td valign="top"><input type="submit" id="btnCpSelect%index%" class="CpSelect" value="%value%" title="%title%" /></td></tr>';

// Very simple templating function
function template( tmpl, data ) {
  return tmpl.replace(/%(\w*)%/g,function(){ return data[ arguments[1] ] || "";});
}

// Cache the table selector 
var tblCpResults = $J("#tblCpResults");
// Use delegate to bind the click event to for all input.CpSelet  
tblCpResults.delegate("click", ".CpSelect", function (event) {
  // prevent the default action of the click event
  event.preventDefault();
  // retrive the data from the row
  var data = $( this ).closest("tr").data("contact");
  // Select the contact
  SelectContact(data.contactId, data.contactName, data.firstName, data.lastName);
});

function PickContacts() {
    if ($J("#tblCp").length > 0) {
        var broad = $J("#chkCpBroad").prop("checked");
        var contactType = GetCheckBoxListValues("divCpContactType");
        var contactId = "";
        if ($J("#txtCpContactId").length > 0) {
            contactId = $J("#txtCpContactId").val();
        }
        var contactName = $J("#txtCpContactName").val();
        var firstName = $J("#txtCpFirstName").val();
        var lastName = $J("#txtCpLastName").val();
        var email = $J("#txtCpEmail").val();
        var allMatches = $J("#chkCpAllMatches").prop("checked");
        var rows = ParseInts($J("#txtCpRowsReturned").val(), 10);
        if (rows === 0) {
            rows = 15;
        }
        var crmSeatsOnly = false;
        if (cpCrmSeatsOnly !== null && cpCrmSeatsOnly === "Y") {
            crmSeatsOnly = true;
        }

        tblCpResults.empty();
        if (contactId !== "" || contactName !== "" || firstName !== "" || lastName !== "" || email !== "") {
            $J.ajax({
                type: "POST",
                url: "/ClientBin/Contact.asmx/ContactPicker",
                // Use a normal object here much easier to maintain
                data: {
                  'broad': broad,
                  'contactType': contactType,
                  'contactId': contactId,
                  'contactName': contactName,
                  'firstName': firstName,
                  'lastName': lastName,
                  'email': email,
                  'allMatches': allMatches,
                  'crmSeatsOnly': crmSeatsOnly,
                  'rows': rows
                },
                contentType: "application/json; charset=utf-8",
                success: function (result) {
                    if (result.d === "TIME OUT") {
                      TimeOut();
                      return;
                    }
                    var JObject = ParseJson(result.d),
                        // Cache these selectors so we don't have to reselect them in the for loop
                        hdnCpTransSelect = $J("#hdnCpTransSelect"),
                        hdnCpTransSelectContact = $J("#hdnCpTransSelectContact");
                    if (JObject !== null) {
                        if (!JObject.RESULT[0].SUCCESS) {
                          tblCpResults.append('<tr><td><span id="lblCpNoRows">' + JObject.RESULT[0].FEEDBACK + '</span></td></tr>');
                          return;
                        }
                        var c = JObject.CONTACT;
                        // Create an empty jQuery object to stuff all of the rows in
                        var rows = $();
                        for (i = 0; i < c.length; i++) {
                          c[ i ].trStyle = ( i % 2 ) ? "alternatingrowstyleNoBorder" : "rowstyleNoBorder";
                          c[ i ].index = i;
                          c[ i ].value = hdnCpTransSelect.val();
                          c[ i ].title = hdnCpTransSelectContact.val();

                          // Use the template function to handle creating our row
                          var row = template( contactsRowtmpl, c[ i ] );
                          // Add the contacts data to the row so we can retrive it later
                          $.data( row, "contact", c[ i ] );
                          // add the row to the rows jQuery object
                          rows = rows.add( row );
                          // Why do you need to copy the btn style? seems like this could be improved on.
                          CopyBtnStyle("btnCpSelect" + i, "btnCpClose");
                        }
                        // Now that we are done looping add all the rows to the dom.
                        tblCpResults.append( rows );
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    WsFail(XMLHttpRequest, textStatus, errorThrown);
                }
            });
        }
    }
}
...