How to have params read in Backbone js when including pushState: true? - javascript

I have the following code but using pushState: true does not have the function called anymore, pre-pushstate with a hash it works, but when doing ?q=ok does not get read, when I had pushState not set #?q=ok works.
Here is the code:
(function(search,Backbone,$) {
$(function() {
app = new search.Views.AppView({
el: $("[search]")
});
var Router = Backbone.Router.extend({
routes: {
'(?:params*)': function(params) {
if (params) {
params = QueryString.decode(params);
}
else {
params = {};
}
if (params.q) {
app.setQuery(params.q);
}
}
}
});
var router = new Router();
Backbone.history.start({pushState: true});
});
})(search,Backbone,jQuery);

Related

Backbone - Hashtag appearing at very end of URL

I am doing my first Backbone project. I am using Backbone 1.3.3 and Underscore 1.8.3. I am having a problem with my router. When I invoke the router, it places the hashtag at the very end of the URL:
http://server:9999/backbone_demo/addMember#
instead of:
http://server:9999/backbone_demo/#addMember
which is what I want.
var router = null;
var context = "backbone_demo";
DemoRouter = Backbone.Router.extend({
initialize: function () {
initializeEventsForNavigation();
},
routes: {"" : "start", "/bands": "bands", "/addMember": "addMember", "*defaultRoute" : "defaultRoute"},
defaultRoute: function() {
this.start();
},
start: function () {
this.bands();
},
bands: function () {
BackboneDemo.View.unrenderAllViews();
BackboneDemo.View.renderBandList();
},
addMember: function() {
BackboneDemo.View.unrenderAllViews();
BackboneDemo.View.renderAddMember();
}
});
var init = function() {
initializeEventsForBandListRender();
initializeEventsForAddMemberRender();
router = new DemoRouter();
Backbone.history.start({pushState: true, root: context});
};
var navigate = function(e) {
var route = e.detail.route;
router.navigate("/" + route, true);
};
If I pass "addMember" to my navigate function (in e.detail.route), I will be passing "/addMember" to router.navigate. The router works fine except for this detail.
I think you should set pushState to false if you want to use hash routing.
Backbone.history.start({pushState: false, root: context});

Backbone.js + Require.js and ViewsFactory

Let's assume that we have testing code like this:
var App = (function () {
var api = {
Router: null,
init: function () {
this.content = $("#content");
Backbone.history.start();
return this;
}
};
var ViewsFactory = {
view1: function () {
var model1 = new model1();
return new api.Views.View1({
model: model1
});
},
view2: function () {
var model2 = new model2();
return new api.Views.View2({
model: model2
});
},
view3: function () {
var model3 = new model3();
return new api.Views.View3({
model: model3
});
},
};
var Router = Backbone.Router.extend({
routes: {
"": "view1",
"2": "view2",
"3": "view3",
},
view1: function () {
var view1 = ViewsFactory.view1();
$(".content").html(view1.render().el);
},
view2: function () {
var view2 = ViewsFactory.view2();
$(".content").html(view2.render().el);
},
view3: function () {
var view3 = ViewsFactory.view3();
$(".content").html(view3.render().el);
},
});
api.Router = new Router();
return api;
})();
And I want to use Require.js. Please don't focus on names, but on the idea.
If I understand it correctly, I have to include in require method every view (View1, View2, View3) and every model (Model1, Model2, Model3). But what is the purpose of using Require.js in such case instead of traditional <script> tags?
Using ViewsFactory is a good practice in backbone projects?
WHy not a view factory. In your case I'm not sure it's really useful though.
requirejs will help to build reusable modules. http://requirejs.org/docs/why.html
The best option in router is using variables like this:
var $ = require('jquery'),
Backbone = require('backbone');

Backbone.js and router.navigate

I'm trying to improve the navigation of my little backbone application. Right now I just have some simple navigation using html links that use to #path/to/page in the href element.
What I'm running into is when I click on one of these and then click the back button, the page doesn't refresh properly, and the HTML content doesn't change. So I'm trying to incorporate the navigate functionality into my code.
The issue I'm running into is that I can't find an example that matches the code layout I'm currently using, and I don't understand how backbone works enough to adapt the things I find into something useful.
Here's what I've got:
app.js - called from the index.html file
require.config({
baseUrl: 'js/lib',
paths: {
app: '../app',
tpl: '../tpl',
bootstrap: 'bootstrap/js/',
},
shim: {
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'underscore': {
exports: '_'
}
}
});
require([
'jquery',
'backbone',
'app/router',
], function ($, Backbone, Router) {
var router = new Router();
Backbone.history.start();
});
app/router.js - instantiated in app.js
define(function (require) {
"use strict";
var $ = require('jquery'),
Backbone = require('backbone'),
WindowView = require('app/views/Window'),
breadcrumbs = {"Home": ""},
$body = "",
$content = "",
windowView = "";
return Backbone.Router.extend({
initialize: function () {
require([], function () {
$body = $('body');
windowView = new WindowView({el: $body}).render();
$content = $("#content", windowView.el);
});
},
routes: {
'' : 'home',
'profile/login(/)' : 'candidateProfileLogin',
'profile/manage(/)' : 'candidateProfileLogin',
'profile/manage/:id(/)' : 'candidateProfileHome',
'profile/manage/:id/questionnaire/:page(/)' : 'candidateProfileQuestionnaire',
'profile/manage/:id/:section(/)' : 'candidateProfileSection',
},
home: function (){
},
candidateProfileLogin: function () {
require(['app/views/CandidateLogin'], function (CandidateLoginView) {
console.log(Backbone.history.fragment);
var view = new CandidateLoginView({el: $content});
view.render();
});
},
candidateProfileHome: function (id) {
require(["app/views/Candidate", "app/models/candidate"], function (CandidateView, models) {
var candidate = new models.Candidate({id: id});
candidate.fetch({
success: function (data) {
var view = new CandidateView({model: data, el: $content});
view.render();
},
error: function (data) {
var view = new CandidateView({model: data, el: $content});
view.render();
}
});
});
},
candidateProfileSection: function (id, section) {
require(["app/views/Candidate", "app/models/candidate"], function (CandidateView, models) {
var candidate = new models.Candidate({id: id});
candidate.fetch({
success: function (data) {
var view = new CandidateView({model: data, el: $content});
view.render(section);
},
error: function (data) {
//Output the data to the console. Let the template take care of the error pages
console.log(data);
var view = new CandidateView({model: data, el: $content});
view.render();
}
});
});
},
candidateProfileQuestionnaire: function (id, page) {
require(["app/views/Candidate", "app/models/candidate"], function (CandidateView, models) {
var candidate = new models.Candidate({id: id});
candidate.fetch({
success: function (data) {
var view = new CandidateView({model: data, el: $content});
view.render(page);
},
error: function (data) {
//Output the data to the console. Let the template take care of the error pages
console.log(data);
var view = new CandidateView({model: data, el: $content});
view.render();
}
});
});
},
});
});
app/views/Candidate.js - My view I'm trying to process the clicks
define(function (require) {
"use strict";
var $ = require('jquery'),
_ = require('underscore'),
Backbone = require('backbone'),
tpl = require('text!tpl/Candidate.html'),
template = _.template(tpl),
CandidateErrorView = require('app/views/CandidateError'),
errtpl = require('text!tpl/CandidateError.html'),
errTemplate = _.template(errtpl);
return Backbone.View.extend({
events: {
'submit #voters-guide-personalInfo': 'savePersonalInfo',
'submit #voters-guide-essay' : 'saveEssay',
'submit #voters-guide-survey' : 'saveSurvey',
'submit #voters-guide-endorsements': 'saveEndorsements',
'submit #voters-guide-photo' : 'savePhoto',
'click #table-of-contents a' : 'navTOC',
},
savePersonalInfo: function (event) {
console.log(event);
},
saveEssay: function (event) {
console.log(event);
},
saveSurvey: function (event) {
console.log(event);
},
saveEndorsements: function (event) {
console.log(event);
},
savePhoto: function(event) {
console.log(event);
},
navTOC: function (event) {
console.log(event.target);
var id = $(event.target).data('candidate-id');
var path = $(event.target).data('path');
//router.navigate("profile/manage/" + id + "/" + path, {trigger: true});
},
render: function (page) {
//Check to see if we have any errors
if (!this.model.get('error')) {
var dataToSend = {candidate: this.model.attributes};
switch(page) {
case 'personalInfo':
template = _.template(require('text!tpl/Candidate-personalInfo.html'));
break;
case 'essay':
template = _.template(require('text!tpl/Candidate-essay.html'));
break;
case 'survey':
template = _.template(require('text!tpl/Candidate-survey.html'));
break;
case 'endorsements':
template = _.template(require('text!tpl/Candidate-endorsements.html'));
break;
case 'photo':
template = _.template(require('text!tpl/Candidate-photo.html'));
break;
default:
break;
}
this.$el.html(template(dataToSend));
return this;
} else {
this.$el.html(errTemplate({candidate: this.model.attributes}));
return this;
}
}
});
});
Now, in an attempt to stop the 'the page content doesn't reload when I hit the back button' issue, I've been looking into the navigate function that backbone has available (this: router.navigate(fragment, [options]);). There are lots of examples of how this is used, but none of them seem to have anything similar to the file setup that I'm using, so I'm not exactly sure how best to access this functionality from my view. If I include the router file in the view and instantiate a new version of it, the page breaks b/c it tries to run the initialize function again.
I'm just really at a loss on how this is supposed to work.
Can someone point me in the right direction?
Thanks!
--Lisa
P.S. If someone has any better ideas, I am all ears!
You should have access to the Backbone object, which within it, has access to navigate around using the history.navigate function. If you call that passing in trigger: true you'll invoke the route. For instance:
Backbone.history.navigate("profile/manage", { trigger: true });

Update url using router

I have a router on my application now it respond as expected when I type in the url. For exapmple if I type in www.example.com#search/groupa, I get the appropriate result back. I have attempted in the search feature to call navigate to set the url so that a user could cut and paste that and send it to another user. The issue is it doesnt work I get the following error when attempting to do so: "Uncaught TypeError: Object function (){return i.apply(this,arguments)} has no method 'navigate'"
IEG = new Backbone.Marionette.Application();
IEG.addRegions({
searchBox: '#searchBox',
resultBox: '#resultBox',
modalBox: '#modalBox',
recipientBox: '#recipientBox',
confirmBox: '#confirmToggleActive'
});
IEG.vent = _.extend({}, Backbone.Events);
IEG.vent.on("default", function () {
var SBV = new SearchBoxView();
IEG.searchBox.show(SBV);
IEG.searchColl = new GroupEntries();
IEG.searchColl.fetch({
data: {
cmd: 0, //search groups
searchStr: null //if null show all groups
},
success: function (data) {
searchResults = new SearchResultsView({ collection: IEG.searchColl });
IEG.resultBox.show(searchResults);
}
});
});
IEG.vent.on("searchGroups", function (searchStr) {
IEG.Router.navigate("search" + searchStr); // CALLING NAVIGATE HERE
IEG.searchColl.fetch({
data: {
cmd: 0, //search groups
searchStr: searchStr
},
success: function (data) {
searchResults = new SearchResultsView({ collection: IEG.searchColl });
IEG.resultBox.show(searchResults);
}
});
});
IEG.Router = Backbone.Router.extend({
routes: {
'': 'index',
'search/:str': 'search',
'edit/:grp': 'edit'
},
index: function () {
IEG.vent.trigger("default");
},
search: function (str)
{
IEG.vent.trigger("searchGroups",str);
}
});
$(document).ready(function () {
IEG.start();
new IEG.Router;
Backbone.history.start();
});
You need to call navigate on the instance of the Router class and not on its definition (as you're currently doing). Try updating the code in your document ready handler like this:
$(document).ready(function () {
IEG.start();
IEG.router = new IEG.Router(); // Store an instance of the router on the Application
Backbone.history.start();
});
And your searchGroups handler like this:
IEG.vent.on("searchGroups", function (searchStr) {
IEG.router.navigate("search" + searchStr); // call navigate on the instance
// Fetch code .....
});

Backbone Router with parameter not working

I'm trying to use backbone routes with parameters and for some reason, I just can't seem to make the code below to work:
var App = new Backbone.Marionette.Application();
App.Router = Backbone.Router.extend({
routes: {
"export": "export",
"show": "show/:id", // This just won't work
"providers": "providers"
},
export: function() {
var exportView = new App.ExportView();
exportView.render();
$("#main").html(exportView.el);
},
show: function(id) {
console.log('from here'); // This is not even firing
var show = this.collection.get(id);
showView.render();
$("#main").html(showView.el);
},
providers: function() {
var contentProvidersView = new App.ProvidersView();
providersView.render();
$("#main").html(providersView.el);
}
});
App.addInitializer(function() {
var router = new App.Router();
});
Nothing happens when I try to access this: #show/2 (Where 2 is the show id)
Many thanks.
It's the other way around :
routes: {
"show/:id": "show",
}

Categories

Resources