RequireJS - using module returns undefined - javascript

I'm trying to use RequireJS in my app. I'm including the requirejs script from cdnjs like this:
<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script>
on my page I have a button and I register an event for it:
$('#btnSpeedTest').on('click', function (e) {
require([baseUrl + 'Content/js/tools/speedtest.js'], function (speedTestModule) {
alert(speedTestModule);
});
});
If I watch with Fidler - I see that upon clicking the button speedtest.js is loaded.
speedtest.js contains the following:
define('speedTestModule', function () {
function SpeedTest(settings, startNow) {
// basic initialization
}
var fn = SpeedTest.prototype;
fn.startRequest = function (download, twoRequests) {
// logic
}
return SpeedTest;
});
The alert(speedTestModule); command returns "undefined". I saw a tutorial on RequireJS and in that tutorial everything was in the same directory as well as files with names of modules (which is not my case since I'm loading it from CDN).
I even tried to return a simple string, but it did not work. What am I missing?
Thanks

Don't use a named define. Instead of this:
define('speedTestModule', function () {
do this:
define(function () {
and let RequireJS name your module. You typically want to let r.js add names to your modules when you optimize them. There are a few cases where using names yourself in a define call is warranted but these are really special cases.

Related

Magento 2: How to call js Function that is in my Require.js file from phtml file

My main issue here is when using require.js my function is no longer Global. So when I call it from my phtml file it is not being found. Any idea what the correct way to make a function inside my js file global? I've tried multiple methods/answers I found online but nothing seems to be working out. Any suggestions?
Here is my js file
define([
'jquery'
], function ($) {
return function (config) {
console.log(config);
}
function initMap() {
console.log('initMap is being called');
}
});
My requirejs-config.js file:
var config = {
map: {
'*': {
'gslMap': ['Gauge_StoreLocator/js/app']
}
}
};
My phtml file: The callback function "initMap" is being called at end
<script async defer src="https://maps.googleapis.com/maps/api/js?key=<?php echo $this->getGoogleApi(); ?>&callback=initMap">
If you must make your initMap function global, you can do it by deliberately leaking it into the global space:
define([
'jquery'
], function ($) {
return function (config) {
console.log(config);
}
function initMap() {
console.log('initMap is being called');
}
// Deliberately leak initMap into the global space.
window.initMap = initMap;
});
Note, however that RequireJS is always operating asynchronously when used in the browser. So if you just plop your script tag somewhere and hope for the best, you're going to run into trouble. If it is added dynamically by code that loads you module with initMap first, then you'll be fine.
Note that map does not take arrays. paths on the other hand does accept arrays as values but I'm not seeing the point of an array of just one element. (Arrays are meant to provide fallbacks.) The reason RequireJS does not fail loudly due to the array you give in your map is that in JavaScript ["foo"].toString() === "foo" and there is an implicit call to .toString() in the code that processes the values of map so RequireJS sees your array in the same way as if you had just put the single string it contains instead of the array. If you try with an array of more than one element, you'll get into trouble.

Accessing variable from different files(module) using requirejs

I am trying to make MVC structure of application in canjs. For that I am using requireJS to separate the code in different file.
I have searched in google and i am following this tutorial but in that tutorail I dont find to access module variables in different modules. therefore I am following this method to do so.
But I cannot achieve that.
This is my code:
requirejsconfig.js file :
requirejs.config({
paths :{
enforceDefine: true,
waitSeconds : 0,
jquery : "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min",
main : "view/main",
player : "view/player",
PlayerModel : "/models/PlayerModel",
hbs : "/models/view/js/handlebars",
fixture : "/models/view/js/can.fixture",
can : "/models/view/js/can.jquery"
}
});
main.js :
require(["player"],function(player){
player.PlayerModel();
});
I want to use that model methods in my controller.
player.js :
define(['PlayerModel'],function(){
function PlayerModel(){
var Player = PlayerModel.Player;
Players =can.Control({ defaults :{view:view/players.hbs' }},{
init: function(){
this.element.html(can.view(this.options.view, {
players: this.options.players
}));
}
$(document).ready(function(){
$.when(Player.findAll()).then(
function(playersResponse){
var players = playersResponse[0];
new Players('.players', {
players: players
});
});
});
}
});
PlayerModel.js:
define(function(){
var Player = can.Model({
findAll: 'GET /models/players.json',
findOne: 'GET /players.json/{id}'
});
return {
Player:Player
}
});
Every file is being loaded (saw in network tab-chrome devtools) but nothing is being populated in output.
Can anybody help me ?
Thanks in advance!
Carrying on with what #ekuusela said, restructure the code in Player.js in this format:
define(['PlayerModel'],function(){
function PlayerModel(){ ... }
return {
PlayerModel: PlayerModel
}
});
What's happening
Internally, two conventions are followed when defining modules. These relate to:
What the module is called (its label)
What this label represents.
Labeling Modules
The filename is taken as the module's name (unless shim is used, like you have). In other words, the define(['Module_Name'] ...), which is how I would normally read that line, can more accurately be read as a define(['Module_Path_Or_Shim_Symbol_Name' ...)
What Is This 'Module' Anyway
A module isn't magic - it is just a specially labeled map to a function. This map is maintained by RequireJS and probably looks similar to this:
var ModuleMap = {
'Player' : function (...) { ... },
'PlayerModel' : function (...) { ... }
};
Every time a module is accessed, through a require or define call, this map is accessed, and the relevant function found. However, that isn't enough - what we want is the stuff that is defined within the function - the fundamental concept of modules is that everything inside them has Module Function Scope, and is not exposed outside. So, to gain access to this "stuff", the RequireJS brain does the only thing it can do with a function - execute it.
var playerReference = require('Player');
Note that I've used the CommonJS notation of requiring modules, which is more readable for our current purpose.
So, in the code you posted, the module function has defined and declared PlayerModel as a function, but has not exposed it. Since the line player.PlayerModel() expects the module to return an object with a property named PlayerModel that refers to your function, the logical return value of the module is:
var exposedModuleReference = { PlayerModel: PlayerModel };
return exposedModuleReference;
Note that this means the name with which the function is exposed can be different from the function name itself. For example, the following code will also work without any changes anywhere else:
define(['PlayerModel'],function(){
function PlayerModelConstructor(){ ... }
return {
PlayerModel: PlayerModelConstructor
}
});
An Interesting Addition
So, executing a module function and assigning that return value to a reference is one part of what RequireJS's brain does. The other part is, it then updates this map so it now looks like this:
var ModuleMap = {
'Player' : { PlayerModel: PlayerModelConstructor },
'PlayerModel' : function (...) { ... }
};
This means that code written in module functions gets executed at most one time.
You define the function PlayerModel inside player.js and then require a module called PlayerModel there but don't assign the required module to any variable. You should first clean up your code, possibly rename some of your modules and move functions around.
Here, you try to access the function PlayerModel in the module player, but the module factory function in player.js doesn't return anything:
require(["player"],function(player){
player.PlayerModel();
});
What gets assigned to the function parameter player is only whatever you return from the function that defines the module. (If you would define a module as an object then that object would be the argument.)

How to implement a plugin, that modifies the original module only when required?

I have a plugin extending an original module.
It should only modify the module, when explicitly required.
Problem:
As soon as it is required once, the original module is modified forever, also for cases where the plugin is not a dependency.
The order doesn't matter here, it's enough to require the plugin once.
Example:
define("main", [], function() {
return {opt: "A"};
});
define("plugin", ["main"], function(obj) {
obj.opt = "B";
});
require(["main", "plugin"], function(obj) {
console.log(obj.opt); // should log B
});
require(["main"], function(obj) {
console.log(obj.opt); // should log A but logs B
});
I guess the way to go is to somehow tell require to always reload main from source instead of using the cached version.
I have no idea how, though.
Or maybe there's an even more elegant way?
Please enlighten me, guys.
Fiddle: http://jsfiddle.net/r75e446f
UPDATE: Some might find it important to know that I need this for my karma unit test environment to test a module with and without the plugin.
UPDATE2: Look below for my own solution.
RequireJS modules are singletons. If you load main once, twice, 10 times, you are always going to get the same module. And so if you modify its state, it is modified for all modules that use it. It is possible to tell RequireJS to undefine the module but I do not recommend it as it will just make your code obscure.
If I wanted to do what you are trying to do I'd design my code something like this:
<script>
define("main", [], function() {
function Main (opt) {
this.opt = opt;
}
return Main;
});
define("plugin1", [], function() {
return {
install: function (main) {
main.opt += " plugin1";
}
};
});
define("plugin2", [], function() {
return {
install: function (main) {
main.opt += " plugin2";
}
};
});
// Case 1: no plugins
require(["main"], function(Main) {
var main = new Main("A");
console.log(main.opt);
});
// Case 2: only plugin1
require(["plugin1", "main"], function (plugin1, Main) {
var main = new Main("A");
plugin1.install(main);
console.log(main.opt);
});
// Case 3: only plugin2
require(["plugin2", "main"], function (plugin2, Main) {
var main = new Main("A");
plugin2.install(main);
console.log(main.opt);
});
// Case 4: plugin1 and plugin2
require(["plugin1", "plugin2", "main"], function (plugin1, plugin2,
Main) {
var main = new Main("A");
plugin1.install(main);
plugin2.install(main);
console.log(main.opt);
});
Basically, make what is common to all cases a Main class which can be initialized at construction and which can be modified by plugins. Then each plugin can install itself on Main. The code above is a minimal illustration of how it could be done. In a real project, the final solution would have to be designed to take into account the specific needs of the project.
If you don't want the original module to be modified for all modules which use it, then your plugin should not modify the original module. Instead, have the plugin return a modified copy of the original module instead.
define("main", [], function() {
return {opt: "A"};
});
define("plugin", ["main"], function(obj) {
var decorator = {}
for (var key in obj) { decorator[key] = obj[key];}
decorator.opt = "B";
return decorator
});
require(["main", "plugin"], function(obj, plugin) {
console.log(plugin.opt); // should log B
});
require(["main"], function(obj) {
console.log(obj.opt); // should log A but logs B
});
This will work without any complications if your original object is a simple struct-like object without any functions. If there are functions, or if your original object was constructed using the Module Pattern, then there is a strong possibility of subtle errors in the copy, depending on how the methods were defined.
EDIT 2015-01-13: The OP clarified his question that he would like a way for his tests to be able to run both modified and unmodified original module without having to reload the page. In that case, I would recommend using require.undef to unload the main module and then reload it without having to reload the entire page.
I would like to bring up my understanding for discussion.. when we AMD, we define the module. Unless the module (in this case is main, the defined source) is able to accepting the plugin and allow the plugin to change the properties, i guess we're not able to hijack it or it will be an anti-pattern?
what about we extend/clone the defined source, like
define("plugin", ["main"], function(obj) {
return $.extend(true, {}, obj, {opt: "B"});
});
http://jsfiddle.net/r75e446f/6/
here the plugin module is always using the main module as its dependency, then when using the module we just directly use the plugin module and no longer need to require the main module? (by the way i understand this defeat the definition of 'plugin', but my direction is that we're dealing with the module as what the requireJs designed to be)
--2nd approach--
if you do really want to do it the plugin way, how about the loader plugin? like the text plugin we always using `require('text!abc.json'). So write a loader and register it to the requireJs's config, and then we could use it. (more)
So I found out how to achieve, what I want and thought I'd share it here.
The answer is called 'context', which is an option in the requirejs config.
http://requirejs.org/docs/api.html#multiversion
Here's how I implemented my solution:
var reqOne = require.config({
context: 'one'
});
var reqTwo = require.config({
context: 'two'
});
reqOne(["main", "plugin"], function(obj) {
console.log(obj.opt); // logs B
});
reqTwo(["main"], function(obj) {
console.log(obj.opt); // logs A
});
Unfortunately this doesn't work in the fiddle, because the second require will try to load the main module externally and I can't upload files to jsfiddle.
But the mere fact, that he tries to do that and doesn't use the 'main' module already loaded in the other require, should be proof that his method works.
If the definitions are outsourced to single files this works like a charm.
Thanks for everybody who chimed in.
A more elegant solution would be to take an object-oriented approach, where:
the modules return constructors rather than instances, and
plugin can then be a subclass of main.
This is the implementation (fiddle):
console.clear();
define("Main", [], function() {
return function() { this.opt = "A"; };
});
define("Plugin", ["Main"], function(Main) {
return function() {
Main.call(this);
this.opt = "B";
};
});
require(["Plugin"], function(Plugin) {
console.log((new Plugin()).opt); // should log B
});
require(["Main"], function(Main) {
console.log((new Main()).opt); // should log A
});

Visual Studio Intellisense methods with underscore don't appear

I'm using VS2012, and one of my project-wide Javascript function namespaces has all of its exposed methods beginning with underscores _, for example:
var NameSpace = {
_aMethod = function () { },
_anotherMethod = function () { }
};
I created a quick vsdoc file for the namespace, and the namespace itself appears, but none of the methods do. NOTE: If I remove the _ at the beginning of the methods, it works like a charm.
// This would work, and show up in the VSDOC
var NameSpace = {
aMethod = function () { },
anotherMethod = function () { }
// ^ notice no underscores
};
Is there anyway around this?
Going through the entire project and renaming them (even with a find-all) would be risky since these methods are so intertwined with everything.
If you go into Tools->Options->Text Editor->JavaScript->IntelliSense->References there should be a drop down for the reference group (depending on what type of project you may need to change this)
Once you have the right group you'll noticed there are some default included intellisense reference files. Try removing the underscorefilter.js

RequireJS - pass parameters into module for initialization [duplicate]

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>

Categories