I'm new to Javascript and I'm having troubles understanding the following piece of code. I have read this post (https://stackoverflow.com/a/60669635/9867856) which suggests that mifosXComponents.js and mifosXStyles.js are being passed as arguments into the function function(componentsInit){...}, but isn't componentsInit a single function that returns a promise? How come two .js files are converted into a function? I'm confused.
require(['mifosXComponents.js', 'mifosXStyles.js'], function (componentsInit) {
componentsInit().then(function(){
require(['test/testInitializer'], function (testMode) {
if (!testMode) {
angular.bootstrap(document, ['MifosX_Application']);
}
});
});
});
If you require two modules (as per example) then RequireJS will:
load them async;
load their dependencies;
inject the modules to you callback, each as separate argument.
So you have a mistake in your code, your callback will receive actually two arguments, so you need to have two parameters:
// require two modules async,
// when they are loaded,
// they are injected to your callback
require(['mifosXComponents.js', 'mifosXStyles.js'], function (mifosXComponents, mifosXStyles) {
// now you can use both modules,
// seems that first one is a function which returns promise,
// but I have no idea what is the second one :)
mifosXComponents().then(function(){
require(['test/testInitializer'], function (testMode) {
if (!testMode) {
angular.bootstrap(document, ['MifosX_Application']);
}
});
});
});
Related
I am trying to understand this piece of code
require(['mifosXComponents'], function (componentsInit) {
componentsInit().then(function(){
require(['test/testInitializer'], function (testMode) {
if (!testMode) {
angular.bootstrap(document, ['MifosX_Application']);
}
});
});
});
The code is at mifosX client code. I believe this is the entry point of the mifosX web client software. I am really confused by the require syntax here. All the online sample code I have seen is like require(["a", "b"], function (a, b){});. In the other words, the parameter list inside the function() are all listed inside the dependence [] right before it. However the code I pasted above has componentsInit inside the function(). And I could not find any place in the source code tree that componentsInit gets defined.....
What I am trying here is to understand the code logic flow of mifosX. I am new to Javascript and RequireJS. Please help me understand this if you know what's going on here. Thanks in advance!
Here is your code with some comments which will clarify:
// in the first line you are requiring a module with id `mifosXComponents`
// which then is passed to the callback as `componentsInit`
require(['mifosXComponents'], function (componentsInit) {
// seems that `componentsInit` is a function which returns a Promise object,
// so your are passing a callback to it to execute it after its fulfilment
componentsInit().then(function(){
// when the promise is fulfilled, you are requiring another module
// with id `test/testInitializer` which is passed to callback as `testMode`
require(['test/testInitializer'], function (testMode) {
// next lines are pretty simple to understand :)
if (!testMode) {
angular.bootstrap(document, ['MifosX_Application']);
}
});
});
});
About Promise you can read here: What does the function then() mean in JavaScript?
I'm trying to convert our requirejs calls to use SystemJS, but I'm not exactly sure what I'm doing wrong.
Our original calls look like this:
return function(callback) {
requirejs(["/app/shared.js"], function(result){
callbackFunction = callback;
callback(dashboard);
main();
})
}
And what I'm trying instead is:
return function(callback) {
console.log(callback.toString())
SystemJS.import('app/shared.js').then(function(result){
callbackFunction = callback;
callback(dashboard);
main();
});
}
I've had to remove some leading / to get things to load properly, which is fine, but I've now ran into an issue where variables that were defined at the top of shared.js aren't visible in my local main.js file. In my browser console I get:
Potentially unhandled rejection [1] ReferenceError: dashboard is not defined
shared.js defines dashboard:
var dashboard = { rows: [], }
// Other definitions...
define(["/app/custom-config.js", /* etc */]);
I guess I have two questions:
is this the correct way to replace requirejs calls?
if so, why aren't my variables from shared.js accessible?
For a fuller picture, main() just sets up the dashboard object, and then calls callbackFunction(dashboard) on it.
Your problem can be reduced to the following case where you have two AMD modules, with one that leaks into the global space, and the 2nd one that tries to use what the first one leaked. Like the two following modules.
src/a.js requires the module that leaks and depends on what that module leaks:
define(["./b"], function () {
console.log("a loaded");
callback();
});
src/b.js leaks into the global space:
// This leaks `callback` into the global space.
var callback = function () {
console.log("callback called");
}
define(["./b"], function () {
console.log("b loaded");
});
With RequireJS, the code above will work. Oh, it is badly designed because b.js should not leak into the global space, but it will work. You'll see callback called on the console.
With SystemJS, the code above won't work. Why? RequireJS loads modules by adding a script element to the header and lets script execute the module's code so callback does end up in the global space in exactly the same way it would if you had written your own script element with an src attribute that points to your script. (You'd get an "Mismatched anonymous define" error, but that's a separate issue that need not detain us here.) SystemJS, by default, uses eval rather than create script elements, and this changes how the code is evaluated. Usually, it does not matter, but sometimes it does. In the case at hand here callback does not end up in the global space, and module a fails.
Ultimately, your AMD modules should be written so that they don't use the global space to pass information from one another.
However, there is another solution which may be useful as a stepping-stone towards a final solution. You can use scriptLoad: true to tell SystemJS to use script elements like RequirejS does. (See the documentation on meta for details and caveats.) Here is a configuration that does that:
System.config({
baseURL: "src",
meta: {
"*": {
scriptLoad: true, // This is what fixes the issue.
}
},
packages: {
// Yes, this empty package does something. It makes `.js` the
// default extension for modules.
"": {}
},
});
// We have to put `define` in the global space to
// so that our modules can find it.
window.define = System.amdDefine;
If I run the example code I've given here without scriptLoad: true, then module a cannot call the callback. With scriptLoad: true, it can call the callback and I get on the console:
b loaded
a loaded
callback called
I'm a strange behavior with RequireJS using the CommonJS syntax. I'll try to explain as better as possible the context I'm working on.
I have a JS file, called Controller.js, that registers for input events (a click) and uses a series of if statement to perform the correct action. A typical if statement block can be the following.
if(something) {
// RequireJS syntax here
} else if(other) { // ...
To implement the RequireJS syntax I tried two different patterns. The first one is the following. This is the standard way to load modules.
if(something) {
require(['CompositeView'], function(CompositeView) {
// using CompositeView here...
});
} else if(other) { // ...
The second, instead, uses the CommonJS syntax like
if(something) {
var CompositeView = require('CompositeView');
// using CompositeView here...
} else if(other) { // ...
Both pattern works as expected but I've noticed a strange behavior through Firebug (the same happens with Chrome tool). In particular, using the second one, the CompositeView file is already downloaded even if I haven't follow the branch that manages the specific action in response to something condition. On the contrary, with the first solution the file is downloaded when requested.
Am I missing something? Is it due to variable hoisting?
This is a limitation of the support for CommonJS-style require. The documentation explains that something like this:
define(function (require) {
var dependency1 = require('dependency1'),
dependency2 = require('dependency2');
return function () {};
});
is translated by RequireJS to:
define(['require', 'dependency1', 'dependency2'], function (require) {
var dependency1 = require('dependency1'),
dependency2 = require('dependency2');
return function () {};
});
Note how the arguments to the 2 require calls become part of the array passed to define.
What you say you observed is consistent with RequireJS reaching inside the if and pulling the required module up to the define so that it is always loaded even if the branch is not taken. The only way to prevents RequireJS from always loading your module is what you've already discovered: you have to use require with a callback.
I have an external API which provides a script file with javascript callback function in it. It assumes the function is implemented in my code.
eg a JS file with the following content:
aCallback({json:'stuff'});
I would like to wrap this in a requireJS module but am not too sure how to go about it.
I have tried the following shim:
define("my-wrapper", [], function () {
return function(data){ console.log(data); }
}
);
var require = {
shim: {
"my-wrapper": {exports: "aCallback"},
"http://api.con/service": ["my-wrapper"]
}
};
require(["http://api.con/service"], function (service) {});
but it says when it try's to load the service that aCallback is undefined. What have I got wrong? Is there a better way to wrap this kind of script?
You might want to try requiring the callback as a dependency instead of using shim so that it does exist in the same scope.
require(["http://api.con/service", "my-wrapper"], function (service, aCallback) {
});
It does depend on how the service expects to consume the callback though.
I read on ICanHaz.js documentation that i should load templates from a remote like this
$.getJSON('/myserver/templates.json', function (templates) {
$.each(templates, function (template) {
ich.addTemplate(template.name, template.template);
});
});
I have no idea how the json template should look like, would really appreciate an example ICanHaz.js json template.
Thanks
To save some time on debugging $.each requires two arguments to the callback function: iterator and actual object
$.getJSON('/myserver/templates.json', function (templates) {
$.each(templates, function (id, template) {
ich.addTemplate(template.name, template.template);
});
});
Of course you must remember to set promise since these templates are loaded in async mode.