0
votes

Question: I am using backbone.js I have a player view for one player, the root element for this view is a <li></li> list item node.

Then I have a players view that shows all the players in the collection, the root element for this view is a <ul></ul>. (Pretty simple stuff!)

The result for this would be.

<ul> //The players collection root for the players collection view
    <li>Kobe Bryant is on the lakers</li> // The player model root element for the player model view
    <li>LeBron James is on the heat</li> // The player model root element for the player model view
</ul>

My model's attributes consist of name, team.

[
    {name: 'Kobe Bryant', team: 'lakers'},
    {name: 'LeBron James', team: 'heat'}
]

How do I loop (or do whatever is best) so that my view results like this.

<ul class="lakers"> 
    <li>Kobe Bryant is on the lakers</li>
</ul>
<ul class="heat"> 
    <li>LeBron James is on the heat</li>
</ul>

Even Better wouldn't I need to do a teams collection view. Then write some code to match each player to his team? So a result something like this.

<div class="lakers">// Teams collection root element
    <ul>// Players collection root element 
        <li>Kobe Bryant is on the lakers</li>// Player model root elemnt
    </ul>
</div>
<div class="heat">// Teams collection root element
    <ul>// Players collection root element 
        <li>LeBron James is on the heat</li>// Player model root elemnt
    </ul>
</div>

I took an attempt at this but I am thinking the way I am instantiating each view is wrong, or I am just doing something wrong, so if it's a good idea to put a collection of players in a collection of teams, how do I get a result like above, where I can have a parent element which is the team, then a list of the players for that team inside?


My Ideas & Code: I am thinking inside the players view I can write some stuff to organize each model by team, like.

_.each(this.collection.where({team: "lakers"}), function(model) {
       var playerView = new PlayerView({ model: model});
       this.$el.append(playerView.render().el);
       this.$el.addClass('lakers');
}, this);

Well there are obvious issues with this because, we write all this just to add a class to the root, and if we did this again it would keep adding to the root <ul class="lakers miami"> That doesn't help.

I am running low on ideas, I get the picture I know I want to categorize each player but I cant quite figure it out. I am leaning towards a teams collection of players collection, I am just confused how to match this.team.get('name') == this.player.get('name') //Something relative to this. I am not sure if that actually makes sense, ill admit I need help lol. Happy Thanksgiving everyone, I doubt anyone is on stackoverflow today.

1

1 Answers

1
votes

hm...you don't really need to match players and teams.

Let's think from the backend's (data) perspective:

you have a Player model and a Team model a player belongs to a team, and a team has many players. in order to find which team a player belongs to, all we have to do is to add a foreign key :team_id to the Player model:

team_id, is the id of the team. usually you don't want to use name, because: 1. it may be changed, and you don't want to update all the players when you change the team name. 2, it's not efficient. (string field vs integer field) ID is always unique, and you should never change them.

let's say you have Kobe, and Lakers

//here's Kobe
var kobe = {
  id: 24,  //yea, all models should have their own primary key - id
  name: 'Kobe',
  team_id: 3
}

//this is Lakers in the database
var lakers = {
  id: 3,  //id for lakers,
  name: 'Lakers'
}

now, how do you find the name of the team that Kobe belongs to?

let's say, you have a collection of teams (all the teams)

var teams = new Teams([ ..all the teams! .. ]);

//to find the name of the team

teams.get(kobe.get('team_id')).get('name');  // you find the model first, then read its name.

You can wrap players inside teams, or assign teams to players, but you don't have to. It really depends on what's the main purpose of your app.(or view) In some large Apps, you may find places where people wrap team into player instances, and other places where players are wrapped under teams;

in your case, it seems you haven't decided what to do with your view yet. and, there's nothing wrong to pass two collections into one view(but when you have to do this, usually it means you need to rethink about how you should organize your page)

PlayersView = Backbone.View.extend({

  initialize: function(options) {
    //in case teams/players is not passed to the view, we just set them to empty collections
    this.teams = options.teams || new Teams([]);
    this.players = options.players || new Players([]);
  }

});

When you instantiate your view, pass both collections:

var playersView = new PlayersView({
  players: players,
  teams: teams
});

and in your template, if you are just listing all the players:

<% _.each(players, function(player) {
   <% var team = teams.get(player.get('team_id'))%>
   <%= player.get('name') %> belongs to <%= team.get('name') %>
}) { %>

or if you are listing teams and their players: //in this case, you really should create children views instead of doing it all in one template

<% _.each(teams, function(team) {
   <ul class="<%= team.get('name')%>">
     <% var teamPlayers = players.where({team_id: team.get('id')}) %>
         <% _.each(teamPlayers, function(player) {
           <li>
             <%= player.get('name') %> belongs to <%= team.get('name') %>
           </li>
         <% }) %>
   </ul>
}) { %>

=================

Edit:

In your code

_.each(this.collection.where({team: "lakers"}), function(model) { var playerView = new PlayerView({ model: model}); this.$el.append(playerView.render().el); this.$el.addClass('lakers'); }, this);

you are repeating addClass, in _.each() which is not necessary. since you have already decided you want to find lakers players, you should do it in the template, or just assign it as the root element's className, assuming each team is in a view:

 //this is a view for a Team, it's model should be Team
 TeamView = Backbone.View.extend({
   className: function() {
     return this.model.get('name');
   }
 });