Justin Davis
Justin Davis

Reputation: 305

Backbone Collection not rendering when going back

I have a Backbone app I'm building with Trigger.io, and have a bit of confusion why data is disappearing when I click the back button in the phone toolbar.

Here's the setup:

I have a view, SearchResultsView, that looks like this (Trigger.io code removed for brevity):

window.SearchResultsView = Backbone.View.extend({

initialize: function() {
    this.template = _.template($('#searchResultsView-template').html());
},

render: function() {

    var self = this;
    var renderedContent = this.template();
    $(this.el).html(renderedContent);

    if (window.resultsCollection) {
        self.drawList(window.resultsCollection);
    }

    return this;
},

events: {
    "click #submitQuery" : "processClick"
},

drawList: function(collection) {

        collection.each(function(place){
            window.console.log(place.get("name"));
            $("#resultsList").append("<li><a href='#locationdetail/"+place.id+"' class='link'>" + place.get("name") +"</a></li>");
        });
},

processClick: function() {

    var self=this;
    this.querystring = $("#searchBox").val(); //get the query

    window.resultsCollection = new Places(null, {query: this.querystring}); 
    window.resultsCollection.fetch(); //this is fetching via a call to the FourSquare API, and populating the models in the collection with that data

    window.resultsCollection.bind('reset', function(collection){
        self.drawList(collection);
    });
}

});

Here is the template:

<script type="text/template" id="searchResultsView-template">
<div id="searchbar"></div>
<h1>Results Bitch</h1>
    <input type="text" id="searchBox"></input>
    <input type="submit" id="submitQuery"></input>
    <ul data-role="listview" id="resultsList">
    </ul>
    <a href="locationdetail">Click me</a>
</script>

And here is the router:

searchresults: function() {
    this.searchresults = new SearchResultsView({});
    $('#container').empty();
    $('#container').append(this.searchresults.render().el);
},

Here's how it works in practice: when I initially load the page, there's no list of results (as it should be). I enter the query and execute the search, and it comes back, populating the list as it should. Then, I'll click on an item to go to another view, and when I click "Back", the list is empty again.

What I'm trying to do is test to see if the collection still exists, and if it does, go ahead and re-render the list, but it's never rendering the list. The collection does exist, as I'm able to log it to the console and see the data.

My suspicion is that the #resultsList element isn't available yet, and so when it goes to append the results to it, it can't find it, thus not showing anything.

So:

Hopefully I'm clear enough. I haven't included the model and collection, to keep things short. If those will help, I'm happy to include them (although, I tend to think this is a view issue).

Thanks!

Upvotes: 1

Views: 659

Answers (1)

Venkat Kotra
Venkat Kotra

Reputation: 10773

The issue is with the way you are attaching the rendered view in the calling method.

In the below router method

searchresults: function() {
        this.searchresults = new SearchResultsView({});
        $('#container').empty();
        $('#container').append(this.searchresults.render().el);
    },

You should first attach the initialised view's el to an element in the parent view and then render it.

This is necessary because sometimes child view might search for an html element in the html created and attached within it self (as in your case). If the view is not attached before rendering, the html created while rendering will not actually be part of the windows.document and therefore not searchable (its just in memory).

In your case, you are trying to search for an element which is not yet part of window.document.

 var SearchResultsView = Backbone.View.extend({
    ...
        drawList: function(collection) {
                collection.each(function(place) {
                    window.console.log(place.get("name")); // this proves the collection is still here. But, it's not rendering? Because the DOM isn't finished rendering yet?
                    $("ul#resultsList").append("<li><a href='#locationdetail/" + place.id + "' class='link'>" + place.get("name") + "</a></li>");
                });
            },
...
});

Following change should fix the issue.

 searchresults: function() {
                this.searchresults = new SearchResultsView({});
                $('#container').empty();
                $('#container').append(this.searchresults.el);
                this.searchresults.render();
            },

The SearchResultsView's el is now part of the window.document. Any html created and attached within the view is also part of the window.document and searchable.

Here is the sample working html file with backbone code I wrote, based on your code.

http://jsfiddle.net/venkat_kotra/rHWPL/

Upvotes: 1

Related Questions