How to integrate Requirejs, d3, and d3.slider module - javascript

This post is in reference to a previous question about NodeJS and requiring a module which injects a function. However, the previous question is in the context of Webpack. I too am trying to integrate d3.js and the d3.slider module, but using RequireJS.
According to the comment left by Nikos Paraskevopoulos a shim is needed. I have not successfully implemented the shim needed for the d3.slider module and was hoping someone could lead me in the right direction. Right now I have
require.config({
paths: {
"d3": "https://d3js.org/d3.v3.min",
"d3.slider": "lib/d3.slider"
},
shim: {
"d3.slider": {
"deps": ["d3"],
"exports": "d3"
}
}
});
require(['d3'], function(d3) {
console.log(d3.version);
d3.select("#time_slider").call(d3.slider());
});
This logs:
3.5.17
TypeError: d3.slider is not a function
I think my problem is in the shim, but I'm not quite sure. Any direction is appreciated.

When I look at the source code of d3.slider I see it calls define. So you do not need a shim for it.
Also, you are not loading it. You should do this:
require(['d3', 'd3.slider'], function (d3) {
console.log(d3.version);
d3.select("#time_slider").call(d3.slider());
});
In the source I see that it installs itself on d3. So you do not need to add a parameter to your anonymous function: once loaded it will be available on the d3 object.

Related

requirejs dependencies load order doesn't work

I have such a code:
requirejs.config({
urlArgs: "bust=" + (new Date()).getTime(),
paths: {
mods: 'default',
myFriend: 'myFriend',
myCoworker: 'myCoworker'
},
shim: {
mods: ['myFriend', 'myCoworker']
}
});
require(['mods'], function (mods) {
// something to do
});
and modules which are the dependencies:
myFriend.js
var mess = `<a really huge text, almost 200 Kbytes>`
console.log('This code is ran in the myFriend module...', {mess:mess});
myCoworker.js
console.log('This code is ran in the myCoworker module...');
var wrk = {
name: 'John'
};
So I hope, that accordingly to shim is should always load myFriend.js (that is checked by console.output) before myCoworker.js. But it doesn't. The console output shows:
This code is run in the myCoworker module...
and then
This code is run in the myFriend module...
Probably I have missed something, but what?
The entire code is here: http://embed.plnkr.co/zjQhBdOJCgg8QuPZ5Q8A/
Your dealing with a fundamental misconception in how RequireJS works. We use shim for files that do not call define. Using shim makes it so that RequireJS will, so to speak, add a kind of "virtual define" to those files. The shim you show is equivalent to:
define(['myFriend', 'myCoworker'], function (...) {...});
The dependency list passed to a define or require call does not, in and of itself, specifies a loading order among the modules listed in the dependency list. The only thing the dependency list does is specify that the modules in the list must be loaded before calling the callback. That's all.
If you want myFriend to load first, you need to make myCoworker dependent on it:
shim: {
mods: ['myFriend', 'myCoworker'],
myCoworker: ['myFriend'],
}
By the way, shim is really meant to be used for code you do not control. For your own code you should be using define in your code instead of setting a shim in the configuration.

RequireJS JQuery ContextMenu issues

I'm working on an HTML5 page whose Javascript is powered by RequireJS. I've defined many dependencies using RequireJS, even ones that do not support AMD, with success (I mention this to illustrate that my RequireJS config is mostly functional). I have run into an issue with one particular dependency, however.
I'm trying to get Medialize's JQuery ContextMenu Plugin working.
The relevant parts (or, at least, the parts I believe to be relevant) of my RequireJS config are:
require.config({
paths: {
'jquery': "jQuery/jquery-latest", //jQuery 1.10.2
'jquery-ui': "jQuery/jquery-ui-1.10.3",
'jquery-contextmenu': "jQuery/jquery.contextmenu.r2.packed",
...
},
shim: {
"jquery-ui": ["jquery"],
"jquery-contextmenu": ["jquery"],
...
}
});
Then, in my code, I'm doing:
define(["jquery", "jquery-contextmenu"], function ($) {
$(document).ready(function () {
$.contextMenu({
selector: 'a',
items: {
"edit": {name: "Edit"}
}
});
});
});
So, the idea would be that any time an "a" tag got right-clicked, a context menu should pop out with one option, Edit.
Instead, Before I click anything, I get the error Uncaught TypeError: $.contextMenu is not a function which, to me, sounds like the contextMenu isn't being loaded correctly by/for RequireJS...but I'm not sure how to fix it.
Any assistance is appreciated
EDIT: Added a Plunker, but it's not working very well. I'm getting some timeouts and RequireJS script errors. Not sure why.
The errors you got in your Plunker were due to slapping ".js" at the end of your paths. Don't do this. (You did not do this in the code you show in the question but introduced this problem in your plunker.) You also did what this answer suggested, which was bad advice, because with the shim you are using for it jquery-contextmenu returns undefined for a module value. So assigning it to $ makes $ undefined.
Once I edit those issues out of your plunker (which I forked), the error in your question here does not happen.

Using OpenLayers with RequireJS and AngularJS

I'm trying to get an app running that uses both AngularJS and RequireJS. I'm having problems getting my OpenLayers lib to work in this setup.
I set the main AMD-modules in the main.js:
require.config(
{
baseUrl: 'scripts',
paths: {
// Vendor modules
angular: 'vendor/angular/angular',
openLayers: 'vendor/openlayers-debug',
other modules.....
},
shim: {
angular: {
exports: 'angular'
},
openLayers: {
exports: 'OpenLayers'
},
other modules....
}
}
);
require(['openLayers',
'angular',
'app',
'controllers/olMapController',
'directives/olMap',
other modules...
], function(OpenLayers) {
return OpenLayers;
}
);
Then in the angular controller I use for the initialisation of OpenLayers, I try to indicate that openlayers-debug.js is a dependency:
define(['openLayers'],
function(OpenLayers) {
controllers.controller('olMapController', ['$scope', function(scope) {
console.log('Loaded olMapController. OpenLayers version: ' + OpenLayers.VERSION_NUMBER);
}]);
}
);
Well, this doesn't work. SOMETIMES the olMapController function is executed, but mostly not. The console then just displays an error stating:
Error: [ng:areq] Argument 'olMapController' is not a function, got undefined
So, I think OpenLayers hasn't finished loading yet, but somehow require thinks it has and continues loading code that depends on OpenLayers, in this case the olMapController. It then can't find its dependency, whereupon Angular returns this error message. Or something like that...? Sometimes something happens that makes OpenLayers load fast enought for it to be present when it is loaded as a dependency. What that is, I can't tell.
I left out other libraries and modules require and define to keep the code readable. I hope the example is still understandable.
Any ideas on what I could do to get openlayers to load well? The error message disappears when I leave the ['openLayers'] dependency out of olMapController.
Thanks in advance for any help.
Best regards,
Martijn Senden
Well, just for reference my final solution. The comment by angabriel set me off in the right direction.
Like i said, I'm using the domReady module provided by RequireJS to bootstrap Angular. This is still being called to early, because OpenLayers isn't loaded yet when angular starts. RequireJS also provides a callback property in require.config. This is a function that is triggered when all the dependencies are loaded. So I used that function to require the angular bootstrap module. My config now looks like this:
require.config(
{
baseUrl: 'scripts',
paths: {
// Vendor modules
angular: 'vendor/angular/angular',
domReady: 'vendor/domReady',
openLayers: 'vendor/openlayers-debug',
etcetera....
},
shim: {
angular: {
deps: ['jquery'],
exports: 'angular'
},
openLayers: {
exports: 'OpenLayers'
},
},
deps: ['angular',
'openLayers',
'app',
'domReady',
'controllers/rootController',
'controllers/olMapController',
'directives/olMap'
],
callback: function() {
require(['bootstrap']);
}
}
);
And the bootstrap module looks like this:
define(['angular', 'domReady', 'app'], function(angular, domReady) {
domReady(function() {
angular.bootstrap(document, ['GRVP']);
});
});
Thanks for the help. #angabriel: I upvoted your comment. It's not possible to accept a comment as an answer, is it? Your initial answer wasn't really the answer to my question, but the comment helped a lot...
Regards, Martijn
Sorry this answer will only contain text as your code is too big for a small example.
I would suggest to write a directive that utilizes head.js to load libraries you need at a specific context. One could also think of a directive that initializes openLayers this way.
I guess your error is a timing problem, because the require.js and angular.js module loading gets out of sync - more precisely there seems to be no sync at all between them.
update
To repeat my comment which lastly helped to lead the OP in the right direction:
You have to decide which framework gives the tone. If you go with requireJS, then require everything and bootstrap angular manually. (Remove ng-app="" from index.html) and do `angular.bootstrap()ยด when requirejs has completed. So the problem most likely is, that angular starts too early.

Adding RequireJS module that uses jquery on a page that already has jquery as a global

I have an add-on to an application (call it appX) that allows users to create their own customizations using javascript, css and appX's webservices api.
Usually customizations are small and do not involve a lot of external libraries/plugins but when they do have external libs the typical users' library of choice is jQuery.
In the next version of appX they are using jQuery natively which I know is going to break some of the customizations.
So I have a need to modularize this situation. I have some other problems that are coming up and RequireJS seems like a good solution to these issues. I just need to figure out how to apply RequireJS properly for this situation
In my POC I'm loading require.js as follows:
<!--A bunch of other script including jQuery (but not require) are loaded already -->
<script type="text/javascript" src="/custom/js/require.js"></script>
<script type="text/javascript" src="/custom/js/dostuff.js"></script>
We'll call the jQuery loaded with appX jqueryx and the one I want to load jqueryp (p for private)
jQuery utilizes AMD and by default uses this definition internally:
define( "jquery", [], function () { return jQuery; } );
But in this case RequireJS is loaded AFTER jQuery (jqueryx) so there will be no default 'jquery' definition correct?
Some more background before I show you my problem... the file structure is like this:
appx
/js:
jqueryx.js
other.js
appx
/custom/js:
jqueryp.js
dostuff.js
Looking at the RequireJS api it seems that I should be doing something like this:
require.config({
baseUrl : 'custom/js',
paths : { 'jquery' : 'jqueryp'},
map: {
'*': { 'jquery': 'jquery-private' },
'jquery-private': { 'jquery': 'jquery' }
}
});
define(['jquery'], function (jq) {
return jq.noConflict( true );
});
require(['jquery'], function(jq){
console.log(jq.fn.jquery);
});
But when I do this I get an error:
Mismatched anonymous define() module: function (jq)...
I've played around with switching references to jquery, jquery-private as it's kind of confusing but with no progress.
How should I be applying RequireJS to this situation?
Almost a year late but better than no answer at all...
The following part should be moved into a "jquery-private.js" file:
define(['jquery'], function (jq) {
return jq.noConflict( true );
});
You can't define a module in your main entry point. Even if you could, the module has no name so how would you reference it?

Loading Highcharts via shim using RequireJS and maintaining jQuery dependency

I'm attempting to load the Highcharts library using a shim in RequireJS. However, when Highcharts loads, it throws an exception because it can't access the jQuery methods it depends on.
The require config looks like so:
require.config({
baseUrl: "js",
shim: {
'libs/highcharts/highcharts.src.js': {
deps: ['jquery'],
exports: function(jQuery)
{
this.HighchartsAdapter = jQuery;
return this.Highcharts;
}
}
}
});
The exception that is thrown is:
Uncaught TypeError: undefined is not a function
and is in regards to this line:
dataLabels: merge(defaultLabelOptions, {
The issue is the merge call, which eventually maps itself back to jQuery (or some other adapter that Highcharts supports; but I'm just using jQuery).
I'm not sure exactly how to make sure Highcharts gets access to jQuery using RequireJS and shim.
Has anyone used RequireJS and Highcharts together before? I guess the issue isn't specific to highcharts, but any library that has other sorts of dependencies.
Thanks in advance for any advice or points to the correct direction!
To add further context, in hopes that someone who is familiar with require.js or shims will be able to help without having to be too intimately familiar with highcharts, here's some source that sets up this merge method in Highcharts
var globalAdapter = win.HighchartsAdapter,
adapter = globalAdapter || {},
// Utility functions. If the HighchartsAdapter is not defined,
// adapter is an empty object
// and all the utility functions will be null. In that case they are
// populated by the
// default adapters below.
// {snipped code}
merge = adapter.merge
// {snipped code}
if (!globalAdapter && win.jQuery) {
var jQ = win.jQuery;
// {snipped code}
merge = function () {
var args = arguments;
return jQ.extend(true, null, args[0], args[1], args[2], args[3]);
};
// {snipped code}
}
The win object is a reference set up to window at the beginning of the script. So, I thought adding window.jQuery = jQuery; to the export method on the shim would result in highcharts picking up the jQuery reference; but it didn't.
Again, any insight, info, advice, or heckles would be appreciated at this point - I'm at a complete loss, and starting to question whether trying to implement and AMD package system in browser javascript is even worth it.
After accepting the answer from pabera below I thought it appropriate to update my question to reflect how his answer helped my solution (though, it's basically his answer).
RequireJS uses "paths" to find libs that aren't "AMD" supported and loads them on your page. the "shim" object allows you to define dependencies for the libraries defined in paths. The dependencies must be loaded before requirejs will try to load the dependent script.
The exports property provides a mechanism to tell requirejs how to determine if the library is loaded. For core libs like jquery, backbone, socketio, etc they all export some window level variable (Backbone, io, jQuery and $, etc). You simply provide that variable name as the exports property, and requirejs will be able to determine when the lib is loaded.
Once your definitions are done, you can use requirejs' define function as expected.
Here's my example require.config object:
require.config({
baseUrl: "/js/",
paths: {
jquery: 'jquery',
socketio: 'http://localhost:8000/socket.io/socket.io', //for loading the socket.io client library
highcharts: 'libs/highcharts/highcharts.src',
underscore: 'libs/underscore',
backbone: 'libs/backbone'
},
shim: {
jquery: {
exports: 'jQuery'
},
socketio: {
exports: 'io'
},
underscore: {
exports: '_'
},
backbone: {
deps: ['jquery', 'underscore'],
exports: 'Backbone'
},
highcharts: {
deps: ['jquery'],
exports: 'Highcharts'
}
}
});
As pabera mentioned before, this is for Require.JS version 2.0.1.
I hope someone gets some use out of this; I know it road blocked me for a little while; so hopefully we kept you from banging your head into the same spot in the wall that we did, by posting this.
I had the exact same problem and I was struggling around many hours until I saw your entry here. Then I started over from scratch and now it works for me at least.
requirejs.config({
baseUrl:'/js/',
paths:{
jquery:'vendor/jquery',
handlebars: 'vendor/handlebars',
text: 'vendor/require-text',
chaplin:'vendor/chaplin',
underscore:'vendor/underscore',
backbone:'vendor/backbone',
highcharts: 'vendor/highcharts'
},
shim: {
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
underscore: {
exports: '_'
},
highcharts: {
exports: 'Highcharts'
}
},
});
Since I use Chaplin on top of Backbone, I am including some more files in my paths attribute. Highcharts has a similar structure to Backbone so I thought I could load it the same way. It works for me now. As you can see, I am introducing highcharts in the paths attribute already to export it as a shim afterwords.
Maybe this helps, otherwise let's try to contribute on it even more to solve your problem.
Although jQuery can be used as an AMD module it will still export itself to the window anyway so any scripts depending on the global jQuery or $ will still work as long as jQuery has loaded first.
Have you tried setting a path? jQuery is an interesting one because although you're encoruaged not to name your modules by the RequireJS documentation, jQuery actually does.
From the jQuery source
if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
define( "jquery", [], function () { return jQuery; } );
}
What that means is you will need to tell RequireJS where to find 'jquery'. So:
require.config({
paths: {
'jquery': 'path/to/jquery'
}
});
If you're interested in why jQuery registers itself this way then there is a pretty large comment in the source which goes into more detail

Categories

Resources