I am trying to use RequireJS to use the require() function in the browser. For context, I am trying to work with the Node wrapper for the Lob API: https://github.com/hisankaran/lob-node.
Here's the relevant code:
define (function (require) {
var LOB = require('lob');
LOB = new LOB(API_KEY);
})
// var LOB = new (require('lob')) (API_KEY);
console.log('Success?')
It runs successfully, but when I try to actually call anything, for example LOB.bankaccounts.create, it says LOB is not defined.
The Lob docs suggested that I do simply this:
var LOB = new (require('lob')) (LOB_API_KEY);
but I kept getting that the module had not yet been loaded for context error described here (http://requirejs.org/docs/errors.html#notloaded), so I tried the above syntax from the RequireJS website.
I'm super new to RequireJS (and coding in general), so I may just be doing something silly.
The define() function has to actually return the object it defines.
Furthermore, in the browser require() should be used asynchronously as the synchronous call only works, when the module has already been loaded.
That being said, I would restructure your code as follows:
define( ['lob'], function( LOB ){
return new LOB( API_KEY );
});
Put that in some module definition and load it in your main module, e.g., like this
require( [ 'myLob' ], function( myLob ){
// do something with myLob
});
Related
UPDATE: Worked out a solution I'm comfortable with, the answer is below.
I have an app that uses manual bootstrapping, with a chunk of code that essentially looks like this:
(function() {
'use strict';
angular.element( document ).ready( function () {
function fetchLabels( sLang, labelPath ) {
// retrieves json files, builds an object and injects a constant into an angular module
}
function rMerge( oDestination, oSource ) {
// recursive deep merge function
}
function bootstrapApplication() {
angular.element( document ).ready( function () {
angular.bootstrap( document, [ 'dms.webui' ] );
});
}
fetchLabels( 'en_AU' ).then( bootstrapApplication );
}
It works great - essentially fetches two json files, combines them and injects the result as a constant, then bootstraps the app.
My question is how to unit test these functions? I want to write something to test the fetchLabels() and rMerge() methods, but I'm not sure how to go about it. My first thought was separate the methods out into a service and use it that way, but I wasn't sure if I could actually invoke my own service this way before I've even bootstrapped the application?
Otherwise, can anyone suggest a way to separate out these methods into something standalone that I can test more readily?
OK after some fiddling, I found a solution I'm happy with.
I moved the methods into the Labels Service, and modified the labels module file to preset an empty object into the relevant constant.
I added an exception to my grunt injection setup to ignore the label service files, and instead manually called them earlier where I am calling the module file itself.
I took the direct injection code for $http and $q from the bootstrap script and put them inside the Label service, as they aren't available for normal injection prior to bootstrap.
Finally I manually loaded the labels module, injected the Labels service, then used the Labels service to execute the aforementioned methods.
So my bootstrap script now looks like this:
(function () {
'use strict';
var injector = angular.injector( [ 'labels' ] );
var Labels = injector.get( 'Labels' );
/**
* Executes the actual bootstrapping
*/
function bootstrapApplication() {
angular.element( document ).ready( function () {
angular.bootstrap( document, [ 'myAppModule' ] );
});
}
// get the label files and build the labels constant, then load the app
Labels.fetchLabels( 'en_AU', '/lang/' ).then( bootstrapApplication );
})();
And I can properly unit test the Labels service discretely. The loading order and adding extra bits to the normal way of loading modules for us is an exception, but I'm comfortable that it's specific purpose warrants the exception, and it leaves us in a much more flexible position for testing.
Is it possible to do this:
define( function( require ){
var path = 'json!/app/pagelang/login';
var appLang = require(path),
instead of this:
define( function( require ){
var appLang = require('json!/app/pagelang/login'),
from my tests it's not possible because it results on the following console error:
Uncaught Error: Module name "json!/app/pagelang/login_unnormalized2" has not been loaded yet for context: _
Yes, you just have to change your syntax a little:
define( function( require ){
var path = 'json!/app/pagelang/login';
require([path], function(appLang){
// Do stuff with appLang…
});
});
The answer is actually "no", your second snippet uses sugar syntax which uses regular expressions to rewrite your code "behind the scenes" to be something like:
define(['json!/app/pagelang/login'], function (appLang) {
// appLang available
});
The same mechanism can't work when the module name is a variable because the dependencies block needs concrete module names, not variables. Because of that, as noted by #idbehold you need to use a proper asynchronous form of inlined require:
define(function (require) {
var path = 'json!/app/pagelang/login';
require([path], function (appLang) {
// appLang available
});
});
I am quite new to javascript and I am struggling with a simple problem. I have to split up codes into separate files. As an example I have a file called Database.js. In that file I have the following lines:
function Database(){
//someStuff
this.fetchAll = function(){
//some stuff
return something;
}
}
Now I want to use the Database.js code in the file app.js. So I write the following code in app.js:
var Database = require('Database');
var myDB = new Database();
var result = myDB.fetchAll();
However, I get the error Script Error = '[object Database]' is not a constructor (evaluating 'new Database()') at app.js (line 3).
What is my mistake?
Before you moving to the development, you need to understand thoroughly about CommonJS Modules in Titanium. Then it will be more simple for you. Also refer the require function
Let's come to your error. [ERROR] [object Database]' is not a constructor (evaluating 'new Database()') at app.js (line 3) means that the module you created is not constructor. Your constructor function might not return any value. Read simple usage of CommonJS module. I'm sure it will resolve your issue.
There is an alternative way, you can include your Database.js file in your app.js. You does not need to return anything and no need to use require function. You just need to use the include method. Just write Ti.include('Database.js'); inside your app.js and you can access all the global variables and functions inside the Database.js file
This question is old but it has not been answered yet. So i will just provide the answer for anyone who is visiting here.
You have to export you function as global. To do so you would declare it as below
exports.fetchAll = function Database(){
//some stuff
return something;
};
You can also declare the function so that it can be used globally as well as locally within the file
var fetchAll = function Database(){
//some stuff
return something;
};
exports.fetchAll = fetchAll;
Then assuming the file name is Database and it is in same folder as app.js, you can use it as below
var Database = require('Database');
var result = Database.fetchAll();
edit: This answer is javascript general and it's not oriented towards Appacelerator Titanium.
There is no such include or require in javascript. You can on the other hand do one of the following
Include a script tag before your script to include Database.js
<script type="text/javascript" src="Database.js" >
OR
Add it dynamically
function loadScript(url, callback)
{
// adding the script tag to the head as suggested before
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// then bind the event to the callback function
// there are several events for cross browser compatibility
script.onreadystatechange = callback;
script.onload = callback;
// fire the loading
head.appendChild(script);
}
The problem seemed to be the usage of the variable name 'Database'. Maybe there is somewhere a name collusion.
I am sorry that I did not know that the usage of require is not a basic concept of js.
Just a quick guess here. If you use CommonJS then you have to tell what should be available outside of the module. The way you lay out that you have made the Database "object" you would need to add:
module.exports = Database;
somewhere in your module. I always put them at the end - but not sure that is a requirement.
You can also make individual functions available outside of a module by specifying:
exports.getMyDatabase = getMyDatabase;
Where "getMyDatabase" is a function you have specified in the module. I use this way to "hide" certain implementation details of some functions from the outside and just make available the functions I want the developer to be able to call ;-)
/John
I think this is the right usage of require js:
require(["Database"], function() {
var myDB = new Database();
var result = myDB.fetchAll();
});
http://requirejs.org/docs/jquery.html
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to load bootstrapped models in Backbone.js while using AMD (require.js)
I am currently creating a RESTful API for one of our projects and also wanted to provide a Javascript library to access it.
Since I like the AMD principle and using require.js, I would provide an AMD module as well.
The problem is: the initialization of the module would require some information like the API key on initialization.
How do I pass such parameters into a module upon initalization?
If you have something like:
define(['dep1', 'dep2', 'dep3'], function (dep1, dep2, dep3) {
var module = {
...
};
return module;
});
change it to:
define(['dep1', 'dep2', 'dep3'], function (dep1, dep2, dep3) {
var module = {
...
};
var init = function (options) {
// Initialize here
return module;
};
return init;
});
Then after requiring your module somewhere, you can call it to initialize. You might also want to look into the factory pattern if you need something more complex and return the factory.
require.js does not restrict you in what you return. It can be a simple object, a string, a function...
I think what your looking for is the ability to set config variables that get picked up by the module. Here is an example using require.js
How to load bootstrapped models in Backbone.js while using AMD (require.js)
One other possibility that came to my mind is to use a serverside script to manipulate the source of the module when you are requesting it.
For example when you have to pass an API-key into the module, you do the following:
Before you do your first define() call, put the following code:
require.config({
paths: {
api: 'https://api.example.com/api.amd.js?api_key=f615ac61&'
}
});
This enables you to simply require your API from anywhere like this:
require(['api'], function(api){
});
So the server recieves the request - maps it thorugh mod_rewrite to some script, takes the GET parameter and puts it on the correct place in the module sourcecode, then returns the custom source.
Thats the way I solved this by now and it works like a charm, without the need to change any behaviour of the developers and it makes use of functionality thats already built into requirejs.
I don't think you can do that with require.js, but you can with Frame.js or some other module library. In Frame you would do that like this:
//moduleName.js
(function(exports){
exports.moduleName = function(args){
// do stuff
}
})(window.exports);
// in main js file
var exports = {}; // global variable
Frame('moduleName.js');
Frame(function(next){
var myArgs = { ... settings ... };
exports.moduleName(myArgs);
next();
});
Frame.init();
Is it possible to use a namespaced variable, and then to reference the appropriate object when you initialize the specific library? Maybe I don't understand exactly what you want require.js to do, but it looks like you call it from your main.js in any event, so I'm pretty sure it would work... I don't think you can do it like <script = "require.js?apiKey=jsdfhjkfklsjkfdjks">
var libData = {
apiKey: "jsdfhjkfklsjkfdjks",
otherpram: "userIDorsomething"
}
require(libData.apiKey);
but if you needed to send the apikey in the url parameter of the page, you could use a script like this to get the parameters:
<script>
function getQueryParams(qs) {
qs = qs.split("+").join(" ");
var params = {},
tokens,
re = /[?&]?([^=]+)=([^&]*)/g;
while (tokens = re.exec(qs)) {
params[decodeURIComponent(tokens[1])]
= decodeURIComponent(tokens[2]);
}
return params;
}
// assuming the page is loaded like page.html?apikey=jsdfhjkfklsjkfdjks
apiKey = getQueryParams(document.location.search).apiKey;
// however you have to call require, pass the api key?
</script>
I follow this pattern to organize my js application.
As that example says our application should has the single entry point. File application.js doing that work.
// Filename: application.js
var chat = {
// Create this closure to contain the cached modules
module: function() {
// Internal module cache.
var modules = {};
// Create a new module reference scaffold or load an
// existing module.
return function(name) {
// If this module has already been created, return it.
if (modules[name]) {
return modules[name];
}
// Create a module and save it under this name
return modules[name] = { Views: {} };
};
}()
};
// Using the jQuery ready event is excellent for ensuring all
// code has been downloaded and evaluated and is ready to be
// initialized. Treat this as your single entry point into the
// application.
jQuery(function($) {
$(document).ready(function(){
var foo = new Application.module('Chat').Collection();
});
});
// Filename: chat-module.js
(function(chat){
chat.Model = Backbone.Model.extend({ ... }),
chat.Collection = Backbone.Collection.extend({ ... }),
})(Application.module('Chat'));
It seems well but if try to define chat module for example and invoke it later I have the following error:
Uncaught TypeError: Property 'Collection' of object #<Object> is not a function
I think that error due jQuery ready invokes when chat-module.js not available yet.
How can I resolve that problem?
Your code creates an object and assigns it to the global variable chat, which has a module function as a property:
var chat = {
module: function...
};
...but then when you use it, you use Application.module rather than chat.module.
Application.module('Chat')
and
var foo = new Application.module('Chat').Collection();
It seems to me that your chat variable should be called Application.
Also note that you're using module in two different ways, both with new and without. Without would be the correct use based on your code. It will work both ways because module returns a function (which is an object), and so that will override the normal new behavior, but it means that using new serves no purpose and is misleading to someone reading the code.