RyanP13
RyanP13

Reputation: 7743

Render backbone models from collection sequentially on click

I have pulled down a collection of models from the server like so:

I only want to render the first model in the view, and then when the user clicks a button in the rendered view we render the next model from the collection in sequence.

I cannot render the whole view and then show/hide as these are quiz questions and people will most likely figure out how to cheat that way!

My current view:

define([
    'domLib',
    'underscore',
    'backbone',
    'router',
    'config',
    'collection/quiz',
    'text!template/quiz.html'
    ],
    function($, _, Backbone, Router, AppConfig, QuestionList, QuizTemplate) {

        var QuizView = Backbone.View.extend({
            el: '[data-view="main-content"]',
            template: _.template(QuizTemplate),
            initialize: function onInitialize(param){
                this.collection = new QuestionList();
                this.collection.fetch({
                    reset: true,
                    data: {
                        categoryId: param.id || AppConfig.constants.CATEGORY,
                        limit: AppConfig.constants.QLIMIT
                    }
                });
                this.collection.bind('reset', this.render, this);
            },
            render: function onRender(){
                this.$el.html(this.template({questions: this.collection.toJSON()}));
            }
        });

        return QuizView;
});

My collection; the base64 decoding is there to decode the encoded response from the server:

define([
    'domLib',
    'underscore',
    'backbone',
    'router',
    'config',
    'model/quiz'
    ],
    function($, _, Backbone, Router, AppConfig, Quiz) {

        var QuestionList = Backbone.Collection.extend({
            model: Quiz,
            url: AppConfig.api.game.quiz,
            parse: function onParse(response){

                var self = this;

                _.each(response, function(obj, index){
                    _.each(obj, function(val, key, list){
                        if(key !== 'id'){
                            obj[key] = self.decode64(val);
                        }
                    });
                    self.push(obj);
                });

                return this.models;
            },
            decode64: function onDecode(data){

                var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
                var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
                    ac = 0,
                    dec = '',
                    tmp_arr = [];

                if (!data) {
                    return data;
                }

                data += '';

                do { // unpack four hexets into three octets using index points in b64
                    h1 = b64.indexOf(data.charAt(i++));
                    h2 = b64.indexOf(data.charAt(i++));
                    h3 = b64.indexOf(data.charAt(i++));
                    h4 = b64.indexOf(data.charAt(i++));

                    bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;

                    o1 = bits >> 16 & 0xff;
                    o2 = bits >> 8 & 0xff;
                    o3 = bits & 0xff;

                    if (h3 == 64) {
                    tmp_arr[ac++] = String.fromCharCode(o1);
                    } else if (h4 == 64) {
                    tmp_arr[ac++] = String.fromCharCode(o1, o2);
                    } else {
                    tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
                    }
                } while (i < data.length);

                dec = tmp_arr.join('');

                return dec;
            }
        });

        return QuestionList;
});

Upvotes: 0

Views: 208

Answers (1)

machineghost
machineghost

Reputation: 35790

As @Loamhoof mentioned, one approach would be to add a currentQuestion property to your collection, then give it some sort of getNextQuestion method which increments currentQuestion and then returns this.at(this.currentQuestion).

Another approach would be to use the Backbone.Collection shift method:

Remove and return the first model from a collection. Takes the same options as remove.

So instead of yourCollection.getNextQuestion() you'd just call yourCollection.shift(). However, this modifies the collection (removing the question you shift out), so if you want to be able to go backwards through the collection you'll probably want to use the currentQuestion appropach.

Upvotes: 1

Related Questions