Why does my Handlebars not have a compile method? - javascript

I am setting up a Backbone project with Handlebars and I am having an issue with Handlebars not finding the compile method. Here is my config file:
require.config({
hbs: {
templateExtension: '.hbs'
},
paths: {
backbone: "libs/backbone/backbone",
handlebars: 'libs/handlebars/handlebars.amd',
hbs: 'libs/requirejs-hbs/hbs',
jquery: 'libs/jquery/jquery',
jqueryMockAjax: 'libs/jquery-mockjax/jquery.mockjax',
text: 'libs/requirejs-text/text',
templates: 'templates/',
underscore: 'libs/underscore/underscore'
},
shim: {
backbone: {
deps: [
'underscore',
'jquery'
],
exports: 'Backbone'
},
hbs: {
deps: ['handlebars'],
exports: 'hbs'
},
jqueryMockAjax: {
deps: [ 'jquery' ],
exports: '$.mockjax'
},
underscore: {
exports: '_'
}
}
});
require(['app'], function(App) {
'use strict';
var app = new App();
app.render();
});
Here is the app.js that I am trying to render:
define(function(require) {
var Backbone = require('backbone');
var testTemplate = require('hbs!templates/test');
var router = Backbone.View.extend({
el: $('body'),
template: testTemplate,
render: function() {
return $(this.el).html(this.template());
}
});
return router;
});
When Handlebars calls the hbs.js file on line 25 it cannot find the compile function
define(["handlebars"], function(Handlebars) {
var buildMap = {},
templateExtension = ".hbs";
return {
// http://requirejs.org/docs/plugins.html#apiload
load: function (name, parentRequire, onload, config) {
// Get the template extension.
var ext = (config.hbs && config.hbs.templateExtension ? config.hbs.templateExtension : templateExtension);
if (config.isBuild) {
// Use node.js file system module to load the template.
// Sorry, no Rhino support.
var fs = nodeRequire("fs");
var fsPath = config.dirBaseUrl + "/" + name + ext;
buildMap[name] = fs.readFileSync(fsPath).toString();
onload();
} else {
// In browsers use the text-plugin to the load template. This way we
// don't have to deal with ajax stuff
parentRequire(["text!" + name + ext], function(raw) {
// Just return the compiled template
****HERE onload(Handlebars.compile(raw));
});
}
},
// http://requirejs.org/docs/plugins.html#apiwrite
write: function (pluginName, name, write) {
var compiled = Handlebars.precompile(buildMap[name]);
// Write out precompiled version of the template function as AMD
// definition.
write(
"define('hbs!" + name + "', ['handlebars'], function(Handlebars){ \n" +
"return Handlebars.template(" + compiled.toString() + ");\n" +
"});\n"
);
}
};
});
The Handlebars variable gives me the Handlebars environment, but it has an extra layer in it, so I have to change that line to Handlebars.default.compile(raw). Where is that default object coming from and how do I get rid of it? I wouldn't worry about it, but if I pull down this project somewhere else I am always going to have to remember to do that.

I just encountered this myself, using Handlebars for this first time. It's likely that you're using the "runtime" build of Handlebars. I included this one in my requirements, mistakenly assuming it was the minified version or something.
But in fact the runtime version is significantly smaller as it excludes the template compiler, and is for use only with pre-compiled templates. If you're compiling the template client-side then you need the full version from http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v3.0.3.js (Note: This link may be out of date; you're probably better off going directly to handlebarsjs.com and looking for the current download for the "full version", as opposed to runtime.)
Otherwise, you can follow the instructions on the Handlebars website to run the template compiler. You need node for this. The template compiler produces a JavaScript file containing the pre-compiled template code which you need to link to your page along with the Handlebars runtime build.

Here is how I fixed this issue, although I do not understand completely why the configuration above did not work. The hbs plugin had a folder with all the dependencies it needed in it, like handlebars. When I referred to the handlebars copy contained in the hbs directory, then everything worked like it was supposed to. I do not understand why the vanilla copy of handlebars did not work. I was not using the handlebars runtime, it was the full version, but still there was an issue. After I resolved this, then my template stuff just worked.

Related

Load Test csript inside test in intern.js

I'm trying to load test script according to custom argument passed through start command to start intern test.
To do this I'm trying to require the specific test script inside a test but i am getting Attempt to require unloaded module error.
This is my code set up. Can someone help on on this or sugest some alternative work around to make this work.
define(function (require) {
var intern = require('intern');
var AdvalentAutomationTestSuite = require('intern!object');
AdvalentAutomationTestSuite({
name: 'Advalent Automation Test',
'AdvalentTestSets': function () {
return this.remote
.then(function () {
var product = intern.args.product;
var script = 'Automation/TestScripts/FRG/' + product + '-Config';
require(script)
})
},
});
});
Update:
Including intern.js file:
define(function (require) {
var intern = require('intern');
console.log(intern)
return {
proxyPort: 9000,
proxyUrl: 'http://localhost:9000/',
defaultTimeout: 120000,
capabilities: {
'selenium_version': '2.48.2',
},
environments: [
{browserName: 'chrome', version: '48', platform: ['WINDOWS'], chromeOptions: {args: ['start-maximized']}},
],
maxConcurrency: 3,
tunnel: 'NullTunnel',
reporters: [
{id: 'JUnit', filename: 'test-reports/report.xml'},
{id: 'Runner'},
],
Loaders: {
'host-node': 'dojo/dojo',
'host-browser': 'node_modules/dojo/dojo.js'
},
loaderOptions: {
packages: [{name: 'intern-tutorial', location: '.'}]
},
functionalSuites: [
'Automation/TestScripts/FRG/FRG-Config',
],
defaultTimeout: 70000,
excludeInstrumentation: /^(?:tests|node_modules)\//
}
});
You should be fine with the default loader, although as #Troopers points out, it's loaders, not Loaders. The problem is that you're doing a dynamic require with a computed name:
var script = 'Automation/TestScripts/FRG/' + product + '-Config';
require(script)
AMD loaders don't completely support the require(script) syntax since they don't load modules synchronously. When a module is written in CJS-compatibility mode, the loader fakes it by scanning the module code for require calls and then preloading and caching the modules before executing the module code. When the require(script) call is eventually executed, the preloaded module is returned.
When you use a computed module name, the loader can't preload the module being required, so the synchronous require call will fail. To load a module with a computed name you'll need to use the require([ dependency ]) syntax, like:
var script = 'Automation/TestScripts/FRG/' + product + '-Config';
return new Promise(function (resolve) {
require([ script ], resolve);
});
At a higher level, though, it seems odd to be doing this in a test in the first place. It seems like something that should be handled at the module or config levels. For example, assuming 'Automation/TestScripts/FRG/' + product + '-Config' is a functional test suite, the config could simply add that suite to the functionalSuites list if the required command line argument were provided.
You need to specify a loader in your configuration file :
loaders: {
"host-node": "requirejs",
"host-browser": "node_modules/requirejs/require.js"
},
And install the npm package requirejs
The documentation is here
After few hit and trial I managed to make it work by changing my intern.js as follows:
define(function (require) {
var intern = require('intern');
var product = intern.args.product
return {
functionalSuites: [
'Automation/TestScripts/FRG/' + product + '-Config.js',
],
// rest of config code ...
}
});
Please suggest if there's any better way to do this.

Require JS with Knockout components is looking for js file in incorrect path

I am trying to understand how require js works by building knockout components.I have built 2 separate knockout components for testing. My directory structure is as follows:
- App
|_ Components
|_ Like-Widget
|_like-widget.js
|_like-widget.html
|_ sign-in
|_sign-in.js
|_sing-in.html
|_ startup.js
- Scripts
|_ knockout.js
|_ knockout-es5.js
|_ app.js
I have configured require.js as follows in app.js file
require.config({
paths: {
ko: "/Scripts/knockout-3.4.0",
kox: "/Scripts/knockout-es5",
jquery: "/Scripts/jquery-1.10.2.min",
text: "/Scripts/text"
},
shim: {
"kox": {
deps:["ko"]
}
},
baseUrl: "/App/Components"
});
require(["/App/Components/startup.js"]);
Here is my startup.js file
define(['ko'], function (ko) {
ko.components.register('like-widget', { require: 'like-widget/like-widget' });
ko.components.register('sign-in', { require: 'sign-in/sign-in' });
ko.applyBindings();
});
my like-widget.js and sign-in.js files are almost identical for testing purpose
define(["kox", "text!like-widget/like-widget.html"], function (ko, template) {
function myViewModel(params) {
var self = this;
self.personName = 'Bob';
self.personAge = 23;
ko.track(this);
};
return {
viewModel: myViewModel,
template: template
};
});
define(["kox", "text!sign-in/sign-in.html"], function (ko, template) {
function signInViewModel(params) {
var self = this;
self.userName = 'User 1';
ko.track(this);
};
return {
viewModel: signInViewModel,
template: template
};
});
this is how I am referring to require.js in my html page
<script type='text/javascript' data-main="/Scripts/app.js" src="~/Scripts/require.js"></script>
The problem is that my like-widget component is working fine but as soon as I try to use my sign-in component, I am getting an error
GET http://localhost:65182/App/Components/knockout.js
Uncaught Error: Script error for "knockout", needed by: kox
http://requirejs.org/docs/errors.html#scripterror
From the error it seems that requirejs is trying to load knockout from incorrect location, my knockout.js is not in components directory but in scripts directory. What I can't understand is how it is correctly loading the like-widget component?
I am new to requirejs so I am assuming I am making some naive mistake, can you please point it out?
If you look at the source code for knockout-es5 plugin you will see that it requires the knockout path to be set to 'knockout', not 'ko'.
} else if (typeof define === 'function' && define.amd) {
define(['knockout'], function(koModule) {
ko = koModule;
attachToKo(koModule);
weakMapFactory = function() { return new global.WeakMap(); };
return koModule;
});
}
If you change your require config path for knockout
require.config({
paths: {
knockout: "/Scripts/knockout-3.4.0",
// instead of ko: "/Scripts/knockout-3.4.0"
}
it should work. You can also remove the shim for knockout-es5 (kox in your example) since it shouldn't be needed.

How to Override a model/ view file at runtime, for a js file combined by requirejs optimizer?

Scenario:
Framework used are backbone and require.
I have a main.js which have several dependencies on util, model and view js, which are again inter-dependent. There are cyclic dependencies also.
This main.js has been compiled into a single file using requirejs optimizer.
Problem:
How to override certain views and models at runtime?
(I have a single compiled version of main, so i am not talking about excluding the js for models or views at compile time).
At compile time i don't know whether the model/view would be over-ridden. So when i run the optimizer a single js file with all the models and views is created.
I need to override a particular class definition in that single js file, such that i don't modify that file.
Is there any configuration which will tell 'require' to load the model/view from a separate file rather than that single compiled js file?
or is there any way this could be achieved, with minimal changes?
//models/ - folder
//mymodel.js - filename
define([
'jquery',
'underscore',
'backbone'
], function($, _, Backbone) {
var mymodel2 = Backbone.Collection.extend({
//some code
});
return mymodel2;
});
//mymodel2.js - filename
define([
'jquery',
'underscore',
'backbone',
'mymodel'
], function($, _, Backbone, mymodel) {
var mymodel2 = Backbone.Collection.extend({
//some code
});
return mymodel2;
});
//views/ - folder
//view1.js - filename
define([
'jquery',
'underscore',
'backbone',
'runtime/util/logmanager',
'runtime/util/logger'
], function($, _, Backbone, LogManager, Logger) {
var view1 = Backbone.View.extend({
_configure: function(options) {
//some code
},
initialize: function() {
//some code
},
endsWith: function(str, suffix) {
//some code
}
});
return view1;
});
//like this i have view2.js, view3.js... etc
//Similarly i have util folder with util1.js, util2.js... etc
//main.js
;(function(){
if (!window.console) window.console = {};
if (!window.console.log) window.console.log = function () { };
var paths = {
jquery: 'libs/jquery/jquery',
underscore: 'libs/underscore/underscore',
initializer: 'runtime/initializer/initializer',
backbone: 'libs/backbone/backbone',
json2: 'libs/json/json2',
text: 'libs/require/text',
jqueryform: 'libs/jqueryform/jqueryform',
jqueryui: 'libs/jqueryui/jquery-ui',
slimscroll: 'libs/slimscroll/slimScroll',
i18next: 'libs/i18next/i18next',
common: 'libs/commons/common',
utility1 : 'util/util1',
utility2 : 'util/util2',
.
.
model2 : 'model/mymodel2',
.
.
.
view2 : 'view/view1'
};
window.configData = window.configData || {};
window.configData.serverPath = location.protocol + "//" + window.location.host;
require.config({
paths: paths,
shim: {
'underscore': {
exports: '_'
},
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'i18next': {
deps: ['jquery', 'json2'],
exports: 'i18n'
}
}
});
require(['router'],
function(Router) {
Router.initialize();
});
})();
compiled/ combined file will look something like:
*! jQuery v1.7.1 jquery.com | jquery.org/license */
(//jquery-def file code)(window);
// Underscore.js 1.3.3
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the MIT license.
// Portions of Underscore are inspired or borrowed from Prototype,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore
(function() {
//uderscore code
}).call(this);
define("underscore", (function (global) {
return function () {
var ret, fn;
return ret || global._;
};
}(this)));
.
.
.
all lib definition
.
.
then depending on the dependencies models, views, utils, routers, definition
.
.
and finally main
;(function(){
if (!window.console) window.console = {};
if (!window.console.log) window.console.log = function () { };
var paths = {
jquery: 'libs/jquery/jquery-min',
underscore: 'libs/underscore/underscore',
initializer: 'runtime/initializer/initializer',
backbone: 'libs/backbone/backbone',
json2: 'libs/json/json2',
text: 'libs/require/text',
bootstrap: 'libs/bootstrap/bootstrap',
jqueryform: 'libs/jqueryform/jqueryform',
jqueryui: 'libs/jqueryui/jquery-ui',
slimscroll: 'libs/slimscroll/slimScroll',
i18next: 'libs/i18next/i18next',
common: 'libs/commons/common',
utility1 : 'util/util1',
utility2 : 'util/util2',
.
.
model2 : 'model/mymodel2',
.
.
.
view2 : 'view/view1'
};
window.configData = window.configData || {};
window.configData.serverPath = location.protocol + "//" + window.location.host;
require.config({
paths: paths,
shim: {
'underscore': {
exports: '_'
},
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'i18next': {
deps: ['jquery', 'json2'],
exports: 'i18n'
}
}
});
require(['router'],
function(Router) {
Router.initialize();
});
})();
define("main", function(){});
Is there any configuration which will tell 'require' to load the
model/view from a separate file rather than that single compiled js
file?
To load a Javascript file using require, you can call it at any time (even after the optimizer has been run), like so:
myModule = require('myJavascriptFile');
The optimized file isn't designed to be manipulated. Modify your source, then re-optimize.
Also, note: Require does not compile your Javascript.
How to override certain views and models at runtime?
In Javascript, you can reassign variables at any time. Example:
var x = 1; // the value of x is 1
x = 2; // the value of x is now 2
Similarly, you can override Backbone Models and Views at runtime like so:
var myModel = new Backbone.Model({x: 1});// create myModel
myModel = new Backbone.Model({x: 2});// now, myModel is a different model
myModel = "something else entirely";// now, myModel is a string
You could override require() itself and make it look for the module in a directory first before loading it the way that it normally does.
This probably won't be easy to do.

How to load bootstrapped models in Backbone.js while using AMD (require.js)

Backbone.js documentation suggest loading bootstrapped models this way:
<script>
var Accounts = new Backbone.Collection;
Accounts.reset(<%= #accounts.to_json %>);
var Projects = new Backbone.Collection;
Projects.reset(<%= #projects.to_json(:collaborators => true) %>);
</script>
But this is a pattern that can't be used in AMD approach (using require.js)
The only possible solution is to declare global variable storing JSON data and use this variable later in relevant initialize methods.
Is there a better way to do this (without globals)?
This is how we bootstrap data in a way that it doesn't pollute the global namespace. Instead it uses require.js exclusively. It also helps you provide the initial app configuration based on variables within the template.
Within your rendered page
<script src="require.js"></script>
<script>
define('config', function() {
return {
bootstrappedAccounts: <%= #accounts.to_json %>,
bootstrappedProjects: <%= #projects.to_json(:collaborators => true) %>
};
});
</script>
<script src="app.js"></script>
globals.js
This file checks for config and extends itself using any of the data returned
define([
'config',
'underscore'
], function(config) {
var globals = {
};
_.extend(globals, config);
return globals;
});
config.js
This file is needed if you want be able to load the app regardless of if you have defined config in the page.
define(function() {
// empty array for cases where `config` is not defined in-page
return {};
});
app.js
require([
'globals',
'underscore',
'backbone'
], function(globals) {
if (globals.bootstrappedAccounts) {
var accounts = new Backbone.Collection(globals.bootstrappedAccounts);
}
if (globals.bootstrappedProjects) {
var projects = new Backbone.Collection(globals.bootstrappedProjects);
}
});
Looks like you can use the require.config() function or the "require" global with the "config" option in order to pass data to a module through the special dependency "module". See http://requirejs.org/docs/api.html#config-moduleconfig:
There is a common need to pass configuration info to a module. That
configuration info is usually known as part of the application, and
there needs to be a way to pass that down to a module. In RequireJS,
that is done with the config option for requirejs.config(). Modules
can then read that info by asking for the special dependency "module"
and calling module.config().
So, for bootstrapping models we have, in the top level HTML page:
<script>
var require = {
config: {
'app': {
bootstrappedAccounts: <%= #accounts.to_json %>
bootstrappedProjects: <%= #projects.to_json(:collaborators => true) %>
}
}
};
</script>
<script src="scripts/require.js"></script>
Then in the app module (app.js), we have:
define(['module'], function (module) {
var accounts = new Backbone.Collection( module.config().bootstrappedAccounts );
var bootstrappedProjects = new Backbone.Collection( module.config().bootstrappedProjects );
});
Here "module" is a special dependency supplied for these types of cases.
This is untested but looks pretty sure from the documentation.
In RequireJS this is done with the config option for requirejs.config(). Modules can then read that info by asking for the special dependency "module" and calling module.config(). Example:
index.html
<script>
var require = {
config: {
'app': {
'api_key': '0123456789-abc'
}
}
};
</script>
<script src="js/libs/require.js" data-main="js/main"></script>
main.js
require( ['app'], function(App) {
new App();
});
app.js
define( ['module'], function(module) {
var App = function() {
console.log( 'API Key:', module.config().api_key );
};
return App;
});
Just note that the name of the configuration-object must match the name of the module. In my example the name of the module was app, so the name of the configuration-object needed to be named app as well. In the module, you will need to include ['module'] as a dependency and call module.config()[property name] to retrieve the configuration-data.
Read the documentation about this: http://requirejs.org/docs/api.html#config-moduleconfig
Some of the answers here got me close to my similar problem but nothing nailed it. In particular the top ranked and accepted answer gave seemed to give me a nasty race condition where sometimes the dummy object would load first. This also happened 100% of the time when used with the optimiser. It also uses explicit string names for the module which the require documentation specifically advises you not to do.
Here's how I worked it. Similar to Brave Dave, I use the config object to capture parameters (in my case from a jsp page) like so
<script type="text/javascript">
var require = {
config: {
options : {
bootstrappedModels : ${models}
}
}
}
</script>
In particular note that my parameters are in an object called options. This name is not optional! Though the documentation makes no mention of this, the following is how require will load your config (line 564 in requirejs 2.1.1) :
config: function () {
return (config.config && config.config[mod.map.id]) || {};
},
The key point is that there has to be property on the config object with the key mod.map.id which resolves to 'options'.
From here you can now access the models like so
define(['module'], function(module){
console.log(module.config().bootstrappedModels);
//...
});
You could add a loopy function at the end of your AMD module to check for when the init method is defined (so that it can be populated after body, or loaded from an include). that way the module is guaranteed available and initialization can happen when it's ready.
require(...,function (...) {
//define models collections, etc..
var initme = function () {
if(document.initThisModule)
document.initThisModule();
else
setTimeout(initme, 10);
}();
});
I'm not (too) familiar with the AMD approach, but instead of using a global variable, why don't you add the JSON to the dom.
for example:
var json = ...,
$jsonContainer = $(json).wrap("<script id='json-container' type='text/javascript'>").appendTo($("body"));
Then, instead of an embedded script tag as suggested by the backbone documentation, inside the document ready:
$(function(){
MyCollection.reset($("#json-container").html());
...
});
How about doing something like this:
<script>
define('Models', ['backbone'], function(Backbone) {
var Models = {
Accounts: new Backbone.Collection,
Projects: new Backbone.Collection
};
Models.Accounts.reset(<%= #accounts.to_json %>);
Models.Projects.reset(<%= #projects.to_json(:collaborators => true) %>);
return Models;
});
</script>
Then you'll be able to use Models in other modules like this:
var models = require(['Models']);
models.Accounts.doWhatYouNeed();
or this:
define(['any', 'dependencies', 'and', 'Models'], function(a, b, c, Models) {
// Models will be available here
});
Like described above, the 'data module' (or config, or whatever you want to call it) could be included in a file that is already generated anyway (e.g. index.html) but I think this is rather ugly.
Another way would be to declare it in its own module file but this would require an extra roundtrip to the server in production environments. As soon as you want to build and optimize your requirejs dependencies, the data module cannot be included because it is dynamically generated upon page load.
A third option might be to append it to one of the files that you serve (for example, the optimized requirejs file), but I have no idea of how/if that could be done.
Ansewr by #dlrust work but it not able extend param and pass more than from one place in code. If you try do something like this in your render template:
<script>
define('config', function() {
return {
bootstrappedAccounts: <%= #accounts.to_json %>,
bootstrappedProjects: <%= #projects.to_json(:collaborators => true) %>
};
});
</script>
and in another file add some data
<script>
define('config', function() {
return {
goods: <%= some data %>,
showcaseList: <%= some json or array %>
};
});
</script>
it was overwrite (NOT EXTEND!!!). In config will be only last declared data.
My solution: used Backbone model with set/get data.
app.js
define("App", [], function() {
window.App = {
// модели
Model: {},
// коллекции
Collection: {},
// виды
View: {},
// роутеры
Router: {},
// модальные окна
Modal: {},
// UI компоненты
UI: {}
};
return window.App;
});
global.js
define(["App", "underscore", "backbone"], function(App, _, Backbone) {
"use strict";
// модель глобальных данных
App.Model.Global = Backbone.Model.extend({
defaults: {}
});
return new App.Model.Global;
});
index.php
<!DOCTYPE html>
<html>
<head>
<!--HEAD_START-->
<script type="text/javascript" data-main="/app/init" src="/app/require/require.js"></script>
<!--HEAD_END-->
</head>
<body>
<div id="tm-inner-wrap">
<div id="loader"><i class="uk-icon-refresh uk-icon-spin"></i></div>
<!--HEADER_START-->
<?= $this->includeTpl('header_view'); ?>
<!--HEADER_END-->
<!--CONTENT_START-->
<div>your html content data</div>
<!--CONTENT_END-->
<!--FOOTER_START-->
<?= $this->includeTpl('footer_view');?>
<!--FOOTER_END-->
<script>
require(["global"], function(Global) {
Global.set("notifyList", <?=json_encode($this->notifyList);?>);
});
</script>
</div>
</body>
</html>
another template
someTemplate.php
<div class="tm-inner-body">
<div class="uk-container uk-container-center">
// content data
</div>
</div>
<script>
require(["global", "module/index"], function(Global) {
Global.set("goodList", <?=json_encode($this->goodList);?>);
});
</script>
index.js
require(["App", "core", "jquery", "uikit!uikit-addons-min", "underscore", "backbone", "global", "module/good/goodView"], function(App, Core, $, UIkit, _, Backbone, Global, goodView) {
"use strict";
// Global.get("notifyList"); its too able
App.Collection.Good = new Backbone.Collection(Global.get("showcaseList")["items"]);
// вид списка товаров
App.View.GoodList = Backbone.View.extend({
// елемент
el: ".tm-good-list",
// init
initialize: function() {
this.collection = App.Collection.Good;
// список товаров
this.drawList();
},
// отрисовка списка
drawList: function() {
this.$el.empty();
this.collection.each(function(item, index) {
this.$el.append(this.drawItem(item));
}, this);
},
// отрисовка елемента
drawItem: function(data) {
var good = new goodView({model: data});
return good.render().el;
}
});
App.View.Index = Backbone.View.extend({
el: "body",
// пользовательские события
events: {
//
},
// init
initialize: function() {
var $this = this;
if(Global.get("showcaseList")) new App.View.GoodList();
}
});
new App.View.Index();
});
File structure:

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