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
});
}
);
Related
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>
<% }); %>
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.
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.
I am trying to get to grips with Backbone and Require JS using marionette for some of its excellent features. However I am finding a few issues with the app being available to views:
main.js
require(['application'], function(app){
app.start();
});
application.js
define([
'marionette',
'router'
], function(marionette, Router){
"use strict";
var app = new marionette.Application();
app.addRegions({
header : 'header',
main : '#main'
});
app.addInitializer(function(){
this.router = new Router();
});
return app;
});
dashboard.js
define([
'application',
'underscore',
'backbone',
], function(app, _, Backbone) {
var DashboardView = Backbone.View.extend({
initialize: function() {
console.log(app);
$('a').click(function(e){
e.preventDefault();
app.router.navigate("claims", {
trigger: true
});
});
},
});
return DashboardView;
});
I am receiving undefined in the console log? Should the application be using requirejs modules instead?
EDIT: Update with require
require.config({
paths: {
'jquery' : '../vendors/jquery-1.8.2',
'underscore' : '../vendors/underscore',
'text' : '../vendors/text',
'json2' : '../vendors/json2',
'backbone' : '../vendors/backbone',
'marionette' : '../vendors/plugins/backbone.marionette',
'paginator' : '../vendors/plugins/backbone.paginator',
'relational' : '../vendors/plugins/backbone.relational',
'moment' : '../vendors/moment',
'bootstrap' : '../vendors/bootstrap',
'datepicker' : '../vendors/plugins/bootstrap.datepicker',
'templates' : 'templates/'
},
shim: {
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
marionette : {
exports : 'Backbone.Marionette',
deps : ['backbone']
},
paginator: {
deps: [
'backbone',
'underscore',
'jquery'
],
exports: 'Backbone.Paginator'
},
relational: ['backbone'],
underscore: {
'exports': '_'
},
bootstrap: {
deps: ['jquery'],
exports: "bootstrap"
},
datepicker: {
deps: ['jquery','bootstrap'],
exports: "datepicker"
},
moment: {
exports: 'moment'
}
}
});
require(['application'], function(app){
app.start();
});
router
define([
'views/claims/PaginatedList',
'views/dashboard/Dashboard'
], function(PaginatedClaimListView, DashboardView){
var Router = Backbone.Router.extend({
routes: {
"": "index",
"claims": "claims"
},
initialize: function(){
Backbone.history.start({
pushState: true,
root: '/app_dev.php/hera'
});
},
index: function(){
var dashboard = new DashboardView();
},
claims: function(){
var claimListView = new PaginatedClaimListView();
}
});
return Router;
});
I think I've figured it out, even if I'm not 100% sure why.
The problem lies in your Router definition. Putting there your views with a reference to Application makes the router start before app.start() is called in main.js. In fact if you put a console.log(app) in your main.js you'll notice that it gets called after the one in dashboard.js.
So here's how I've resolved it:
define(['backbone'], function(Backbone){
var Router = Backbone.Router.extend({
routes: {
"": "index",
"claims": "claims"
},
initialize: function(){
Backbone.history.start({
pushState: true,
root: '/app_dev.php/hera'
});
},
index: function(){
require(['views/dashboard/Dashboard'],function(DashboardView){
var dashboard = new DashboardView();
});
},
claims: function(){
require(['views/claims/PaginatedList'],function(PaginatedClaimListView){
var claimListView = new PaginatedClaimListView();
});
}
});
return Router;
});
I'm not sure if there's a better solution that keeps your views defined in your router, anyway this works and will make your router lighter, especially if your views grown in number...
I've found that usually whenever I have Require.js modules set to undefined when they shouldn't be, it's because of a circular dependency. For instance, let's say "vent" depended on "dashboard"; you'd have: vent needs dashboard needs application needs vent ...
When this happens Require's response is essentially just to just pick one of the files and make it work, but any of the other files involved in the circular dependency come in as undefined.
You can test this theory by removing imports to see if that fixes your undefined. Alternatively the Require folks have a tool you can download called xrayquire which assists in finding circular dependencies.
Do you have to access the router via app.router? Can you not just have dashboard require router on its own, and access it directly? As long as application has already executed (which it should have, at that point), then you don't need to access it via app. I think your problem is definitely a complicated circular dependency.
I am using require in my app and on certain android devices and every now and again on the web I get an error like jQuery is not defined or Backbone not defined]
my index page is simple and has a link to my require
<script data-main="js/main" src="js/vendor/require/require.js"></script>
within here I setup all paths and the call the router as well as switching off the routing for JQM
require.config({
paths: {
jquery: 'vendor/jqm/jquery_1.7_min',
jqm: 'vendor/jqm/jquery.mobile-1.1.0',
underscore: 'vendor/underscore/underscore_amd',
backbone: 'vendor/backbone/backbone_amd',
text: 'vendor/require/text',
templates: '../templates',
views: '../views',
models: '../models'
}
});
define(['router','jqm-config'], function(app) {
});
then on my router page I define what is needed there..
define(['jquery', 'underscore', 'backbone','views/home/home',
'models/products/productCollection',
'views/products/productTypes',
'jqm'],
function($, _, Backbone,HomeView,ProductsType,ProductListView ) {
var AppRouter = Backbone.Router.extend({
//code here
});
$(document).ready(function () {
console.log('App Loaded');
app = new AppRouter();
Backbone.history.start();
});
return AppRouter;
});
how do i stop these errors occuring?
In your require.config you could add a shim section to define those dependencies:
require.config({
// The shim config allows us to configure dependencies for
// scripts that do not call define() to register a module
shim : {
'underscore' : {
exports : '_'
},
'backbone' : {
deps : [ 'underscore', 'jquery' ],
exports : 'Backbone'
},
'dataTables' : {
deps : [ 'jquery' ],
exports : 'dataTables'
}
},
paths : {
...