Подтвердить что ты не робот

Событие Backbonejs происходит несколько раз

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

Просмотр FieldList:

var fieldListView = Backbone.View.extend({
el: "#centerbodycontent",
initialize: function () {
    _.bindAll(this, 'render', 'addField');
},

render: function () {
    $(this.el).empty();
    $("#FieldGridTemplate").tmpl({ results: this.model }).appendTo(this.el)
    stripe($(this.el).find("tbody"));
    return this;
},
events: {
    "click a#addfield": "addField"
},
addField: function (e) {
    window.appController.popup = new fieldFormView({ model: new fieldModel({ contenttype_id: this.model.id }) });
    window.appController.popup.render();
}

});

Вид формы (это то, что вызывается для всплывающего окна)

var fieldFormView = Backbone.View.extend({
el: "#popupwindowcontent",

events: {
    "click #savefieldandnew": "savefield",
    "click #savefieldandclose": "savefield",
    "change input,textarea,select": "changeField"
},
render: function () {
    var formWrapper = $(this.el).find(".modal-form")[0];
    $(formWrapper).empty();
    $("#FieldFormTemplate").tmpl({ results: this.model }).appendTo(formWrapper)
    OpenForm(this.el, "Add Field", 450, 600);
    return this;
},
// automatically updates the model during field changes
changeField: function (e) {
    var changeobj = new Object;
    switch (e.target.type) {
        case "radio":
            changeobj[e.target.id] = parseInt($(e.target).val());
            break;
        case "checkbox":
            changeobj[e.target.id] = $(e.target).is(":checked");
            break;
        default:
            changeobj[e.target.id] = $(e.target).val();
            break;
    }

    if (e.target.id.toLowerCase() == "name") {
        var k = $(this.el).find("#key");
        if (jQuery.trim(k.val()).length == 0)
            k.val($(e.target).val().replace(/[^a-zA-Z0-9]+/g, '').toLowerCase());

        var l = $(this.el).find("#label");
        if (jQuery.trim(l.val()).length == 0)
            l.val($(e.target).val());
    }

    var options = { silent: true };
    this.model.set(changeobj, options);
},
savefield: function (e) {
    var kcode = (e.which);
    var thiz = this;
    var m = this.model;
    var nextaction = e.target.id;
    alert(nextaction);
    if (kcode == 0 || kcode == 1 || kcode == 32) {
        e.preventDefault();
        if ($("#contentfieldform").validate({
            rules: {
                name: { required: true },
                label: { required: true },
                key: { required: true }
            }
        }).form()) {
            m.save(null, {
                headers: { "If-Match": m.get("version") },
                error: function (model, response) {
                    var errResp = JSON.parse(response.responseText);
                    popupException("Content Type Modification Error", errResp.errors[0].message);
                },
                success: function (model, response) {
                    window.appController.popup.model = new fieldModel;
                    $.pnotify({
                        pnotify_title: 'Field Saved',
                        pnotify_text: 'The field was saved successfully.'
                    });

                    if (nextaction == "savefieldandclose") {
                        $.modal.close();
                    }
                }
            });
        }
    }
}
4b9b3361

Ответ 1

Так как никто не ответил, я думал, что добавлю дополнительную информацию, если кто-нибудь столкнется с этим. Хороший ресурс для объяснения того, что происходит (и предлагает общее решение), http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/. Кроме того, в последней версии базовой системы есть несколько новых методов, позволяющих отменить регистрацию событий из представлений.

Ответ 2

У меня такая же головная боль сегодня утром, но я нашел небольшое обходное решение, которое работает для меня как прелесть.

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

   Overview: backBone.View.extend({
        el: $('#overviewTab'),

        dialog : null,
Диалог

- это мое поле, где im собирается удерживать объект моего представления

теперь на обратном вызове, который создает новый вид, я делаю это:

showNewActivityDialog: function () {
            this.dialog = this.dialog || new window.RTB.Views.NewActivity();
            this.dialog.render();
            return false;
        },

в этом случае я не создаю новые представления - я повторно использую ранее созданный, поэтому я не связываю новые события!
Надеюсь, что это сработает для вас.

Ответ 3

Быстрое исправление (которое я не поощряю) заключается в использовании функции _.throttle. Используйте его, чтобы обернуть обработчик событий так, чтобы он вызывается только один раз, скажем, 100 мс. Он может работать для пользовательского интерфейса, а не для логики приложений.

addField: (function() {
    return _.throttle( function (e) {
        window.appController.popup = new fieldFormView({ model: new fieldModel({ contenttype_id: this.model.id }) });
        window.appController.popup.render();
    }, 100 );
})(),