Backbone.js routes don't fire correctly - backbone.js

My code is as follow:
var AppRouter = Backbone.Router.extend({
_data: null,
_length: 0,
_index: null,
_todos: null,
routes: {
"*action": "index",
"category/:name": "hashcategory"
},
initialize: function(options){
this._data = options.data;
this._todos = new TodosCollection(options.data);
this._length = this._todos.length;
this._index = new CategoriesView({collection: this._todos});
},
index: function(){
this._index.render();
},
hashcategory: function(name){
console.log('started');
}
});
initializeRouter = function (router) {
Backbone.history.start({ pushState: true });
$(document).on('click', 'a:not([data-bypass])', function (evt) {
var href = $(this).attr('href');
var protocol = this.protocol + '//';
if (href.slice(protocol.length) !== protocol) {
evt.preventDefault();
router.navigate(href, true);
}
});
return router;
};
var start = function(){
p = $.ajax({
url: 'data/todolist.json',
dataType: 'json',
data: {},
success: function(data) {
var approuter = initializeRouter(new AppRouter({data: data}));
}
});
};
I have a <a> link in my html which has a href = "category/num1" attibute. But every time I click the link, it always shows a security error in firebug. Actually I just have one index.html page, what I want to do is append a string to it to make a fake html page like folder/index.html/category/num1 and all of the things will still be rendered in current page. But the url shown to me when the link is hovered is folder/category/num1. Because this path actually doesn't exist in my folder, I think that's why it shows a security error.
So how should I fix it? Should I create another html page and the corresponding folder? Or can I make all of the routing in one index.html page?

Try putting a # in the href, like
href = "#category/num1"

Related

Backbone views events firing repeatedly in routes

I have a backbonejs application that contains a router file and some views , and also i'm using requirejs to add views to routes and add templates to views. here is my codes :
routes.js
var AppRouter = Backbone.Router.extend({
routes: {
"": "getLogin",
"login": "getLogin",
"register": "getRegister",
"forget-password": "getForgetPassword"
},
getLogin: function() {
require(['views/auth/loginView'], function(view) {
view = new this.LoginView();
});
},
getRegister: function() {
require(['views/auth/registerView'], function() {
view = new this.RegisterView();
});
},
getForgetPassword: function() {
require(['views/auth/forgetPasswordView'], function() {
view = new this.ForgetPasswordView();
});
},
});
var route = new AppRouter();
Backbone.history.start();
loginView.js
var LoginView = Backbone.View.extend({
el: '#wrapper',
initialize: function() {
NProgress.start();
this.render();
},
render: function() {
require(['text!partials/auth/login.html'], function(t) {
var json = { title: 'title', formName: 'frmLogin' };
var template = _.template(t);
$('#wrapper').html(template(json));
});
NProgress.done();
},
events: {
"click #btnLogin": "login"
},
login: function(e) {
e.preventDefault();
alert('some message');
}
});
also registerView.js and forgetPasswordView.js are similar to loginView.js.
now! when i change routes multiple times and hit #btnLogn it fires alert('some message'); function multiple times...!
Have you tried un-delegating the events in the view, on route change?
You could override the route method (annotated source) in your AppRouter and run it before each route is rendered.
route: function(route, name, callback) {
view.undelegateEvents();
return Backbone.Router.prototype.route.apply(this, arguments);
}
Note: Just an idea, not tested with your code

How to fix the Back Button Behavior (should be clicked Twice) in backnone?

I am working on a backbone application with multiple views. The navigation between the view is done by calling router.navigate('view', {trigger:true, replace:false}). I have a login page that has it own structure and the other views has another structure (very different). When I click on the login button the view changes along with the hash. The problem is when I click on the back button of the browser it doesn't go back to the login page but load the home page again, then I am required to click again on the back button in order to go back to the login page. In addition, when navigating to other pages sometimes the view handler isn't called when I click on the back button. I always use the router.navigate('view', {trigger:true, replace:false}) function to navigate between the views.
Here is my Router :
define([ "jquery", "backbone", 'views/header', 'views/sidePanel' ], function($,
Backbone, Header, sidePanel) {
var ApplicationRouter = Backbone.Router.extend({
_header : null,
_sidePanel : null,
routes : {
"" : "login",
"home" : "home",
"perspectives" : "perspectives"
},
initialize : function() {
this.firstPage = true;
Backbone.history.start();
},
login : function() {
var self = this;
require([ 'views/loginPageView' ], function(loginView) {
self.changePage(new loginView(), true);
});
},
home : function() {
var self = this;
require([ 'views/homePageView' ], function(homeView) {
self.changePage(new homeView(), false);
});
},
perspectives : function() {
var self = this;
require([ 'views/treePerspectivesView' ],
function(perspectivesView) {
self.changePage(new perspectivesView(), false);
});
},
changePage : function(page, noPanel) {
var deferred = $.Deferred();
console.log(page);
$page = $(page.el);
if (this.firstPage) {
if (!noPanel) {
self._sidePanel = new sidePanel({
el : ".left_col"
});
self._header = new Header({
el : '.top_nav'
})
$page.attr('class', 'right_col');
$page.attr('role', 'main');
$('.main_container').append($page);
} else {
$('body').append($page);
}
page.render();
} else {
if (!noPanel) {
$('.right_col').remove();
$('.right_col').unbind();
$page.attr('class', 'right_col');
$page.attr('role', 'main');
$('.main_container').append($page);
}else{
$('body').html($page);
}
page.render();
}
if (this.firstPage) {
this.firstPage = false;
}
deferred.resolve();
return deferred;
}
});
return ApplicationRouter;
})
This is how I navigate to the home view :
login:function(){
console.log("Login Clicked");
this.remove();
this.unbind();
router.fromBack=true;
router.navigate('home', {trigger: false, replace: false});
//router.home();
},
Is there a better way to navigate between the views to fix this problem (Maybe calling the changePage function with the has as a parameter) ?
How t fix the issue of the Back Button ?
Thank You.
I'd recommend you to use the count navigation hits for a router. Also you should create a back route for this job. Like this:
AppRouter.prototype.initialize = function() {
this.routesHits = 0;
Backbone.history.on('route', (function() {
this.routesHit++;
}), this);
};
AppRouter.prototype.back = function() {
if (this.routesHits > 1) {
this.routesHits = this.routesHits - 2;
window.history.back();
} else {
if (Backbone.history.getFragment() !== '/app') {
this.routesHits = 0;
}
this.navigate('/', {
trigger: true,
replace: true
});
}
};
Your changePage function:
// ...
changePage : function(page, noPanel) {
this.routesHit++;
// ...
}
And for using go back functionality you can use your back function:
appRouter.back()
For using this approach you should use a singleton object of the AppRouter.

Backbone: Setting server response from one model to another

After login user gets redirected to another page. So the response Login model gets from server, it tries to set to another model.
Second model gets set properly from the first model.But when it reaches another page's view, it becomes empty.
Models
var LoginModel = Backbone.Model.extend({
url:'http://localhost:3000/login',
defaults: {
email:"",
password:""
},
parse: function(resp) {
console.log('Model: Got the response back');
return resp;
},
login: function() {
console.log('Model: Login function:'+JSON.stringify(this));
this.save(
{}, {
success: function(resp) {
console.log('success'+JSON.stringify(resp));
dashboardModel.set(resp.result);
window.location = 'templates/dashboard.html'
},
error: function(error) {
console.log('error: '+JSON.stringify(error));
}
});
},
redirect: function() {
console.log('inside redirect method');
}
});
var loginModel = new LoginModel();
var DashboardModel = Backbone.Model.extend({
defaults: {
campaignName:"",
orderedAndGoal:"",
status:"",
endDate:"",
},
parse: function(resp) {
console.log('Model: Got the response back');
return resp;
}
});
var dashboardModel = new DashboardModel();
View
var DashboardView = Backbone.View.extend({
template:_.template('<div>'+
'<h3><%= campaignName %></h3>'+
'<span><%= orderedAndGoal %>, </span>'+
'<span><%= status %>, </span>'+
'<span><%= endDate %>, </span>'+
'</div>'),
initialize: function() {
this.model.on('change', this.render, this);
},
render: function() {
console.log('what happens here')
var attributes = this.model.toJSON();
this.$el.html(this.template(attributes));
},
});
var dashboardView = new DashboardView({model: dashboardModel});
dashboardView.render();
$(".container").append(dashboardView.el);
You are literally navigating to another HTML page with window.location = .... That's not gonna work. When the browser navigates to another page, all your running code and any variables they set are blown away. Backbone is all about creating "single page applications (SPA)" where there is only 1 page loaded by the browser and then the DOM is dynamically changed at runtime. Take a look at Backbone.Router as a starting point for understanding this. You'll call methods on this router to move the user to another "view" rather than touching window.location
Fix that and your code should work :)

Routing with slashes in Backbone

I am trying to use pushState routing in Backbone.js
The problem is that when I try to use routes which contain slashes in between the links, the router function wouldn't get called and the console would show an error:
var Router = Backbone.Router.extend({
routes: {
"work/mobileapps": "showPortfolio"
},
showPortfolio: function(){
alert('Show Portfolio');
}
The showPortfolio function never gets called in this case. I've also tried to do it with parameters, like this:
var Router = Backbone.Router.extend({
routes: {
"work/:section": "showPortfolio"
},
showPortfolio: function(){
alert('Show Portfolio');
}
but the problem still remains the same.
However, if I change the route to something like this:
var Router = Backbone.Router.extend({
routes: {
"work-mobileapps": "showPortfolio"
},
showPortfolio: function(){
alert('Show Portfolio');
}
it starts to work.
So it seems like there's some problem with the slashes. Please help and let me know what mistake I am making.
Thanks!
Here's the full code:
//Set variables according to production/development environment
var production = 0;
var rootpath = (production) ? "/" : "Websitev2/code";
//--------------------------------------------------------------
var Router = Backbone.Router.extend({
routes: {
"work/mobileapps": "showPortfolio",
"about": "showAbout",
"work": "showWork",
"": "showHome"
},
showPortfolio: function(){
alert('Show Portfolio');
//$("#work-content").empty();
},
showAbout: function () {
alert('Show About');
},
showWork: function () {
alert('Show Work');
},
});
$(document).ready(function () {
window.router = new Router();
Backbone.history.start({
pushState: true,
root: rootpath
});
});
In my very limited experience, have you tried:
var Router = Backbone.Router.extend({
routes: {
'work(/:section)': 'showPortfolio'
},
showPortfolio: function(section){
alert('Show Portfolio ' + section);
}
});
As noted in the comments, you need to reference routes with a hash:
http://localhost/Websitev2/code/#work/mobileapps

backbone.js Newbie Collection

I am trying to write some backbone.js stuff to get a better understanding on where and if it fits in better for me on projects. Any way I have a site and I am loading a collection with page content.
Json data comes back with (pid,name,title,content) on my router the default is
defaultRoute: function (actions)
{
this.showInfo('food');
},
showInfo: function (id)
{
var view = new ContentView({ model: this._items.at(id) });
$(".active").removeClass("active");
$("#" + id).addClass("active");
view.render();
}
if I put a 0 in place of id in this "new ContentView({ model: this._items.at(0) })" I will get the first item in the collection and if I do this in the View:
var ContentView = Backbone.View.extend({
el: $('#content'),
render: function ()
{
this.el.empty();
$(this.el).append(this.model.attributes.content);
return this;
}
});
I get the content displayed perfectly but of course may not be the content I wanted
Is it possible to select from a collection based on name == "food"?? I dont want to have to map the content to id numbers defeats the purpose of storing in a db
Sorry if this seems like a foolish question but I have crawled all over looking and Im sure Im missing something simple
here is my full NavigationRouter code in case it helps
var NavigationRouter = Backbone.Router.extend({
_data: null,
_items: null,
_view: null,
routes: {
"p/:id": "showInfo",
"*actions": "defaultRoute"
},
initialize: function (options)
{
var _this = this;
$.ajax({
url: "page_data.php",
dataType: 'json',
data: {},
async: false,
success: function (data)
{
_this._data = data;
_this._items = new ItemCollection(data);
_this._view.render();
Backbone.history.loadUrl();
}
});
return this;
},
defaultRoute: function (actions)
{
this.showInfo('home');
},
showInfo: function (id)
{
var view = new ContentView({ model: this._items.at(id) });
$(".active").removeClass("active");
$("#l_" + id).parent().addClass("active");
view.render();
}
});
Backbone mixes in a bunch of Underscore's functions into its Collections.
So if you want to find the model in the collection where name === 'food', you can do:
var foodModel = this._items.find(function(model) {
return model.get('name') === 'food';
});
// this will set foodModel to the first model whose name is 'food'
As a side note, you don't need to call empty in your render function, which can just be:
render: function() {
$(this.el).html(this.model.get('content'));
return this;
}
jQuery's html function just replaces the content of an element with the html string you pass in.

Categories

Resources