I am having an issue with an undefined variable in my module set up, best to explain by example, I have:
common.js (config for requirejs)
require([
'module/polyfills/someModule'
], function(
module
) {
module.init();
});
module/polyfills/someModule.js
define([
'underscore',
'config',
'text!tpl/utils/textTemplate.html'
], function(_, config, template) {
// ref 1
return {
init: function() {
// ref 2
// do stuff
},
events: function() {
// add some events
},
};
});
If I put a breakpoint at the comment ref 1 I can see the config variable and its properties. However if I put a breakpoint at ref 2 then config is undefined. However underscore and the template are not undefined.
I have removed anything special about config in my require configuration. Config looks like this:
config.js
define([], function (clickType) {
return {
clickType: 'test'
};
});
There are no errors in console and I am very certain this is not a circular dependency!
the comment place at ref2 is a closure where you haven't accessed config. The function is created at parse and it is a closure, whatever you access inside it is available. simple test, add the following line of code at //ref2
var myConfig = config;
Now you will see config as defined.
Related
I am trying to keep my code separated in modules. When I defined my first module I extended sap.ui.base.Object and it worked. My question is: Is it a must to extend sap.ui.base.Object when defining my own module? According to the API documentation I tried following example:
sap.ui.define([], function() {
// create a new class
var SomeClass = function();
// add methods to its prototype
SomeClass.prototype.foo = function() {
return "Foo";
}
// return the class as module value
return SomeClass;
});
I required this module inside my Component.js as dependency like this:
sap.ui.define([
"path/to/SomeClass"
], function (SomeClass) {
"use strict";
//var test = new SomeClass();
I always receive a syntax error:
failed to load '[...]/Component.js' from ./Component.js: Error: failed to load '[...]/module/SomeClass.js' from ./module/Service.js: SyntaxError: Unexpected token ;
Does anyone have an idea why this happens? Thanks!
We group code in modules like this for example:
jQuery.sap.declare("our.namespace.iscool.util.Navigation");
our.namespace.iscool.util.Navigation = {
to: function (pageId, context) {
// code here
}
// etc.
}
and call the function of the module like this in a controller
jQuery.sap.require("our.namespace.iscool.util.Navigation");
sap.ui.controller("our.namespace.iscool.Detail", {
// somewhere in this file comes this
handleNavButtonPress: function (evt) {
our.namespace.iscool.util.Navigation.navBackToMaster(
evt.getSource().getBindingContext()
);
},
}
Stupid mistake - missing curly brackets in the docs.
var someclass = function() {} ;
I have an application which has an app object which does the start routine and stores useful things like app.state and app.user. However I am trying to access this app instance without passing this from the app instance all the way around my large codebase.
Strangely I work on other projects which include app in the same way as in something.js and it works but I can't see why.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Cannot require app in another file</title>
</head>
<body>
<script data-main="config" src="require.js"></script>
</body>
</html>
config.js
requirejs.config({
deps: ['app']
});
app.js
define([
'something'
], function(Something) {
'use strict';
var App = function() {
this.name = 'My app';
};
return new App();
});
something.js
define([
'require',
'app'
], function (require, app) {
'use strict';
var SomeModule = function() {
app = require('app'); // EXCEPTION
console.log('App:', app);
};
return new SomeModule();
});
When loading this requirejs exception is throw because of the require in SomeModule:
Uncaught Error: Module name "app" has not been loaded yet for context: _
Demo of above (see console for error): http://dominictobias.com/circulardep/
It's not clear to me why you need to have a circular dependency. As stated in the documentation for RequireJS:
Circular dependencies are rare, and usually a sign that you might want to rethink the design.
This being said, if you do need the circular dependency, the issue with your code is that require('app') is called too early. It cannot be called until after the module something has returned its value. Right now, it is called before the value is returned. If you look at the code given as example in the documentation:
define(["require", "a"],
function(require, a) {
//"a" in this case will be null if a also asked for b,
//a circular dependency.
return function(title) {
return require("a").doSomething();
}
}
);
you see that the module returns a function which then would be called by the code that required the module, which happens after this module has returned its value.
So how do you fix this? What you could do is have the class you return call a function that fetches module app whenever needed. So:
define([
'require',
'app'
], function (require) {
'use strict';
var app_;
function fetch_app() {
if (app_ === undefined)
app_ = require("app");
return app_;
}
var SomeModule = function() {
// ...
};
SomeModule.prototype.doSomethingWithApp = function () {
var app = get_app();
app.whatever();
};
return new SomeModule();
});
I've removed app from the list of arguments and store the value of the app module in app_ because doing it this way provides for early detection of a missing call to get_app() in any method of SomeModule. If app is made a parameter of the module's factory function then using app inside a method without calling get_app() first would be detected only if it so happened that no other method that calls get_app() was called first. (Of course, I could type app_ and face the same problem as the one I aim to prevent. It's a matter of respective likelihoods: I'd be very likely to forget to call get_app() everywhere it is needed because I don't usually write code with circular dependencies. However, I'd be unlikely to type app_ for app because I don't usually put _ at the end of my variable names.)
I have this Backbone view defined:
define(["jquery", "backbone", "main", "text!templates/loginViewTemplate.html"],
function($, Backbone, loginViewTemplate) {
var LoginView = Backbone.View.extend({
render: function() {
console.log(loginViewTemplate);
this.template = _.template(loginViewTemplate, {});
$(this.el).html(this.template);
return this;
},
// ...
});
});
But the console.log statement is "undefined", nothing gets rendered. Although I can see a request to the loginViewTemplate.html file in the console. What am I missing?
After getting off the screen for some minutes, I figured out, that the order of dependency declaration is important.
Making the first line look like this solved it:
define(["jquery", "backbone", "text!templates/loginViewTemplate.html", "main"],
function($, Backbone, loginViewTemplate) {
In my web site, I have bunch of JavaScript files, all for different use but the login page only needs the jquery and loginValidate files. When I attach my main.js, it is suppose to load only these two files by checking the conditions. How to do that?
My config file:
requirejs.config({
baseUrl:"scripts",
paths:{
//libraries
jquery :"lib/jquery-1.9.0.min",
jqueryUI :"lib/jquery-ui-1.9.2.custom.min",
underScore :"lib/underscore-min",
backBone :"lib/backbone-min",
//scripts
appInit :"js/tasklist",
loginValidate :"js/loginValidate"
},
shim:{
"underScore":{
exports: "_"
},
"backBone":{
exports:"Backbone",
deps:["underScore"]
},
"appInit" : {
deps:["jquery","jqueryUI","underScore","backBone"]
},
"jqueryUI":{
deps:["jquery"]
},
"loginValidate":{
deps:['jquery']
}
}
});
It is only needed on login page:
require(["jquery","loginValidate"], function($,validate){
how can i call the loginValidate function?
});
The loginValidate function:
define(function(){
var tasklistHandler = function (params) {
//params take care.. to validate
};
$(function(){ // calling internally the function
var paramsLoginForm = {
loginForm : $('#tlLoginForm')
}
tasklistHandler(paramsLoginForm);
});
})
Is this the correct way to do? I am using also Backbone.js to utilise some other page; how can I proceed for those pages?
The problem you have is the lack of "return" in the "factory" function (the callback function you pass to the define call in the last snippet).
Instead you need to have something like this there:
define(function(){
return function (params) {
//params take care.. to validate
};
})
And in your require call you use run the function that is returned to you by factory function:
require(["jquery","loginValidate"], function($, validate){
var paramsLoginForm = {
loginForm : $('#tlLoginForm')
}
// \|/ that is what is returned by `define`'s callback function.
validate(paramsLoginForm);
});
I am playing around and learning about vows with a personal project. This is a small client side library, with testing done in vows. Therefore, I must build and test a file that is written like this:
(function(exports) {
var module = export.module = { "version":"0.0.1" };
//more stuff
})(this);
In my testing (based off of science.js, d3, etc.) requires that module like so:
require("../module");
I continued to get a "module not defined error" when trying to run the tests, so I went to a repl and ran:
require("../module")
and it returned:
{ module: { version: "0.0.1" } }
I realize I could do something like:
var module = require("../module").module;
but feel like I am creating a problem by doing it that way, especially since the libraries that I based this project on are doing it in the format I described.
I would like for my project to behave similar to those which I based it off of, where:
require("../module");
creates a variable in this namespace:
module.version; //is valid.
I have seen this in a variety of libraries, and I am following the format and thought process to the T but believe I might be missing something about require behavior I don't know about.
There is no problem creating it this way. Modules define what they return in the module.exports object. By the way, you don't actually need self executing functions (SEF), there is no global leakage like in browsers :-)
Examples
module1.js:
module.exports = {
module: { 'version': '0.1.1' }
};
main.js:
var module1 = require( './module1.js' );
// module1 has what is exported in module1.js
Once you've understood how this works, you can easily export the version number right away if you want to:
module1.js:
module.exports = '0.1.1';
main.js:
var module1 = require( './module1.js' );
console.log( module1 === '0.1.1' ); // true
Or if you want some logic, you can easily extend your module1.js file like this:
module.exports = ( function() {
// some code
return version;
} () ); // note the self executing part :-)
// since it's self executed, the exported part
// is what's returned in the SEF
Or, as many modules do, if you want to export some utility functions (and keep others "private"), you could do it like this:
module.exports = {
func1: function() {
return someFunc();
},
func2: function() {},
prop: '1.0.0'
};
// This function is local to this file, it's not exported
function someFunc() {
}
So, in main.js:
var module1 = require( './module1.js' );
module1.func1(); // works
module1.func2(); // works
module1.prop; // "1.0.0"
module1.someFunc(); // Reference error, the function doesn't exist
Your special case
About your special case, I wouldn't recommend doing it like they're doing.
If you look here: https://github.com/jasondavies/science.js/blob/master/science.v1.js
You see that they're not using the var keyword. So, they're creating a global variable.
This is why they can access it once they require the module defining the global variable.
And by the way, the exports argument is useless in their case. It's even misleading, since it actually is the global object (equivalent of window in browsers), not the module.exports object (this in functions is the global object, it'd be undefined if strict mode were enabled).
Conclusion
Don't do it like they're doing, it's a bad idea. Global variables are a bad idea, it's better to use node's philosophy, and to store the required module in a variable that you reuse.
If you want to have an object that you can use in client side and test in node.js, here is a way:
yourModule.js:
// Use either node's export or the global object in browsers
var global = module ? module.exports : window.yourModule;
( function( exports ) {
var yourModule = {};
// do some stuff
exports = yourModule;
} ( global ) );
Which you can shorten to this in order to avoid creating the global variable:
( function( exports ) {
var yourModule = {};
// do some stuff
exports = yourModule;
} ( module ? module.exports : window.yourModule ) );
This way, you can use it like this on the client-side:
yourModule.someMethod(); // global object, "namespace"
And on the server side:
var yourModule = require( '../yourModule.js' );
yourModule.someMethod(); // local variable :-)
Just FYI, .. means "parent directory". This is the relative path of where to get the module. If the file were in the same directory, you'd use ..