veces obtiene objeto forma eventos evento elementos ejemplos ejecuta dinámicamente dinámica creados creado como asociar acceso javascript backbone.js javascript-events

javascript - obtiene - Vinculando eventos a vistas-Disparando un número desigual de veces



evento click jquery se ejecuta dos veces (2)

El problema principal es que está renderizando todas las vistas de UserView en el mismo contenedor:

$(''#users-list'').append(this.template(this.model.toJSON()));

Esta es la razón por la cual el selector de eventos de clics (''click .user-data'') está seleccionando los otros botones UserView y disparando sus clics también.

No lo preguntaste, pero ... aquí van algunas sugerencias:

  1. No invoque render desde la función de inicialización ;
  2. Evita definir el el ;
  3. Evite agregar el contenido de la vista fuera de la vista usando $ . Use esto. $ El en su lugar;
  4. NUNCA te olvides de devolver esto; a usted rinde funciones.

Aquí hay un jsfiddle con lo que creo que quiere: https://jsfiddle.net/Neviton/n52j873u/

Tengo UserModel : UserView y UserCollection : UserCollectionView . Con esto, intento vincular un evento de click al UserView (estoy haciendo esto en UserView ). Entonces, este es el código que tengo:

var root = ''http://localhost:5000/api/v1''; var app = {}; // Backbone Model app.UserModel = Backbone.Model.extend({ defaults: { // urlRoot: root + ''/users'', name: ''Default Name'', email: ''30'', username: ''default_username'' }, initialize: function() { this.set({ id: this.get(''username'') }); console.log(''User model /''' + this.id + ''/' has been initialized.''); }, // parse: function(data) { // console.log(''Model parse funciton called''); // return data; // } }); // Backbone Model View app.UserView = Backbone.View.extend({ // el: ''#users-list'', // tagName: ''div'', el: ''.user-box-wrapper'', events: { ''click .user-data'': ''userClicked'' }, userClicked: function(ev) { console.log("User selected"); // console.log(ev.currentTarget); }, template: _.template($(''#connections-user-template'').html()), initialize: function() { this.render(); }, render: function() { $(''#users-list'').append(this.template(this.model.toJSON())); // this.$el.append( this.template( this.model.toJSON())); console.log(''User view is rendered''); } }); // Backbone Collection app.UserCollection = Backbone.Collection.extend({ model: app.UserModel, url: root + ''/users'', initialize: function() { // this.fetch(); }, parse: function(data) { // console.log(data.data); return data.data; } }); // Backbone Collection View app.UserCollectionView = Backbone.View.extend({ el: ''#users-list'', template: _.template($(''#connections-template'').html()), initialize: function() { this.connections = new app.UserCollection(); var self = this; this.connections.fetch().done(function() { self.render(); }); }, render: function() { console.log(''User collection view is rendered''); this.$el.html(this.template()); // this.$el.append( this.template( this.model.toJSON())); this.connections.each(function(user) { console.log(''User : '' + user.get(''id'')); var userView = new app.UserView({ model: user }); // userView.model.fetch(); // userView.render(); }); } }); var connectionsView = new app.UserCollectionView();

Los datos JSON realmente devuelven 14 objetos (o UserModels en este caso). El problema es que si hago clic en la primera vista de usuario, se desencadena 13 veces y el segundo clic de vista se activa 12 veces, y así sucesivamente, el último evento de clic de vista no se activó cuando se hizo clic.

Sin embargo, las UserViews individuales se representan una vez (eso es lo que creo al menos). ¿Puede alguien explicar por favor cuál es el problema aquí y qué está sucediendo exactamente aquí?

PD: soy consciente de la solución alternativa de vincular los eventos en CollectionView.

Editar 1

Esta es la estructura DOM:

<!doctype html> <html> <head> <title>Hey there</title> <link rel="stylesheet" href="../static/css/normalize.css"> <link rel="stylesheet" href="../static/css/index.css"> <script src="/static/js/jquery-2.2.0.js"></script> <script src="/static/js/underscore-1.8.3.js"></script> <script src="/static/js/backbone-1.2.3.js"></script> </head> <body> <header id="top"> <div id="logo-wrapper"> <img src="../static/img/logo.png" alt="Logo" id="logo"> </div> <div id="top-links"> <div id="top-profile-box" class="toplink"> <div id="top-profile-data-box"> <div id="top-profile-data-name">Kevin Isaac</div> <div id="top-profile-data-passion">Writer</div> </div> <img id="top-profile-image" src="../static/img/user1.jpg" alt=""> </div> <div id="notification-icon" class="toplink"></div> <div id="top-message-icon" class="toplink"></div> <div id="logout-icon" class="toplink"></div> </div> </header> <div id="middle"> <nav id="side-nav"> <div id="side-nav-top"> <div class="side-nav-link" id="side-nav-home-link"> <div class="side-nav-link-img"></div> <div class="side-nav-link-title">Home</div> </div> <div class="side-nav-link" id="side-nav-profile-link"> <div class="side-nav-link-img"></div> <div class="side-nav-link-title">Profile</div> </div> <div class="side-nav-link" id="side-nav-messages-link"> <div class="side-nav-link-img"></div> <div class="side-nav-link-title">Message</div> </div> <div class="side-nav-link" id="side-nav-account-link"> <div class="side-nav-link-img"></div> <div class="side-nav-link-title">Account</div> </div> </div> </nav> <div id="main-content"> <!-- Start of page specific HTML --> <div id="content-title"> <div class="content-subtitle" id="connections">Connections</div> <div class="content-subtitle" id="followers">Followers</div> <div class="content-subtitle" id="followings">Followings</div> </div> <div id="content-body"> <div id="users-box"> <div id="users-list">No connection</div> <!-- Backbone Template Starts --> <script type="text/template" id="connections-template"></script> <script type="text/template" id="connections-user-template"> <div class="user-box-wrapper"> <div class="user-box"> <div class="user-pic-wrapper"> <img src="/static/img/user1.jpg" alt=""> </div> <div class="user-data" id="boox"> <div class="user-name"><%= name %></div> <div class="user-passion"><%= username %></div> <div class="user-city"><%= email %></div> </div> </div> </div> </script> <!-- Backbone Template Ends --> <div id="users-side-box"> <div id="users-box-search"> <input id="user-search" type="text" name=""> </div> <div id="user-metadata"> <div id="metadata-user-top-box"> <div id="metadata-user-image-wrapper"> <img src="/static/img/user1.jpg" alt=""> </div> <div id="metadata-user-name-box"> <div id="metadata-name">Name''s Bond</div> <div id="metadata-passion">Assassin</div> </div> </div> <div id="metadata-user-bottom-box"> <div class="metadata-user-attribute"> <span class="metadata-property">Studied at: </span> <span class="metadata-value">Karunya University </span> </div> <div class="metadata-user-attribute"> <span class="metadata-property">Native City: </span> <span class="metadata-value">London</span> </div> <div class="metadata-user-attribute"> <span class="metadata-property">Website: </span> <span class="metadata-value">www.007.com</span> </div> </div> </div> </div> </div> </div> <!-- End of page specific HTML --> </div> <aside id="main-aside"> Aside one two therr </aside> </div> <script src="../static/js/index.min.js"></script> </body> </html>


Hay muchos problemas con tu código.

El principal problema es que todos sus userView apuntan al mismo selector, y el elemento que coincide con este selector .user-box-wrapper está dentro de la plantilla de visualización. Por lo tanto, cada vez que cree un nuevo userView, agregará un nuevo detector de eventos a .user-box-wrapper presente en todas las vistas de usuario existentes, pero no a sí mismo. Por lo tanto, su primer userView tendrá n-1 controladores de eventos registrados mientras que el último no tiene ninguno ( n es el número total de userViews). Se supone que el elemento de vista no forma parte de la plantilla, se supone que la plantilla se debe agregar al elemento de vista.

Cuando su vista tenga múltiples copias de sí mismo, no defina la opción el, deje que backbone cree un nuevo elemento para cada instancia de la vista. Puede personalizar las propiedades de este elemento.

Otro problema es que no está agregando la plantilla userView a su elemento userView, sino algo más externo ( $(''#users-list'') . Por lo tanto, al hacer clic en la plantilla no se activará el controlador de eventos (en su caso, esta es la razón usted es el último userView no activa su evento. Estaba vinculado a todas las demás vistas existentes porque el selector común fue proporcionado por el )

Debería intentar evitar los selectores globales como $(''#users-list'') desde una vista. En este caso, puede agregar userView a #users-list de #users-list desde userCollectionView, que es el points a #users-list .

Tu código debería ser:

var root = ''http://localhost:5000/api/v1''; var app = {}; // Backbone Model app.UserModel = Backbone.Model.extend({ defaults: { // urlRoot: root + ''/users'', name: ''Default Name'', email: ''30'', username: ''default_username'' }, initialize: function() { this.set({ id: this.get(''username'') }); console.log(''User model /''' + this.id + ''/' has been initialized.''); } }); // Backbone Model View app.UserView = Backbone.View.extend({ className: ''user-box-wrapper'', /*--^-- creates a new div with this class for each user*/ template: _.template($(''#connections-user-template'').html()), events: { ''click .user-data'': ''userClicked'' }, initialize: function() { this.render(); }, render: function() { this.$el.append( this.template( this.model.toJSON())); console.log(''User view is rendered''); }, userClicked: function(ev) { console.log("User selected"); // console.log(ev.currentTarget); } }); // Backbone Collection app.UserCollection = Backbone.Collection.extend({ model: app.UserModel, url: root + ''/users'', initialize: function() { // this.fetch(); }, parse: function(data) { // console.log(data.data); return data.data; } }); // Backbone Collection View app.UserCollectionView = Backbone.View.extend({ el: ''#users-list'', template: _.template($(''#connections-template'').html()), initialize: function() { this.connections = new app.UserCollection(); var self = this; this.connections.fetch().done(function() { self.render(); }); }, render: function() { this.$el.html(this.template()); console.log(''User collection view is rendered''); this.connections.each(function(user) { console.log(''User : '' + user.get(''id'')); var userView = new app.UserView({ model: user }); this.$el.append(userView.el); /*append child view here*/ },this); } }); var connectionsView = new app.UserCollectionView();