Search code examples
backbone.jstwitterunderscore.jslodashunderscore.js-templating

Read Countless Backbone Tutorials But Still Missing Something


I've read countless posts here on StackExchange as well as countless tutorials across the Internet but I seem to be just off from understanding basic Backbone use and implementation.

I'm attempting to build a custom Twitter timeline using pre-filtered JSON that is generated from a PHP file on my work's server.

I feel close but I just can't seem to get things to work. At times I'm able to view 20 tweets in my console but am only able to get 1 tweet to render via my template.

Here is my current Backbone setup:

(function($){

    if(!this.hasOwnProperty("app")){ this.app = {}; }
    app.global = this;

    app.api = {};

    app.api.Tweet = Backbone.Model.extend({
       defaults: {} 
    });

    app.api.Tweets = Backbone.Collection.extend({
        model: usarugby.api.Tweet,
        url: "https://custom.path.to/api/tweets/index.php",
        parse: function(data){
            return data;
        }
    });

    app.api.TweetsView = Backbone.View.extend({
        el: $('#tweet-wrap'),
        initialize: function(){
            _.bindAll(this, 'render');
            this.collection  = new app.api.Tweets();
            this.collection.bind('reset', function(tweets) {
                tweets.each(function(){
                    this.render();
                });
            });
            return this;
        },
        render: function() {
            this.collection.fetch({
                success: function(tweets){
                    var template =  _.template($('#tweet-cloud').html());
                    $(tweets).each(function(i){
                        $(this).html(template({
                            'pic': tweets.models[i].attributes.user.profile_image_url,
                            'text': tweets.models[i].attributes.text,
                            'meta': tweets.models[i].attributes.created_at
                        }));
                    });
                    $(this.el).append(tweets);
                }
            });
        }
    });

    new app.api.TweetsView();

}(jQuery));

And here is my current HTML and template:

<div id="header-wrap"></div>      

<div id="tweet-wrap"></div>

<script type="text/template" id="tweet-cloud">
    <div class="tweet">
        <div class="tweet-thumb"><img src="<%= pic %>" /></div>
        <div class="tweet-text"><%= text %></div>
        <div class="tweet-metadata"><%= meta %></div>
    </div>
</script>

<script> if(!window.app) window.app = {}; </script>

I also have a CodePen available for testing. Any advice would be greatly appreciated.


Solution

  • Like the comments suggest, additional reading and code rewrite may be needed. The simplest example for a view rendering multiple views is here adrianmejia's backbone tutorial example.

    The snippet below includes an additional view and a couple of added functions along with updating the render and initialize functions. Search for 'cfa' to review changes.

    (function($){
        
        if(!this.hasOwnProperty("app")){ this.app = {}; }
        app.global = this;
    
        app.api = {};
    
        app.api.Tweet = Backbone.Model.extend({
            idAttribute: 'id_str'
        });
    
        app.api.Tweets = Backbone.Collection.extend({
            model: app.api.Tweet,
            url: "https://cdn.usarugby.org/api/tweets/index.php",
            parse: function(data){
                return data;
            }
        });
        
        app.api.TweetView = Backbone.View.extend({
            tagName: 'div',
            template: _.template($('#tweet-cloud').html()),
            initialize: function(){
                
            },
            render: function(){
                var j = {};
                j.pic = this.model.get('user').profile_image_url;
                j.text = this.model.get('text');
                j.meta = this.model.get('meta');
                this.$el.html(this.template(j));
                return this;
            },
        });
        
        app.api.TweetsView = Backbone.View.extend({
            el: $('#tweet-wrap'),
            initialize: function(){
                this.collection = new app.api.Tweets();
                this.collection.on('reset', this.onReset, this);
                this.collection.on('add', this.renderATweet, this);
                this.collection.fetch();
            },
            
            onReset: function(){
                this.$el.html('');
                this.collection.each(this.renderATweet, this);
            },
            renderATweet: function (tweet) {
                var tweetView = new app.api.TweetView({ model: tweet });
                this.$el.append(tweetView.render().el);
            },
        });
    }(jQuery));
    
    
        $(document).ready(function(){
            new app.api.TweetsView();
        });
    <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
    <script src="https://static.usarugby.org/lib.min.js"></script>
    
    <div id="header-wrap"></div>
    
    <div id="tweet-wrap"></div>
    
    <script type="text/template" id="tweet-cloud">
        <div class="tweet">
            <div class="tweet-thumb"><img src="<%= pic %>" /></div>
            <div class="tweet-text">
                <%= text %>
            </div>
            <div class="tweet-metadata">
                <%= meta %>
            </div>
        </div>
    </script>
    
    <div id="footer-wrap"></div>
    
    <script>
        if(!window.app) window.app = {};
    </script>