Require js not loading module - backbone.js

I have been staring at this for a while and can't seem to figure out why some AMDs aren't available after loading them as dependencies. I have a custom module called "models"; a bundle configured in my MVC project with the virtual path "/scripts/models.js". When I define it in require.config and as a dependency, it loads the file. I can see it was requested and found. No errors from require. However, when I try to reference it as the loaded dependency argument passed into my router, it's undefined (models.userModel).
Is there something I am doing wrong here? I don't see any circular dependencies and I have tried defining the models module by giving it a name. It is undefined regardless if I define it globally or request the module by path in my router.js file.
app.js. Main config. (below)
require.config({
baseUrl: "/scripts/app",
paths: {
jquery: "../jquery",
underscore: "libs/underscore",
backbone: "libs/backbone",
kendo: "libs/kendo",
models: "../models"
},
// We shim Backbone since it doesn't declare an AMD module
shim: {
underscore: {
exports: "_"
},
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
}
},
});
require([
"jquery",
"backbone",
"kendo",
"models",
"router"
], function ($, backbone, kendo, models, router) {
alert("config-start");
});
user.js. Indcluded in the models.js bundle. (below)
define({
userModel : kendo.observable({
datasource: kendo.data.DataSource({
transport: {
read: {
url: "/api/usersettings",
dataType: "json",
type: "GET"
},
update: {
url: "/api/usersettings",
dataType: "json",
type: "PUT"
}
},
schema: {
model: {
id: "UserId"
}
},
parameterMap: function (options, operation) {
if (operation !== "read" && options.models) {
return {
models: kendo.stringify(options.models)
};
}
return options;
}
}),
save: function () {
this.data.sync();
},
})
});
router.js file (below)
define(["jquery",
"backbone",
"models"
], function ($, backbone, models) {
/**
* The Router class contains all the routes within the application -
* i.e. URLs and the actions that will be taken as a result.
*
* #type {Router}
*/
var Router = Backbone.Router.extend({
contentArea: $("#MainContent"),
routes: {
"user/usersettings/contact": "contact",
"user/usersettings/security": "security",
"user/usersettings/dashboard": "dashboard",
"user/usersettings/permissions": "permissions",
"user/usersettings/colors": "colors"
},
contact: function () {
var contactTemplate = kendo.template($("#usersettings-usercontact").html());
this.contentArea.empty();
this.contentArea.html(contactTemplate);
kendo.bind(this.contentArea, models.userModel); // models is undefined
},
security: function () {
},
dashboard: function () {
},
permissions: function () {
},
colors: function () {
}
});
// Create a router instance
var router = new Router();
//Begin routing
Backbone.history.start();
return router;
});
Maybe I am missing something obvious, but I have not been able to load "models" as an external dependency. It is undefined when referencing from router.js. On the "contact" function.

Define needs a function that will return a value, this value then will be injected when it was required in another module.
Source code comment:
/**
* The function that handles definitions of modules. Differs from
* require() in that a string for the module should be the first argument,
* and the function to execute after dependencies are loaded should
* return a value to define the module corresponding to the first argument's
* name.
*/
define(function(){
return {
userModel: ...
}
})

Related

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 JS, Marionette and Require JS

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.

require dependencies (loading in a order to prevent errors)

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 : {
...

backbone.layoutmanager and handlebars template engine

I'm using the backbone.layoutmanager project:
https://github.com/tbranyen/backbone.layoutmanager#readme
can some one please post a sample with handlebars template engine?
containing the modified app.js file and an instance view?
i have followed the instructions and i'm a bit confused what should i do in the instance level and the global.
i keep getting the "has no method 'match' err message on my template.
Thanks
Your modified app.js will work with something like this:
define([
"jquery",
"underscore",
"backbone",
"handlebars",
"plugins/backbone.layoutmanager"
],
function($, _, Backbone, Handlebars) {
"use strict";
var JST = window.JST = window.JST || {};
Backbone.LayoutManager.configure({
paths: {
layout: "path/to/layouts/",
template: "path/to/templates/"
},
fetch: function(path) {
path = path + ".html";
if(!JST[path]) {
$.ajax({ url: "/" + path, async: false }).then(function(contents) {
JST[path] = Handlebars.compile(contents);
});
}
return JST[path];
}
// It is not necessary to override render() here.
});
var app = {
// Define global resources here.
};
return _.extend(app, Backbone.Events);
});
An example of a view:
var SampleView = Backbone.View.extend({
template: "path/to/sample/template",
// Override this for fine grained control of the context used by the template.
serialize: function() {
return {
property: 1,
anotherProperty: 2
};
}
// No need to override render() for simple templates.
});
And the template associated with the view:
<div>
<h2>{{property}}</h2>
<h2>{{anotherProperty}}</h2>
</div>

Resources