// build a collection of players with this team ID
this.collection = new PlayersCollection(App.data.players.where({team_id: this.model.id}));
When I do this it renders this.collection = App.data.players;
it has to do with the collection being a new collection, how do I listen to a new collection?
With marionette I am passing a collection of players into a collection of teams with collectionViews, compositeViews, and itemViews.
Teams collectionView > Team compositeView > Player itemView
Inside the team compositeView I define this.collection
as a new PlayersCollection that matches the particular teams ID. This renders perfect, but adding a new player I can't get the view to re-render without refreshing the page.
addPlayer: function(e) {
e.preventDefault();
var $newPlayer = this.$el.find('input.player_name');
var Player = {
player_name : $newPlayer.val(),
team_id : this.model.id
}
App.data.players.create(Player);
$newPlayer.val('');
},
Here is a majority of the code. I am trying to add/create a new player and update the view with listenTo
but since this is not a traditional way to define the collection it seems I have to find a way to bind it?
Teams.js:
var Marionette = require('backbone.marionette'),
playerView = require('./player'),
PlayersCollection = require('../../collections/players');
var teamView = Marionette.CompositeView.extend({
events: {
'submit #AddPlayer': 'addPlayer'
},
initialize: function() {
// anytime something within this specific team changes, render
this.listenTo(this.model, 'change', this.render);
// build a collection of players with this team ID
this.collection = new PlayersCollection(App.data.players.where({team_id: this.model.id}));
},
addPlayer: function(e) {
e.preventDefault();
var $newPlayer = this.$el.find('input.player_name');
var Player = {
player_name : $newPlayer.val(),
team_id : this.model.id
}
App.data.players.create(Player);
$newPlayer.val('');
},
itemView: playerView,
appendHtml: function(collectionView, itemView){
collectionView.$('.the-players').append(itemView.el);
}
});
module.exports = CollectionView = Marionette.CollectionView.extend({
initialize: function() {
this.listenTo(this.collection, 'change', this.render);
},
itemView: teamView
});
Players.js:
var Marionette = require('backbone.marionette');
module.exports = playerView = Marionette.ItemView.extend({
className: 'players-wrap row',
template: require('../../../templates/teams/player.hbs'),
events: {
'mouseenter .player-image': 'playerOn',
'mouseleave .player-image': 'playerOff',
'click .player-image': 'playerClicked',
'keydown': 'on_keypress',
'click .one-point': 'onePoint',
'click .two-point': 'twoPoint',
'click .three-point': 'threePoint'
},
initialize:function() {
_.bindAll(this, 'on_keypress');
$(document).bind('keydown', this.on_keypress);
this.listenTo(this.model, 'change', this.render);
this.$el.attr('data-player', this.model.get('player_name').replace(/\s+/g,"_").toLowerCase());
window.play = this.model;
},
playerOn:function(e) {
this.$el.addClass('hover');
this.findPlayer(this.model.get('player_name'), 'add');
},
playerOff:function() {
this.$el.removeClass('hover');
this.findPlayer(this.model.get('player_name'), 'remove');
},
playerClicked:function() {
this.$el.toggleClass('hover-clicked');
this.findPlayer(this.model.get('player_name'), 'toggle');
},
findPlayer:function(name, action) {
var player = $('.data-wrap .player-data[data-player='+ name.replace(/\s+/g,"_").toLowerCase() +']');
if(action === 'toggle') { player.toggleClass('show-confirmed-clicked') }
if(action === 'add') { player.addClass('show-player-data') }
if(action === 'remove') { player.removeClass('show-player-data') }
},
onePoint:function(e) {
var addStat = parseInt(this.model.get('points')) + 1;
this.model.set('points', addStat);
this.model.save();
},
twoPoint:function(e) {
var addStat = parseInt(this.model.get('points')) + 2;
this.model.set('points', addStat);
this.model.save();
},
threePoint:function(e) {
var addStat = parseInt(this.model.get('points')) + 3;
this.model.set('points', addStat);
this.model.save();
},
on_keypress:function(e) {
this.keyStat(e, 49, 'points', 1); // 1 point
this.keyStat(e, 50, 'points', 2); // 2 points
this.keyStat(e, 51, 'points', 3); // 3 points
this.keyStat(e, 82, 'rebounds', 1); // R rebounds
this.keyStat(e, 83, 'steals', 1); // S steals
},
keyStat:function(e, keyVal, stat, number) {
if(e.keyCode == keyVal && !e.ctrlKey) {
if(this.$el.hasClass('hover')) {
var addStat = parseInt(this.model.get(stat)) + number;
this.model.set(stat, addStat);
this.model.save();
}
}
},
templateHelpers:function(){
return {
name_format: this.model.get('player_name').replace(/\s+/g, '_').toLowerCase()
}
}
});
I can't find the place where you adding your new model to the CompositeView's collection? I found only App.data.players.create(Player);
which is not the collection of CompositeView.
If App.data.players
is another Backbone.Collection which you need to keep in sync with the remote server and because of that you are using create
to persist it to the server, then change addPlayer like this:
addPlayer: function(e) {
e.preventDefault();
var $newPlayer = this.$('input.player_name');
var Player = {
player_name : $newPlayer.val(),
team_id : this.model.id
}
var newPlayer = App.data.players.create(Player);
this.collection.add(newPlayer);
$newPlayer.val('');
},
CompositeView
will catch the "add" event of collection and will append new itemView.
Please try and let me know if it helps.
Just a note: After review of your code I found that appendHtml
in Teams.js can be removed with itemViewContainer
property with value of .the-players
which will improve performance of rendering.