RequireJs: Wrong module order - javascript

I got following router.js:
define(['jquery', 'underscore', 'backbone', 'views/settings/index'], function($, _, Backbone, SettingsView) {
var Router = Backbone.Router.extend({
container: $('div.main'),
routes: {
"settings": "settings"
, "settings/:query": "settings"
},
settings: function(query) {
this.container.html(SettingsView.render().el);
}
});
if (Router._instance) return Router._instance;
Router._instance = new Router();
return Router._instance;
});
The router gets called in the main.js filed which is marked as first dependency in the requirejs config:
define(['jquery', 'underscore', 'backbone', 'router'], function($, _, Backbone, router) {
// ajax settings (sent cors cookies)
$.ajaxSetup({ xhrFields: { withCredentials: true } });
// register master router
window.router = router;
// start backbone history
Backbone.history.start({ root: "/" });
});
In some view I now want to do:
define(['jquery', 'underscore', 'backbone', 'router'], function($, _, Backbone, router) {
var View = Backbone.View.extend({
initialize: function() {
router.on('route:settings', this.change, this);
},
change: function(query) {
// load some new content for example
}
});
return View;
});
Than I am getting this error message:
Uncaught TypeError: Cannot call method 'on' of undefined
UPDATE:
I added a console.log to each module. So I know in which order the modules are executed. I mentioned that requirejs has the wrong order:
view.js -> main.js -> router.js
instead of:
router.js -> main.js -> view.js
Let see how I can solve this
UPDATE2:
I now wrapped the router event binding part into a setTimeout loop:
setTimeout(function() {
window.router.on('route:settings', this.select, this);
}.bind(this), 20);
And see there it works!
This truly just is a fix but nevertheless a fix :)

Why are you trying to create a singleton instance on your router?
Requirejs resolves every module only once as far as I understand and
as far as I would expect from any decent module loader.
#router.js
define(['jquery', 'underscore', 'backbone', 'views/settings/index'],
function($, _, Backbone, SettingsView) {
//your code omitted ...
//no need to do this
//if (Router._instance) return Router._instance;
//Router._instance = new Router();
//return Router._instance;
//this should work as well and give you a "singleton" instance
return new Router();
});

please check if the names/path you have given to requirejs.config() is correct. I have hit the wall hard a few times because I had a slight typo. requirejs doesnt return any errors on such cases but sadly only undefined.
If you are dead sure that there is no typo I'd try to include main.js as an explicit dependency on the definition of your view.

I think you need to return a reference to the Router object at the end of the first define.
define(['jquery', 'underscore', 'backbone', 'views/settings/index'], function($, _, Backbone, SettingsView) {
var Router = Backbone.Router.extend({
container: $('div.main'),
routes: {
"settings": "settings"
, "settings/:query": "settings"
},
settings: function(query) {
this.container.html(SettingsView.render().el);
}
});
var Singletonizer = function(Singleton) {
if (Singleton._instance) return Singleton._instance;
Singleton._instance = new Singleton();
Singletonizer(Singleton);
};
return Singletonizer(Router);
});

Related

Marionettejs Routes

I'm new to Marionette and I just can't get routes to work.
I'm using Marionette's 2.4.1 version, and trying to do it the simplest way possible so it'll just work.
This code works for old version of Marionette, v1.0.2, which was included in one of the yeoman's generator. I know there's a huge gap between those two versoins but for every post, blog, official documentation and even books written for this framework code stays the same.
There are no errors in console, but the 'home' method just won't start.
Am I missing something here?
application.js (Application body):
define(['backbone', 'marionette'],
function (Backbone, Marionette) {
'use strict';
var App = new Marionette.Application();
App.Router = Marionette.AppRouter.extend({
appRoutes: {
"home": "home"
}
});
var myController = {
"home": function() {
console.log("This thing just won't work.");
}
};
/* Add initializers here */
App.addInitializer(function () {
console.log('App initialized');
new App.Router({
controller: myController
});
});
App.on("initialize:after", function () {
if (Backbone.history) {
Backbone.history.start();
}
});
return App;
});
main.js (Starts our app defined in application.js):
require(['marionette', 'application'],
function ( Marionette, App ) {
'use strict';
App.start();
});
config.js (Config for require.js)
require.config({
baseUrl: "/scripts",
/* starting point for application */
deps: ['marionette', 'main'],
shim: {
backbone: {
deps: [
'underscore',
'jquery'
],
exports: 'Backbone'
},
marionette: {
deps: ['backbone'],
exports: 'Marionette'
}
},
paths: {
backbone: '../bower_components/backbone/backbone',
jquery: '../bower_components/jquery/dist/jquery',
underscore: '../bower_components/underscore/underscore',
/* alias all marionette libs */
'marionette': '../bower_components/marionette/lib/core/backbone.marionette',
'backbone.wreqr': '../bower_components/backbone.wreqr/lib/backbone.wreqr',
'backbone.babysitter': '../bower_components/backbone.babysitter/lib/backbone.babysitter'
}
});
It looks like you're missing a reference to the router's controller.
Try updating the Router to include a reference to myController:
App.Router = Marionette.AppRouter.extend({
controller: myController,
appRoutes: {
"home": "home"
}
});
See AppRouter docs for more infomation:
http://marionettejs.com/docs/v2.4.1/marionette.approuter.html
It seems that initialize:after in:
App.on("initialize:after", function () {
if (Backbone.history) {
Backbone.history.start();
}
});
isn't supported in newest versions of Marionette and I was supposed start instead:
App.on("start", function () {
if (Backbone.history) {
Backbone.history.start();
}
});
Most posts about Marionette seems to be rather outdated. Those are still really helpful but be sure to verify it with the official framework's documentation.
I should've done that in the first place..

Unexpected behavoiur of define of requirejs

This code is working
define([
'jquery',
'underscore',
'backbone'
], function($, _, Backbone,home_template) {
var HomeView = Backbone.View.extend({
render: function() {
alert('abcd');
}
});
return HomeView;
});
this code is not working
define([
'jquery',
'underscore',
'backbone',
'text!modules/home/home_template.html'
],
function($, _, Backbone,home_template) {
var HomeView = Backbone.View.extend({
render: function() {
alert('abcd');
}
});
return HomeView;
});
My directory structure is like webroot/modules/home/home_template.html
What can be the problem ??
Thanks
Problem might be in two possible places:
1) Error in path(u can check in in fireBug or any other tool in network tab, look for 404 errors). It might be template or some other scripts placed inn wrong folder.
2) Error in template syntax - in case of underscore be sure your template wrapped in <script type="template">.

Import and using javascript library in backbone.js project

I'm newbie to backbone.js and require.js. Currently I create one backbone project.
Here is app.js code :
define([
'jquery',
'underscore',
'backbone',
'script',
'router'
], function($, _, Backbone, Script, Router){
var initialize = function(){
Router.initialize();
};
return {
initialize: initialize
};
});
Here is main.js:
require.config({
path: {
jquery: 'libs/jquery/jquery-min',
underscore: 'libs/underscore/underscore-min',
backbone: 'libs/backbone/backbone-min',
script: 'libs/scripts/index'
},
shim:{
backbone: ['jquery', 'underscore'],
script: ['jquery'],
enforceDefine: true
}
});
require([
'app',
], function(App){
App.initialize();
});
And the last one is router.js :
define([
'jquery',
'underscore',
'backbone',
'script'
], function($, _, Backbone){
var AppRouter = Backbone.Router.extend({
routes:{
'*actions': 'defaultAction'
}
});
var initialize = function(){
var app_router = new AppRouter;
app_router('route:defultAction', function(actions){
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
I want to add jquery-json library to my project. If in html project, here is my code :
<script type="text/javascript" src="jquery-min.js"></script>
<script type="text/javascript" src="jquery.json-2.4.min.js">
</script>
<script>
function serializeObjToJSON(_obj) {
var _json = $.toJSON(_obj);
return _json;
}
function deserializeJSONToObj(_json) {
var _obj = $.evalJSON(_json);
return _obj;
}
</script>
I want to import the library above and using it in my backbone project. But I have no idea how to do that.
Any help would be much appreciated, thank you.
in your main JS you should add the JSON reference. (put jquery.json-2.4.min.js into lib/ folder)
require.config({
path: {
jquery: 'libs/jquery/jquery-min',
underscore: 'libs/underscore/underscore-min',
backbone: 'libs/backbone/backbone-min',
script: 'libs/scripts/index',
json: 'libs/jquery.json-2.4.min'
}
Then you can add it as a definition into the app.js or any other module.js file which is using it in reference .
define([
'jquery',
'underscore',
'backbone',
'script',
'router',
'json'
], function($, _, Backbone, Script, Router, Json){
//Code
}
Then within your js files you have your reference to json. You can call it by using
Json.method()
for example.. As soon as you write json, it looks for your definition and then reffers to that lib for the functions you called.
So your index.js or whichever end you want to call it will require something like :
define([
'jquery',
'underscore',
'backbone',
'script',
'router',
'json'
], function($, _, Backbone, Script, Router, Json){
serializeObjToJSON: function(_obj) {
var _json = Json.toJSON(_obj);
return _json;
}
deserializeJSONToObj: function(_jsonObject) {
var _returnObj = Json.evalJSON(_jsonObject);
return _returnObj;
}

Using Backbone.js View as Require.js Dependency

How can I include a view from another file (e.g. Views.js) in a JavaScript file loaded as a Require.js module? I receive a "Uncaught TypeError: object is not a function" error when I try to instantiate myView.
define([
'jQuery',
'Underscore',
'Backbone',
'src/Views'
], function ($, _, Backbone, myView) {
new myView ({ });
});
Do your "src/views.js" have a return value?
some like this:
define(['underscore', 'backbone'], function(_, Backbone) {
var view = Backbone.View.extend({
......
});
return view; //the return value is essential
});

require.js modules not loading properly

I have my bootstrap file which defines the require.js paths, and loads the app and config modules.
// Filename: bootstrap
// Require.js allows us to configure shortcut alias
// There usage will become more apparent futher along in the tutorial.
require.config({
paths: {
bfwd: 'com/bfwd',
plugins: 'jquery/plugins',
ui: 'jquery/ui',
jquery: 'jquery/jquery.min',
'jquery-ui': 'jquery/jquery-ui.min',
backbone: 'core/backbone.min',
underscore: 'core/underscore.min'
}
});
console.log('loading bootstrap');
require([
// Load our app module and pass it to our definition function
'app',
'config'
], function(App){
// The "app" dependency is passed in as "App"
// Again, the other dependencies passed in are not "AMD" therefore don't pass a parameter to this function
console.log('initializing app');
App.initialize();
});
app.js is loaded like it should, and it's dependencies are loaded. it's define callback is called, with all the correct dependencies passed as arguments. No error is thrown. HOWEVER, in the bootstrap's callback, App is undefined! no arguments are passed. What can be causing this? Here's my app file ( modified for space)
// Filename: app.js
define(
'app',
[
'jquery',
'underscore',
'backbone',
'jquery-ui',
'bfwd/core',
'plugins/jquery.VistaProgressBar-0.6'
],
function($, _, Backbone){
var initialize = function()
{
//initialize code here
}
return
{
initialize: initialize
};
}
);
As far as I am aware you should probably just drop the 'app' string in your app.js define method.
// Filename: app.js
define([
'jquery',
'underscore',
'backbone',
'jquery-ui',
'bfwd/core',
'plugins/jquery.VistaProgressBar-0.6'
], function($, _, Backbone){
...
);
Ok I had the same problem, the key is the jquery path alias you define. It turns out that RequireJS has some special handling for jquery. If you use the jquery module name it will do a little bit of magic there.
Depending on what you have in jquery.min.js it may cause some problems, also the jquery plugin you have there may be a problem. Here are the relevant lines of code from the RequireJS source:
if (fullName) {
//If module already defined for context, or already loaded,
//then leave. Also leave if jQuery is registering but it does
//not match the desired version number in the config.
if (fullName in defined || loaded[id] === true ||
(fullName === "jquery" && config.jQuery &&
config.jQuery !== callback().fn.jquery)) {
return;
}
//Set specified/loaded here for modules that are also loaded
//as part of a layer, where onScriptLoad is not fired
//for those cases. Do this after the inline define and
//dependency tracing is done.
specified[id] = true;
loaded[id] = true;
//If module is jQuery set up delaying its dom ready listeners.
if (fullName === "jquery" && callback) {
jQueryCheck(callback());
}
}
For me I have it setup such that I have a file called /libs/jquery/jquery.js which returns the jquery object (just a wrapper for RequireJS). What I ended up doing was simply changing the path alias from jquery to $jquery. This helps avoid the undesired magic behavior.
In the original tutorial I read they use jQuery which also works.
This is a simple example that might help get you started:
I've created a very simple module:
https://gist.github.com/c556b6c759b1a41dd99d
define([], function () {
function my_alert (msg) {
alert(msg);
}
return {
"alert": my_alert
};
});
And used it in this fiddle, with only jQuery as an extra dependency:
http://jsfiddle.net/NjTgm/
<script src="http://requirejs.org/docs/release/1.0.7/minified/require.js"></script>
<script type="text/javascript">
require.config({
paths: {
"jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min",
"app": "https://gist.github.com/raw/c556b6c759b1a41dd99d/20d0084c9e767835446b46072536103bd5aa8c6b/gistfile1.js"
},
waitSeconds: 40
});
</script>
<div id="message">hello</div>
<script type="text/javascript">
require( ["jquery", "app"],
function ($, app) {
alert($.fn.jquery + "\n" + $("#message").text());
app.alert("hello from app");
}
);
</script>
This is how I do it with requirejs and backbone:
first, define main or bootstrap file with config:
// bootstrap.js
require.config({
paths: {
text: 'lib/text',
jQuery: 'lib/jquery-1.7.2.min',
jqueryui: 'lib/jquery-ui-1.8.22.custom.min',
Underscore: 'lib/underscore-1.3.3',
Backbone: 'lib/backbone-0.9.2'
},
shim: {
'Underscore': {
exports: '_'
},
'jQuery': {
exports: 'jQuery'
},
'jqueryui': {
exports: 'jqueryui'
},
'Zepto': {
exports: '$'
},
'Backbone': {
deps: ['Underscore', 'Zepto'],
exports: 'Backbone'
}
});
define(function (require) {
'use strict';
var RootView = require('src/RootView');
new RootView();
});
Then, I use this syntax to load my scripts. I find it easier than the array notation to just define my depencies via var declarations.
// rootview.js
define(function (require) {
'use strict';
var $ = require('Zepto'),
Backbone = require('Backbone'),
LoginView = require('./LoginView'),
ApplicationView = require('./ApplicationView'),
jQuery = require('jQuery').noConflict();
return Backbone.View.extend({
// append the view to the already created container
el: $('.application-container'),
initialize: function () {
/* .... */
},
render: function () {
/* .... */
}
});
});
Hope it helps!
This is a bit late, but I just had this problem. My solution can be found here:
https://stackoverflow.com/questions/27644844/can-a-return-statement-be-broken-across-multiple-lines-in-javascript
I posted that question for a different reason, to ask why my fix worked in the first place. Elclanrs provided the perfect answer. To make a long story short, the undefined is probably appearing due to javascript's automatic semicolon insertion: Automatic semicolon insertion & return statements
If you try changing the position of the curly bracket from underneath to directly after the return statement, I think your problem will disappear.
// Filename: app.js
define(
.
.
.
function($, _, Backbone){
var initialize = function()
{
//initialize code here
}
return {
initialize: initialize
};
}
);

Categories