Michael Joseph Aubry
Michael Joseph Aubry

Reputation: 13492

Collection view inside another collection view?

Using backbone.js I have setup an appView that nicely renders two views inside (teamView and playerView), the app view has access to both collections teams and players and renders both collections like this.

this.teams.each(function(team) {
    var teamView = new TeamView({ model: team }); // New instance of the team view
    var teamHtml = teamView.render().el; //So I set the html as a list of teams
    this.$el.append(teamHtml); // Append it

    var teamPlayers = this.players.where({team_id: team.get('id')}) // Organize so that players matches his team id.
    console.log(teamPlayers)

    _.each(teamPlayers, function(player) { // Run a list of the associated players to team
        var playerView = new PlayerView({ model: player }); // New instance of the player view

        var playerHtml = playerView.render().el; //set the html as a list of players
        this.$el.append(playerHtml); //append it
        console.log(player.toJSON());
    }, this);

}, this);

Now this is obvious but the result is like this.

<ul>// The root of the app view
    <div>// The root of the team view
        <strong>Lakers</strong>
    </div>
    <li>Kobe Bryant</li>// The root of the player view
    <li>Pau Gasol</li>// The root of the player view
    <div>// The root of the team view
        <strong>Heat</strong>
    </div>
    <li>LeBron James</li>// The root of the player view
    <li>Dwayne Wade</li>// The root of the player view
</ul>

So you can see, that when I run _.each team I set it to loop the team view, then under it I set it to loop the players view, it's obvious why that result looks like that.

Where I am confused is how do I set the players view inside the team view. Of course I have tried looping the players inside the team view itself, but without looping teams I have a hard time running var teamPlayers = this.players.where({team_id: team.get('id')}) // Organize so that players matches his team id.

Thinking about it inside the view I could possibly have access to this.model.get('id') in replace of team.get('id') and use that instead, but every time I come up with an idea it fails because I am missing the smallest of details, and I end up wasting time. So I figure I can clarify this, get some learning and give out some points.

So finally I want to get an HTML result like this.

<ul>// The root of the app view
    <div>// The root of the team view
        <strong>Lakers</strong>// This isn't important just need it inside the view
        <li>Kobe Bryant</li>// The root of the player view
        <li>Pau Gasol</li>// The root of the player view
    </div>
    // You see the difference, the player view is now inside the team view and both are inside the app view.
    <div>// The root of the team view
        <strong>Heat</strong>// Again this isn't important just need it inside the view
        <li>LeBron James</li>// The root of the player view
        <li>Dwayne Wade</li>// The root of the player view
    </div>
</ul>

I feel like this is quite an easy question, but I learn best through stackoverflow. Hope you guys know what I mean here, the HTML result explains it all :)

Thanks!

FULL CODE: Just in case

/** PLAYER MODEL **/
var Player = Backbone.Model.extend({
    defaults: {
        name: "Kobe Bryant",
        team: "Los Angeles Lakers",
        number: 24,
        position: 'guard',
        hair: true
    }
});

/** TEAM MODEL **/
var Team = Backbone.Model.extend({
    defaults: {
        id: 1,
        name: 'SomeTeam'
    }
});

/** PLAYER COLLECTION **/
var PlayersCollection = Backbone.Collection.extend({
        model: Player,
});

/** TEAM COLLECTION **/
var TeamsCollection = Backbone.Collection.extend({
        model: Team,
});

/** APP COLLECTION VIEW **/
var AppView = Backbone.View.extend({
    tagName: 'ul',

    template: _.template( $('#allTemplate').html() ),

    initialize: function(options) {
        this.teams = options.teams || new Teams([]);
        this.players = options.players || new Players([]);
    },

    render: function() {
        var self = this;

        this.teams.each(function(team) {
            var teamView = new TeamView({ model: team });
            var teamHtml = teamView.render().el;
            this.$el.append(teamHtml);

            var teamPlayers = this.players.where({team_id: team.get('id')})
            console.log(teamPlayers)

            _.each(teamPlayers, function(player) {
                var playerView = new PlayerView({ model: player });

                var playerHtml = playerView.render().el;
                this.$el.append(playerHtml);
                console.log(player.toJSON());
            }, this);

        }, this);

        return this;
    }

});

/** <li> Player View </li> **/
var PlayerView = Backbone.View.extend({
    tagName: 'li',

    template: _.template( $('#playerTemplate').html() ),

    events: {
        'click button':'alert'
    },

    initialize: function() {
        //console.log(this.model.set('name', 'Lance'));
    },

    render: function () {
        this.$el.html( this.template( this.model.toJSON() ) );
        return this;
    },

    alert: function() {
        alert('DONE! ' + this.model.get('name') )
    }

});

/** <div> Team View </div> **/
var TeamView = Backbone.View.extend({
    tagName: 'div',

    template: _.template( $('#teamTemplate').html() ),

    render: function () {
        this.$el.html( this.template( this.model.toJSON() ) );
        return this;
    }

});

var playersCollection = new PlayersCollection([
    {
       name: 'Kobe Bryant',
       team: 'Los Angeles Lakers',
       team_id: 1,
       number: 24
    },
    {
       name: 'Lebron James',
       team: 'Miami Heat',
       team_id: 2,
       number: 6
    },
    {
       name: 'Dwayne Wade',
       team: 'Miami Heat',
       team_id: 2,
       number: 3
    },
    {
       name: 'Michael Beasley',
       team: 'Miami Heat',
       team_id: 2,
       number: 3
    },
    {
       name: 'Ron Artest',
       team: 'New York Knicks',
       team_id: 3,
       number: 15 
    },
    {
       name: 'Karl Malone',
       team: 'Los Angeles Lakers',
       team_id: 1,
       number: 33
    },
    {
       name: 'Damion Lillard',
       team: 'Portland Trailblazers',
       team_id: 4,
       number: 3 
    },
    {
       name: 'Westly Matthews',
       team: 'Portland Trailblazers',
       team_id: 4,
       number: 55 
    },
    {
       name: 'Wilt Chamberlin',
       team: 'Los Angeles Lakers',
       team_id: 1,
       number: 17 
    }
]);

var teamsCollection = new TeamsCollection([
    {
       id: 1,
       name: 'Lakers'
    },
    {
       id: 2,
       name: 'Heat'
    },
    {
       id: 3,
       name: 'Knicks'
    },
    {
       id: 4,
       name: 'Trailblazers'
    }
]);

// RUN!!
var appView = new AppView({ players: playersCollection, teams: teamsCollection });

$(document.body).append(appView.render().el);

Upvotes: 0

Views: 58

Answers (1)

Niranjan Borawake
Niranjan Borawake

Reputation: 1638

What you seem to be doing is appending Team HTML then Players HTMLthen again Team HTML and Players HTML and so on. You should rather add Players HTML to Team HTML and then add Team HTML to your el. Try if this works :

    this.teams.each(function(team) {
        var teamView = new TeamView({ model: team });
        var teamHtml = teamView.render().el;

        var teamPlayers = this.players.where({team_id: team.get('id')})
        console.log(teamPlayers)

        _.each(teamPlayers, function(player) {
            var playerView = new PlayerView({ model: player });

            var playerHtml = playerView.render().el;
            // Add player HTML to Team HTML
            $(teamHtml).find('div').append(playerHtml);
            console.log(player.toJSON());
        }, this);
       // Add Team HTML to el
        this.$el.append(teamHtml);

    }, this);

This is just w.r.t to what you are doing but you should think of structuring your views in a better way.

Upvotes: 1

Related Questions