How to reset/restart backbone application - javascript

I'm building a little quiz game using backbone.js
Once you get to the end of the quiz you have the option to start again.
How can I achieve this? I've tried recalling the initialize function, as well as the first function that gets fired when you start the game. This is just returning errors. The two calls are success but a subsequent function for rending each question is failing.
I think I need to empty my model/collection. This is my first outing with Backbone, I'm still trying to get my head around how every works.
Any help, greatly appreciated.

You could use the backbone router (don't forget to start it):
So in your game view, you'd have an event which triggered when the start again button was clicked. This event would trigger a function which would redirect the user to a newgame route. You could also setup a function in the router to close your old view. This is important to avoid zombie views
e.g. view
//initialize code
//...
events: {
'click .startAgainButton':'restart'
}
restart: function(e) {
e.preventDefault();
window.location.href = '#/new_game';
}
//rest of view code...
e.g. router
//router code
routes: {
"new_game":"reset"
},
trackView: function (next) {
if (this.current) this.current.close();
this.current = next;
},
//kill zombie views
close: function () {
this.undelegateEvents();
this.$el.off();
this.$el.children().remove();
},
reset: function() {
this.trackView(new View());
}

Related

Refresh hasherJS/crossroadsJS routes

I’m utilizing crossroadsJS and hasherJS on an SPA powered by handlebarsJS. In retrospect I probably should have built the whole thing on Ember, but this late in it’s not wise to start over.
I have hash routes set up that switch my handlebars templates in and out based on whatever was clicked. I’m able to move backwards and forwards between the routes with no problem. However, if I refresh the page, I’m always brought back to my #/home view. I’ve done some research into window.onhashchange and window.onbeforeunload, but none of these seem to be solving the issue.
I have a very specific way of how I’m handling my views. I have a global views object constructed like so:
views.procedures = function (template) {
this.initialize = function () {
this.el = $('<div/>');
this.el.attr('id', 'procedures');
this.el.on('click', '.returned-list li a', this.toResults); // list of API objects by name
};
this.render = function () {
var parts = {
title: 'Procedures View',
};
this.el.html(template(parts));
return this;
};
this.toResults = function () {
cache.justClicked = $(this).attr('data-id');
crossroads.addRoute('procedures/{name}', function () {
api.endpoints.procedure(cache.justClicked); // constructed elsewhere
});
};
this.initialize();
};
I mention this because I can’t simply add in JQuery listeners for any type of hash changes in a $(document).ready() or $(window).onhashchange
I’ve read through both the hasherJS and crossroadsJS documentations multiple times, but I’m not able to think of anything to solve the refresh issue. Thanks in advance for any help.
I would need more information from you, but I'm assuming you're doing
var DEFAULT_HASH = 'home';
if (! hasher.getHash()) {
hasher.setHash(DEFAULT_HASH);
}
This is basically saying your default route is always going to be your home route, which is why you're seeing it when you refresh your current route. Try the following:
var DEFAULT_HASH = 'home', url = hasher.getBaseURL();
if (hasher.getURL() === url) {
hasher.setHash(DEFAULT_HASH);
}
This will check to see what your base URL is (the one that's loaded when you first visit the page) and append a #/home route to the base URL, allowing you to refresh your currently viewed route.
Hope this helps.

Backbonejs is calling collection's fetch method in another function good idea? If not what should i use?

I am trying to implement endless scrolling with Backbonejs. My view initializes a collection and calls fetch fetch function.
My view
var app = app || {};
app.PostListView = Backbone.View.extend({
el: '#posts',
initialize: function( ) {
this.collection = new app.PostList();
this.collection.on("sync", this.render, this);
this.collection.fetch();
this.render();
},
render: function() {
/*render posts*/
}
});
In my page I added the following code. It checks if the the user at the bottom of the page. If yes then it checks if the view is initialized. If yes then call that view fetch function of the view's collection object.
var app = app || {};
$(function() {
var post_view;
$(window).scroll(function() {
if(($(window).scrollTop() + $(window).height() == getDocHeight()) && busy==0) {
if(!post_view){
post_view = new app.PostListView();
} else {
post_view.collection.fetch();
}
}
});
});
So far this code is working. I am not sure if this is the right approach or not?
It's not a bad option; it works, and Backbone is making that collection available for you. But there's a couple of other options to consider:
Move that collection.fetch into a method getMoreItems() inside your PostListView, and call it within your else block. That way you're encapsulating your logic inside the view. Your app is more modular that way, and you can make your scrolling smarter without updating the rest of your app.
Move the scroll listener inside your PostListView. I'd probably put this within your PostListView's initialize function. Again, this reduces dependencies between the various parts of your app - you don't have to remember "Whenever I create a PostListView, I must remember to update it on scroll." By setting that event listener within the PostListView itself, all you have to do is create it. Backbone's general philosophy is to have small, independent components that manage their own state; moving the event listener inside would fit with that.

redesigning backbone page and handling events

I am still kind of new to backbone and I have a question. I am currently working on a previously created backbone view. This view is responsible for all the saving within the application. The class is becoming exceedingly large and I wanted to split out some of the events/methods/function to their own "sub class", if that is possible. For example, I have a group of events and functions that are responsible for a specific task. I would like to move those event and functions to their own js page, in a sub folder. The problem is that the events are being called. Here is a general overview of how the class is setup:
var myClass= myClassBaseClass.extend({
events: {
.... all my events here,
'click .eventOneButton': 'eventOne',
},
initialize: function (options) {
//initialize stuff here
},
postRender: function (renderOptions) {
//post render here
},
preRender: function (renderOptions, html) {
return html;
}, template: function (renderOptions) { //template stuff },
//...etc.
//my events
//eventOne was here, now its moved to its own file
});
My new file is in a subfolder, and looks like this:
var myClassSubClass= myClass.extend({
eventOne: function(e){
//event stuff here
}
});
So, is what am I doing wrong? Why wont the event get caught in the second file?
thanks
jason

How to add Ember to the onDeviceReady event in Phonegap?

In Phonegap we wait for the onDeviceReady event for our code to start executing. Following this path I added my Ember app like this:
var App = null; // Ember
var phonegap = {
initialize: function () {
this.bindEvents();
},
bindEvents: function () {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function () {
App = Ember.Application.create({});
// Now I can start adding my Ember stuff, but
// even for a tutorial app that is somewhere between
// 100 to 200 lines and it will be harder to maintain
// inside here. So I wrap that with a function
// and put it outside.
addMyEmberStuff();
}
}
function addMyEmberStuff() {
// Ember Routes, Controllers, Views etc.
App.Router.map(function() {
});
App.IndexController = Ember.Controller.extend({
init: function () {
this._super();
// device API calls
// create/render View(?)
// trigger DOM events etc
}
});
}
I know that I can initialize an Ember app outside of the onDeviceReady and everything will keep working. The problem is that the index page of the app has calls to the device API and also some DOM events must occur before Ember starts working its magic.
This seems to me the proper way of doing things.
How do I solve this design for the case of a larger app where I want to have each Ember Controller/View/Template in its own file? I can't keep wrapping everything with the addMyEmberStuff function.
You want prevent you Ember application from starting before PhoneGap is ready. To do this you can use defer and advance readiness.
App = Ember.Application.create()
App.Post = ...
App.PostsRoute = ...
App.PostsController = ...
App.deferReadiness();
document.addEventListener('deviceready', function() {
App.advanceReadiness();
});
Once advanceReadiness is called Ember will begin routing for your application.

Event is firing multiple times (Parse.com)

I'm writing an app in Parse, using the JavaScript framework. In my view, I have a link with the class 'new-page'. In the JS code, I have:
events: {
"click .new-page" : "createPage",
}
createPage is:
createReel: function() {
var self = this;
// Get current pagelist
var pages= new PageList;
pages.query = new Parse.Query(Page);
pages.query.equalTo("owner", Parse.User.current());
pages.query.ascending("order");
pages.fetch({
success: function(pagelist) {
var newPage = new Page;
newPage .save({
success: function(newpage) {
// Redirect to page edit
new PageEditView();
}
});
}
});
}
First time round, this works fine - the new page is created, and it goes to edit mode for that page. But if I then go back to the view with the 'Add Page' button and click it again, I get 2 new pages. If I do it again, I get 4, and so on.
I assume the event is 'building up', so that the more times the button is clicked, the more times the event gets fired.
I'm not sure where to start looking.
Late answer, but I just had a similar issue.
The mistake I made was that I created the view instance again every time I needed it.
That is not how Backbone is ment to work.
Views are (usually) created once. And when their model changes, the are being rendered again.
you seem to be instantiating your view every time the user saves at this line
PageEditView();
That's when the events stack up.
Instantiate that view once when you start up the page and then render it whenever you update the model for that view.
In native bakbone, event handlers can listen to model changes. Somehow it won't work in the Parse backbone version (or I can't get it to work). So for now, I do that manually with
PageEditView.model = model
PageEditView.render();
Make sure you undelegate events before calling the new PageEditView.

Categories

Resources