2011-04-28 15 views
28

Estoy tratando de jugar con Backbone JS y hasta ahora todo parece tener sentido y funciona sin problemas.Backbone JS View Events not Firing?

Sin embargo, con el siguiente código, parece que mis eventos personalizados no se activan. ¿Hay algo en el siguiente código que destaque por qué podría ser? ¿Debo "inicializar" algo en la vista? Cualquier otro puntero en el código/estructura sería genial también. A continuación está mi JS/HTML completo.

JS

var Todo = Backbone.Model.extend({}); 

var TodoCollection = Backbone.Collection.extend({ 

    model: Todo, 
    url: '/Home/Todos' 

}); 

var AppView = Backbone.View.extend({ 

    // where it should listen, required? 
    el: $(".content"), 

    events: { 
     "keypress #new-todo": "enter" 
    }, 

    initialize: function() { 
     // _.bindAll(this, "render", "createOnEnter"); 
     // this.collection.bind("all", this.render); 
    }, 

    hi: function() { 
     alert('ohai'); 
    }, 

    render: function() { 
     var lis = ''; 
     $.each(this.collection.models, function() { 
      lis += '<li>' + this.get('Text') + '</li>'; 
     }); 
     $('#todo-list').append(lis); 
     return this.el; 
    }, 

    enter: function (e) { 
     alert('hi'); 
    } 

}); 


var TodoController = Backbone.Controller.extend({ 

    routes: { 
     "": "todos" 
    }, 

    initialize: function (options) { }, 

    todos: function() { 
     var todolist = new TodoCollection(); 
     todolist.fetch({ 
      success: function (data) { 
       var appview = new AppView({ collection: data }); 
       appview.render(); 
      } 
     }); 
    } 

}); 

$(function() { 
    window.app = new TodoController(); 
    Backbone.history.start(); 
}); 

HTML

<div id="todoapp"> 
    <div class="content"> 
     <input id="new-todo" placeholder="What needs to be done?" type="text" /> 
     <div id="todos"> 
      <ul id="todo-list"> 
      </ul> 
     </div> 
     <a href="#">say hey</a> 
    </div> 
</div> 

Respuesta

37
el: $(".content") 

Prueba esto:

var appview = new AppView({ el:$(".content"), collection: data }); 

No se puede llamar a un jQuery allí porque el DOM no ha sido creada. Debe hacerlo cuando la vista se carga como mi ejemplo o en la inicialización.

+1

Gracias por la respuesta. Todavía estoy un poco confundido por qué DOM no se crearía en ese momento. Pateo el controlador en la parte inferior y lo envuelvo dentro de una llamada lista para documentos. Luego, mis controladores informan sobre el AppView, por lo que en ese momento ¿no sería la primera vez que llama a 'el'? – aherrick

+5

var AppView = Backbone.View.extend ({}) se evalúa a medida que el navegador lo lee. Lo instancia en la llamada lista para documentos, pero como _el_ no es una función, se evaluará como parte de la extensión. – Julien

+3

¿Alguien puede explicar por qué el ejemplo Backbone.js Todo no necesita pasar parámetros cuando crean su AppView? Tienen este comentario en la parte superior de todo.js, "// Cargue la aplicación una vez que el DOM esté listo, usando' jQuery.ready': ", pero no veo que hagan nada para asegurarse de que el DOM esté listo. Gracias. – Quentamia

16

Además, para que sus eventos funcionen, debe vincular su contenido en la función de renderizado a this.el. Los eventos están todos vinculados al elemento que especifique, por lo que se deduce que debe tener sus elementos generadores de eventos vinculados como secundarios al elemento que actúa como delegador.

+3

me gustaría este comentario dos veces, pero no puedo, fue exactamente mi problema, ¡10 veces! –

+0

esto también ha cambiado, con la actualización de la API Backbone. Ahora hay un método disponible para configurar el el dinámicamente, y si se utiliza, delegateEvents() se llama automágicamente por esa función. –

+0

No sé muy bien la red troncal, pero creo que esto se resolvería al no especificar el atributo el y dentro de la función de representación haciendo $ ('. Content'). Wrap (this.el); – BishopZ

1

La respuesta aprobada tiene un inconveniente. No puede ser muy dinámico si establece {el: $ (". Content")}. No es posible reutilizar ".content" -Elemento dentro de su DOM. Tan pronto como llame a remove() en esta vista, $ (". Content") también desaparecerá.

uso otro parámetro para pasar esa información:

{ renderTarget: $("#content") }. 

e insertar mi punto de vista en el DOM al inicio de la imagen:

initialize: function (options) { 
    options = options || {}; 
    this.renderTarget = options.renderTarget || this.renderTarget; 
}, 
render: function() { 
    if (this.renderTarget) { 
     $(this.renderTarget).html(this.el); 
    } 
    ... render stuff into $(this.el) ... 
    return this; 
}