backbone.js事件在重新渲染后没有触发

时间:2011-09-08 13:41:24

标签: events backbone.js

[编辑:我通过调用delegateEvents()解决了之前的问题,但不应该这样做。重新发布更多信息。]

我有一个View,当渲染时它上面有一个登录按钮并附加了一个点击事件。首先渲染所有工作:单击按钮,成功调用ajax后,登录提示消失,并显示欢迎视图(LoggedInView)。但是,如果我稍后导航回此视图(#foo),UI呈现但事件关联消失,而无需通过调用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);
        }
    }
});

4 个答案:

答案 0 :(得分:19)

你清空了#login div。正如jQuery文档所说:

  

为了避免内存泄漏,jQuery删除了其他构造,如数据   和删除之前来自子元素的事件处理程序   元素本身。

因此,您有效地从视图中删除了事件。我更喜欢使用分离,因为它会保留事件。 http://api.jquery.com/detach/

您可以在视图中实现显示/隐藏,以解决此问题。

答案 1 :(得分:2)

我找到了解决方案,因为我遇到了同样的问题,实际上detach()不是解决方案,因为它会为你带回旧的DOM元素,这是无用的。

这是你需要做的事情

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

如果使用.html()方法,则不会触发事件。 您需要使用appendTo()。

将新创建的HTML附加到DOM

顺便说一下,如果您使用tagName和className动态构建视图,这只会发生在我身上。

答案 2 :(得分:1)

我面临同样的问题。我现在解决它的方法是使用new MyView()完全重新实例化View对象,这可以确保事件反弹。

希望有帮助吗?

答案 3 :(得分:1)

使用$(el).empty()时,它会移除所选元素中的所有子元素并删除所有 绑定到的事件(和数据)所选元素(el)内的任何(子)元素

将事件绑定 子元素,但仍然删除子元素,请使用:

$(el).children().detach();代替$(.el).empty();

这将允许您的视图成功重新呈现仍然绑定并正常工作的事件。