Search code examples
javascriptjquerybackbone.jsrequirejsbackbone-views

How to reference collection's data in render() when fetched in initialize() in BackboneJS?


I'm trying to get my head around the correct way to organise a view when it's calling multiple collections (some which only need to be fetched initially and some which are triggered by events).

I have a collection 'Genres_collection()' which fetches a list of genres from a database:

Genres_collection:

define([
    'jquery',
    'underscore',
    'backbone',
    'models/genre_model'
],function($,_,Backbone,Genre_model){
    var Genres_collection = Backbone.Collection.extend({
        model: Genre_model,
        url: '/api/genres',
        parse: function(response){
          return response;
        }
    })
    return Genres_collection;
});

Genres_model:

define([
    'jquery',
    'underscore',
    'backbone'
],function($,_,Backbone){
    var Genre_model = Backbone.Model.extend({
        defaults: {
            'title': 'Untitled Track'
        }
    })
    return Genre_model;
});

I have a view which, amoung other things, I want to fetch the genres on initialize() and then reference the collection's data in render. From my understanding, initialize is triggered only when a view is initialted (thus the name) and render() is called any number of times (ie: when an event is triggered). So, my thought is that render is used to render and 're-render' a view when actions are taken.

Therefore, I have the following view code:

Search_view:

define([
    'jquery',
    'underscore',
    'backbone',
    'collections/tracks',
    'collections/genres',
    'text!templates/search_view_title.html',
    'text!templates/search_view.html'
],function($,_,Backbone,Tracks_collection,Genres_collection,Search_view_title_template,Search_view_template){
    var Search_view = Backbone.View.extend({
        el: $('#app'),
        
        initialize: function(){
            this.collection = new Tracks_collection();
            this.genre_collection = new Genres_collection();
            this.genre_collection.fetch();
        },
        search: function(searchtype){
            switch(searchtype){
                case 'genre':
                    console.log('genre changed');
                    this.collection.fetch({
                        data: {limit: 30, type:'genre',genre_id:$('#genre_select').val()}
                    });
                break;
                case 'search':
                    console.log('search changed');
                    this.collection.fetch({
                        data: {limit: 30, type:'search',keyword:$('#keyword').val()}
                    });
                break;
            }
        },
        render: function(){
            // MAKE 'THIS' ACCESSIBLE
            var that = this;

            
            console.log(this.genre_collection);

            var template = _.template(Search_view_template);
            var template_vars = {genres: this.genre_collection};
            console.log(template_vars);
            var template_html = template(template_vars);
            that.$el.find('#container').html(template_html);
            


            this.collection.bind('add',function(collection){
                console.log('collection has been changed');
            })
                      
        }
    });

    return Search_view;

});

However, when I try to print the genre_collection in render() to the console or pass it to the template, I don't get the data from the collection which was fetched in initialize().

  1. Is this the correct way to organising this type of call?
  2. Where is it going wrong? How can I get it to pass the data from this.genre_collection in render()?

I am using requirejs and I can confirm that the initialize() and render() call is being called as I have written simpler views which execute the code fine.


Solution

  • In this case, your this = that you should write

    console.log(that.genre_collection) 
    

    instead of

    console.log(this.genre_collection);
    

    Add this to your initialize function

    this.listenTo(this.genre_collection , 'change', this.render);
    

    you can change your genre_collection parse nmethod so it will return your data

    parse: function(response){
        return response.genres
    }