Backbone Require.js Single Page App Not Working Unless Refresh - backbone.js

I am using require.js with a single page backbone.js application. Before leveraging require.js I could click on links and page content would load as expected without refreshing, but now, it won't load unless I refresh the page.
Here is my index page:
<body>
<header></header>
<nav>
World
Business
Opinion
Sports
Fashion & Style
Video
</nav>
<section id="container"></section>
<footer></footer>
<!-- Templates -->
<script type="text/template" id="featuredarticles">
<h2>This is the main content</h2>
<ul id="test"></ul>
</script>
<script type="text/template" id="contentarticles">
<h2>This is a page</h2>
<ul id="test2"></ul>
</script>
<!-- Require.js reference -->
<script src="/js/libs/require.js" data-main="/js/app.js"></script>
Here is my app.js page with the require.js config:
require.config({
paths: {
jquery: "libs/jquery-2.1.0.min",
underscore: "libs/underscore-min",
backbone: "libs/backbone-min",
},
shim: {
underscore: {
exports: "_"
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
}
});
require(['routers/siteRouter'], function(router) {
new router;
});
Here is my router:
define(['underscore', 'backbone', 'views/featuredArticlesView', 'views/contentArticlesView'], function (_, Backbone, featuredArticlesView, contentArticlesView) {
var siteRouter = Backbone.Router.extend({
routes: {
'': 'featuredArticlesView',
'1': 'contentArticlesView',
'2': 'contentArticlesView',
'3': 'contentArticlesView',
'4': 'contentArticlesView',
'5': 'contentArticlesView',
'6': 'contentArticlesView'
}
});
var router = new siteRouter();
router.on('route:featuredArticlesView', function () {
new featuredArticlesView();
});
router.on('route:contentArticlesView', function () {
new contentArticlesView();
});
Backbone.history.start();
return siteRouter;
});

Fixed it. I had two variables in my router and was only returning the "siteRouter". Wrapping these in a function resolved it.
define(['underscore', 'backbone', 'views/featuredArticlesView', 'views/contentArticlesView'], function (_, Backbone, featuredArticlesView, contentArticlesView) {
function routing() {
var siteRouter = Backbone.Router.extend({
routes: {
'': 'featuredArticlesView',
'1': 'contentArticlesView',
'2': 'contentArticlesView',
'3': 'contentArticlesView',
'4': 'contentArticlesView',
'5': 'contentArticlesView',
'6': 'contentArticlesView'
}
});
var router = new siteRouter();
router.on('route:featuredArticlesView', function () {
new featuredArticlesView();
});
router.on('route:contentArticlesView', function () {
new contentArticlesView();
});
Backbone.history.start();
}
return routing;
});

Related

using underscore templates with Backbone and Require.js

I'm trying to create a simple app using underscore templates and backbone (as described in this article). I'm sure that the template file is being loaded correctly, but I'm not so sure whether I'm applying the model to the template properly. (See below example)
I have also checked the output of compiledTemplate variable, but it only contains the <h1> </h1> tags, so it looks like there may be something wrong with the format of my model. But I have not been able to come up witjh any solution so far hence I'm posting this here hoping that someone could possibly help me out with this ..
index.html
<head>
<script src="./dev_env/app/libs/vendor/require.min.js" data-main="dev_env/app/main"></script>
<script>
require(['app_init']);
</script>
</head>
<body >
<div id="test">
</div>
</body>
</html>
./templates/template.html
<h1> <%= obj.title %> </h1>
./app_init.js
require([ '../app' ], function(App){
App.initialize();
});
./app.js
define([ 'backbone', './router', 'underscore','jquery'], function (Backbone, Router, _, $) {
var initialize = function(){
Router.initialize();
}
return {
initialize: initialize
};
});
./models/model_menu.js
define([ 'underscore', 'backbone' ], function(_, Backbone){
var MenuModel = Backbone.Model.extend({
defaults: {
title: "Test1"
}
});
return MenuModel;
});
./collections/collection_menu.js
define([ 'underscore', 'backbone', 'models/model_menu'
], function(_, Backbone, MenuModel){
var MenuCollection = Backbone.Collection.extend({
model: MenuModel
});
return MenuCollection;
});
./router.js
define(['jquery','underscore', 'backbone', 'views/menu/view_menu'], function ($, _, Backbone, vMenu) {
var AppRouter = Backbone.Router.extend({
routes : {
'menu' : 'showMenu',
}
});
var initialize = function () {
var app_router = new AppRouter;
app_router.on('route:showMenu', function () {
var MyMenu = new vMenu();
MyMenu.render();
});
Backbone.history.start();
};
return {
initialize : initialize
};
});
./views/menu_view/view_menu.js
define([ 'jquery','underscore', 'backbone', 'collections/collection_menu', 'text!templates/template.html' ], function ($, _, Backbone, MenuCollection, myTempl) {
var MenuViiew = Backbone.View.extend({
el : $('#test'),
initialize : function () {
this.collection = new MenuCollection();
this.collection.add( {title: "Title2"});
var compiledTemplate = _.template( myTempl, { obj : this.collection.models} );
this.$el.html(compiledTemplate);
}
});
return MenuViiew;
});
I now understand where I was wrong, I misunderstand what a collection was therefore I couldn't make it work. Apologies for that, but I'm still learning this stuff.
here's the solution:
btw. I have changed the collection_menu to menu_collections so it's clear that the file contains a collection of menu models.
views/view_model.js
define([ 'jquery','underscore', 'backbone', 'collections/menu_collections', 'text!templates/template.html' ], function ($, _, Backbone, MenuCollections, myTempl) {
var MenuViiew = Backbone.View.extend({
el : $('#alex'),
initialize : function () {
this.collection = new MenusCollection()
this.collection.add({ title: "Test1" });
this.collection.add({ title: "Test2" });
},
render: function(){
var compiledTemplate = _.template(myTempl, { menus : this.collection.models});
this.$el.html(compiledTemplate);
}
});
return MenuViiew;
});
./templates/template.html
<% _.each(menus, function(menu) { %>
<h1> <%= menu.get('title') %> </h1>
<% }); %>

Backbone / ReactJS view not recognizing JSX

I'm starting on a Backbone AMD application, using React.js for the views. The view is not recognizing the JSX I've written in the render() function. Am I missing a statement in the router or view? The error I'm receiving is 'Unexpected token <'.
Below is the app flow from top to bottom:
Index.html
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<!--<script src="http://fb.me/react-0.12.0.js"></script>
<script src="http://fb.me/JSXTransformer-0.12.0.js"></script> -->
<script data-main="js/main" src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.min.js"></script>
main.js
require.config({
paths: {
jquery: 'http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min',
underscore: 'http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min',
backbone: 'http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min',
react: 'http://fb.me/react-0.12.0',
JSXTransformer: 'http://fb.me/JSXTransformer-0.12.0'
}
});
require([
// Load our app module and pass it to our definition function
'app',
], function(App){
// The "app" dependency is passed in as "App"
App.initialize();
});
app.js
define([
'jquery',
'underscore',
'backbone',
'router' // Request router.js
], function($, _, Backbone, Router){
var initialize = function(){
// Pass in our Router module and call it's initialize function
Router.initialize();
}
return {
initialize: initialize
};
});
router.js
define([
'jquery',
'underscore',
'backbone',
'views/team/list'
], function($, _, Backbone, TeamListView){
var AppRouter = Backbone.Router.extend({
routes: {
// Define some URL routes
'team': 'showTeam',
// Default
'*actions': 'defaultAction'
}
});
var initialize = function(){
var app_router = new AppRouter;
app_router.on('route:showTeam', function(){
// Call render on the module we loaded in via the dependency array
// 'views/teams/list'
var teamListView = new TeamListView();
teamListView.render();
});
app_router.on('route:defaultAction', function(actions){
// We have no matching route, lets just log what the URL was
console.log('No route:', actions);
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
list.js
/**
* #jsx React.DOM
*/
define(
[
'jquery',
'underscore',
'backbone',
'react',
'JSXTransformer'
], function($, _, Backbone, react, JSXTransformer){
var MyWidget = React.createClass({
handleClick: function() {
alert('Hello!');
},
render: function() {
return (
<a href="#" onClick={this.handleClick}>Do something!</a>
);
}
}),
var TeamListView = Backbone.View.extend({
el: 'body',
template: '<div class="widget-container"></div>',
render: function() {
this.$el.html(this.template);
React.renderComponent(new MyWidget(), this.$('.widget-container').get(0));
return this;
}
});
// Our module now returns our view
return TeamListView;
});
list.js (updated - working version)
define(
[
'jquery',
'underscore',
'backbone',
'react'
], function($, _, Backbone, React){
var MyWidget = React.createClass({displayName: 'MyWidget',
handleClick: function() {
alert('Hello!');
},
render: function() {
return (<div>
<ul>
<li></li>
<li></li>
</ul>
<div>Test</div>
<a href="#" onClick={this.handleClick}>Do something!</a>
</div>
)
}
});
var TeamListView = Backbone.View.extend({
el: $('#mainContent'),
events: {
},
initialize: function() {
console.log('test');
},
render: function (){
React.render(
React.createElement(MyWidget, null),
document.getElementById('mainContent')
);
}
});
return TeamListView;
});
JSX must be compiled to JavaScript before browsers can understand it.
You can use the jsx tool to do this.
JSX transformer and Require.js are incompatible.
If you're using RequireJS, you can use a JSX plugin like this one. For what it's worth, when I integrated the JSX transformer into our RequireJS setup, it required quite a bit of tweaking and experimentation.

Backbone Router navigate keeps long history

I am building an application with Backbone and to go from step 1 to step 2 I make use the of the router.navigate function. Now it will go to the next page and go back etc.
However every step I take will be kept in the history and every page in the history will be visited after each event. This will also show up in the console log.
Now I am using require.js as well
Here is my router:
var OF = OF || {};
OF.SubscribeRouter = Backbone.Router.extend({
routes: {
"step/:stepNumber": "goToStep",
"*other": "defaultRoute"
},
goToStep: function(stepNumber) {
switch(stepNumber) {
case "1":
require(['./views/step1],function(Step1) {
OF.step1 = new OF.Step1;
OF.step1.render();
});
break;
case "2":
require(['./views/step2'],function(Step2) {
OF.step2 = new OF.Step2;
OF.step2.render();
});
break;
case "3":
require(['./views/step3'],function(Step3) {
OF.step3 = new OF.Step3;
OF.step3.render();
});
break;
case "4":
require(['./views/step4'],function(Step4) {
OF.step4 = new OF.Step4;
OF.step4.render();
});
break;
case "5":
require(['./views/step5'],function(Step5) {
OF.step5 = new OF.Step5;
OF.step5.render();
});
break;
case "6":
require(['./views/step6'],function(Step6) {
OF.step6 = new OF.Step6;
OF.step6.render();
});
break;
}
},
defaultRoute: function(other) {
//start loading the welcome page
this.goToStep(1);
}
});
Here is my main file which will start the router:
var OF = OF || {};
require.config({
paths: {
underscore: 'vendor/underscore-min',
jquery: 'vendor/jquery-2.0.3',
json2: 'vendor/json2',
backbone: 'vendor/backbone-min',
handlebars: 'vendor/handlebars',
router: 'routers/router'
},
shim: {
'backbone': {
deps: ['underscore', 'jquery', 'json2'],
exports: 'backbone'
},
'handlebars': {
deps: ['jquery', 'json2'],
exports: 'handlebars'
},
'templateReader': {
deps: ['jquery', 'json2', 'handlebars'],
exports: 'templateReader'
},
'router': {
deps: ['jquery', 'json2', 'backbone'],
exports: ''
}
}
});
require(['router'], function(SubscribeRouter) {
// create the application
'use strict';
OF = {
router: new OF.SubscribeRouter(),
};
//start router
Backbone.history.start();
});
And here is the view which will trigger the event for 'page change':
var OF = OF || {};
OF.Step1 = Backbone.View.extend({
el: '#content',
initialize: function() {
console.log("you're in the address view");
},
render: function() {
//save this in that ;)
var that = this;
OF.template.get('step1-step1', function(data) {
//set the source en precompile the template
var htmlSource = $(data).html();
var template = Handlebars.compile(htmlSource);
//fill template with object or ''
var compiled = template(OF);
//now place the completely compiled html into the page
that.$el.html(compiled);
});
},
events: {
"click #next": "nextStep"
},
nextStep: function() {
OF.router.navigate('step/2', {trigger: true});
}
});
So this is what I see in my console log after clicking next:
GET template-step2.html
now going back:
GET template-step1.html
So all seems well right now.
However now that I am back on step1 and click on next I expect to go to step2.
Unfortunately I will go to step3 and this is what I see in my console log:
GET template-step2.html
GET template-step2.html
GET template-step3.html
Is there a way to clear this history of some kind or to prevent this from caching or whatever it is it does?
where can I find a list of options for the router.navigate method?
I found the reason for this 'error' and it is because I use the same ID for the buttons in every template. When I changed this, the problem was solved.
Though I am still figuring out if the cache cannot be cleared so I can still use the same ID's (it is a next page now isn't it?).

backbone.js Uncaught TypeError: Cannot read property 'View' of null

When I run my backbone app in NetBeans 7.3.1, the main page displays for a few seconds, maybe 5 or 6, then in NetBeans output I see the following...
Uncaught TypeError: Cannot read property 'View' of null (18:43:36:307 | error, javascript)
at (js/views/HomeView.js:6:28)
at d.execCb (js/libs/require/require.js:27:197)
at o (js/libs/require/require.js:10:471)
at (js/libs/require/require.js:12:184)
at o (js/libs/require/require.js:12:75)
at (js/libs/require/require.js:14:1)
at o (js/libs/require/require.js:12:75)
at l (js/libs/require/require.js:12:336)
at g.finishLoad (js/text.js:10:192)
at g.load (js/text.js:10:354)
at window.undefined.window.navigator.window.document.c.onreadystatechange (js/text.js:7:30)
Uncaught TypeError: Cannot read property 'Model' of null (18:43:36:317 | error, javascript)
at (js/models/Member.js:6:26)
at d.execCb (js/libs/require/require.js:27:197)
at o (js/libs/require/require.js:10:471)
at x (js/libs/require/require.js:15:186)
at m (js/libs/require/require.js:15:207)
at g.completeLoad (js/libs/require/require.js:21:388)
at d.onScriptLoad (js/libs/require/require.js:27:490)
Uncaught Error: Load timeout for modules: text!templates/homeTemplate.html
http://requirejs.org/docs/errors.html#timeout (18:43:38:511 | error, javascript)
at N (js/libs/require/require.js:7:217)
at A (js/libs/require/require.js:16:230)
at (js/libs/require/require.js:16:394)
It looks like RequireJS is failing to load Backbone. Here is main.js...
// Filename: main.js
require.config({
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
}
},
paths: {
jquery: 'libs/jquery/jquery-min',
underscore: 'libs/underscore/underscore-min',
backbone: 'libs/backbone/backbone-min',
templates: '../templates'
}
});
require([
'app',
], function(App) {
App.initialize();
});
I'm totally spinning my wheels on this. Why is Require not loading Backbone?
#Sushanth--: Edited original post to include HomeView.js
Here is the HomeView.js...
define([
'jquery',
'underscore',
'backbone',
'text!templates/homeTemplate.html'
], function($, _, Backbone, homeTemplate) {
var HomeView = Backbone.View.extend({
el: $("#page"),
initialize: function() {
},
render: function() {
var compiledTemplate = _.template( homeTemplate, {} );
this.$el.html( compiledTemplate );
}
});
return HomeView;
});
#Sushanth--: I'm rendering from the router.js...
// Filename: /js/router.js
define([
'jquery',
'underscore',
'backbone',
'views/HomeView',
'views/MembersView'
], function($, _, Backbone, HomeView, MembersView) {
var AppRouter = Backbone.Router.extend({
routes: {
// Define some URL routes
'members': 'showMembers',
// Default
'*actions': 'defaultAction'
}
});
var initialize = function(){
//alert('router init');
var app_router = new AppRouter;
app_router.on('route:showMembers', function () {
// Like above, call render but know that this view has nested sub views which
// handle loading and displaying data from the GitHub API
var membersView = new MembersView();
});
app_router.on('route:defaultAction', function (actions) {
// We have no matching route, lets display the home page
var homeView = new HomeView();
homeView.render();
});
// Unlike the above, we don't call render on this view as it will handle
// the render call internally after it loads data. Further more we load it
// outside of an on-route function to have it loaded no matter which page is
// loaded initially.
//var footerView = new FooterView();
//alert('hello from router.js');
//Backbone.history.start({pushState: true, root: "/modular-backbone/"});
//Backbone.history.start({pushState: true});
Backbone.history.start();
};
return {
initialize: initialize
};
});
Added a test alert in main.js, app.initialize...
require(['app'], function(App) {
// THIS ALERT NEVER DISPLAYS!?!?!
alert('inside main.js before app.initialize');
App.initialize();
});
I replaced my Backbone and Underscore js files with the AMD versions and it started working.

Backbone is not defined

I'm using backbone.js with require.js. I tried one tutorial and this is my index.html :
<script src="app/script/libs/require/require.js" data-main="app/script/main" type="text/javascript"></script>
<script src="app/script/router.js" type="text/javascript"></script>
<script type='text/javascript'>
$(document).ready(function()
{
var appRouter = new AppRouter(); // Router initialization
Backbone.history.start(); // Backbone start
});
</script>
And this is main.js :
require.config({
urlArgs: "bust=" + (new Date()).getTime(),
paths: {
jquery: 'libs/jquery/jquery',
underscore: 'libs/underscore/underscore',
backbone: 'libs/backbone/backbone'
}
});
require(["jquery", "underscore", "backbone"],
function ($, _, Backbone) {
console.log("Test output");
console.log("$: " + typeof $);
console.log("_: " + typeof _);
console.log("Backbone: " + typeof Backbone);
}
);
And this is my console:
ReferenceError: Backbone is not defined
[Break On This Error]
$(document).ready(function()
ReferenceError: $ is not defined
[Break On This Error]
$(document).ready(function()
Test output
$: function
_: function
Backbone: object
Require.js is working, but the backbone and jquery is undefined, I don't know what's wrong with them.
This is the structure of my file :
Any idea please. Thanks
You should also declare your libs in shim config
require.config({
urlArgs: "bust=" + (new Date()).getTime(),
paths: {
jquery: 'libs/jquery/jquery',
underscore: 'libs/underscore/underscore',
backbone: 'libs/backbone/backbone'
},
shim: {
'backbone': {
deps: ["underscore", "jquery"],
exports: "Backbone"
},
'underscore': {
exports: "_"
}
}
});
require(["jquery", "underscore", "backbone"],
function ($, _, Backbone) {
console.log("Test output");
console.log("$: " + typeof $);
console.log("_: " + typeof _);
console.log("Backbone: " + typeof Backbone);
}
);
With your setup you can use Backbone only if it was injected as a dependency in a requireJS module, it is not available in the global name space. Also requiring something that you need in most of every module like jquery, Backbone or underscore seems not the best idea. Just load them as script tag before your requireJS main file and everything is fine.
If you want to keep the shim solution you have to start your app inside a the main.js file
require.config({
urlArgs: "bust=" + (new Date()).getTime(),
paths: {
jquery: 'libs/jquery/jquery',
underscore: 'libs/underscore/underscore',
backbone: 'libs/backbone/backbone'
}
});
require(["jquery", "underscore", "backbone"],
function ($, _, Backbone) {
console.log("Test output");
console.log("$: " + typeof $);
console.log("_: " + typeof _);
console.log("Backbone: " + typeof Backbone);
$(document).ready(function() {
var appRouter = new AppRouter(); // Router initialization
Backbone.history.start(); // Backbone start
});
}
);

Resources