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

События backbone.js не срабатывают после повторной обработки

[EDIT: Я решил проблему раньше, вызвав делегатEvents(), но не должен. Повторная публикация с дополнительной информацией.]

У меня есть представление, что при визуализации есть кнопка входа в систему с прикрепленным кликом. Сначала выполните все работы: нажмите кнопку и после успешного вызова ajax приглашения на вход исчезнут и появится приветственное представление (LoggedInView). Но, если я снова вернусь к этому представлению позже (#foo), пользовательский интерфейс отобразит, но ассоциация событий исчезнет без необходимости вручную вызывать проблему, вызвав функцию delegateEents().

Что случилось, что мои события не пересоединились?

LoginView = Backbone.View.extend({
    template: _.template($("#loginTemplate").html()),
    initialize: function(stuff,router) {
        _.bindAll(this,'render','rc','gotProfile');
        this.model.bind("rc",this.rc)
        this.router = router;
    },
    events: {
        'click .loginButton': 'login'
    },  
    render: function() {
        $(this.el).html(this.template(this.model.toJSON()));
        $(this.el).find(".actionButton").button();  // Button
//      this.delegateEvents(this.events);  // NEEDED!  Re-wire events on re-render
        return this;
    },
    rc: function(code) {
        switch(code) {
            case errCodes.USER_NOT_FOUND:   this.notFound(); break;
            case errCodes.OK:               this.loginOk(); break;
            default:                            this.otherErr(); break;
        }
    },
    login: function() {
        clearErrors( $('[rel="req"]') );
        var okReq = validate( $('#login [rel="req"]'), validateReq );
        var okEmail = validate( [$('#uid')], validateEmail );
        if( okReq && okEmail ) {
            this.model.set({'uid':$('#uid').val().trim(),     'pwd':$('#pwd').val().trim()});
            this.model.fetch();
        }
    },
    notFound: function() {
        validate( [$('#uid'),$('#pwd')], function(){return[false,"Invalid user / password"]} );
    },
    otherErr: function() {
        validate( [$('#uid'),$('#pwd')], function(){return[false,"Please contact support for help logging in."]} );
    },
    loginOk: function() {
        this.profile = new Profile({uid:this.model.get('uid'),token:this.model.get('key')});
        this.profile.bind("rc",this.gotProfile)
        this.profile.fetch();
    },
    gotProfile: function() {
        this.router.navigate('/',true);
    }
});

LoggedInView = Backbone.View.extend({
    template: _.template($("#loggedInTemplate").html()),
    uList: new ProfileList(),
    initialize: function() {
        _.bindAll(this,'render','renderUserList','renderUser');
        this.model.bind('show', this.render);
        this.uList.bind('rc', this.render);
    },
    events: {
        'click #ufa': 'getUsersForHouse'
    },
    render: function() {
        $(this.el).html(this.template(this.model.toJSON()));
        this.renderUserList();
//      this.delegateEvents(this.events); // NEEDED!  Re-wire events on re-render
        return this;
    },
    renderUserList: function() {
        $(this.el).find('ul').empty();
        this.uList.each(this.renderUser);
    },
    renderUser: function(aUser) {
        $(this.el).find('#userList').append("<li>"+aUser.get('person').firstName+"</li>");
    },
    getUsersForHouse: function() {
        this.uList.fetch(this.model.get('token'),"house");
    }
});

Main = Backbone.Router.extend({
    routes: {
        'foo': 'foo',
        '*all': 'home'
    },
    initialize: function() {
        this.token = new Token();
        this.loginView = new LoginView({model:this.token},this);
    },
    foo: function(){  // naving here looses click event on login button
        $('#login').empty();
        $("#login").append(this.loginView.render().el);
    },
    home: function() {
        $('#login').empty();
        if( this.loginView.profile == null ) 
            $("#login").append(this.loginView.render().el);
        else {
            this.loggedInView = new LoggedInView({model:this.loginView.profile});
            $("#login").append(this.loggedInView.render().el);
        }
    }
});
4b9b3361

Ответ 1

Вы освобождаете #login div. Как гласит документ jQuery:

Чтобы избежать утечек памяти, jQuery удаляет другие конструкции, такие как данные и обработчики событий из дочерних элементов перед удалением сами элементы.

Таким образом, вы эффективно удаляете события из своих представлений. Я предпочитаю использовать detach, потому что он сохраняет события. http://api.jquery.com/detach/

Вы можете реализовать show/hide в своих представлениях, которые будут иметь дело с этим.

Ответ 2

Я нашел решение этого, потому что у меня была такая же проблема, на самом деле detach() не является решением, потому что оно вернет старые DOM-элементы для вас, что не полезно.

это то, что вам нужно сделать

render: function(){ this.$el.empty();  ......  this.$el.appendTo($DOM);   }

если вы используете метод .html(), ваши события не будут запускаться. вам нужно прикрепить вновь созданный HTML к DOM, используя appendTo().

кстати, это произошло только со мной, если вы используете tagName и className для динамического создания своего представления.

Ответ 3

У меня такая же проблема. То, как я решил это сейчас, полностью восстанавливает объект View с помощью new MyView(), это гарантирует, что события будут отскакивать.

Надеюсь, что это поможет?

Ответ 4

При использовании $(el).empty() он удаляет все дочерние элементы в выбранном элементе И удаляет ВСЕ события (и данные), которые привязаны к какому-либо ( дочерние элементы внутри выбранного элемента (el).

Чтобы связать события с дочерними элементами , но все же удалить дочерние элементы, используйте:

$(el).children().detach(); вместо $(.el).empty();

Это позволит вашему представлению успешно выполнить рендеринг с событиями, все еще связанными и работающими.