I'm trying to use the Shipping Time JS plugin on my Magento 2 website, it requires both moment.js and jQuery in order to work however it's not working. I'm getting a ReferenceError: moment is not defined in shiptime.js on line 49 which is the following:
try {
if (moment === undefined || $ === undefined ) throw Error("please include jquery & moment.js");
} catch (e) {
console.log(e);
}
==============
My require.js
This is what my requirejs-config.js looks like, it's sitting in app/design/frontend/##/##/requirejs-config.js:
var config = { // eslint-disable-line no-unused-vars
packages: [{
name: 'momentjs',
location: 'js/',
main: 'moment'
}],
map: {
'*': {
'menu': 'Magento_Theme/js/disable-menu',
'shippingtime': 'js/shiptime'
}
},
shim: {
'momentjs': {
deps: ['jquery']
},
'shippingtime': {
deps: ['jquery',',momentjs']
}
}
};
jQuery is loaded elsewhere and is definitely being loaded (I have various other jQuery libraries which are all working).
==============
Debugging
I initially thought the moment.js/shiptime.js files weren't being loaded in however they are when I check both the source and the network panel. To further test this, I did the following to see if moment.js would output anything:
require(['momentjs'], function (moment) {
console.log(moment().format('LLLL'));
});
This does output the date in the console so moment.js is definitely loading, this is my code for the shiptime.js file which isn't working and gives me the error I mentioned above:
require(['jquery', 'shippingtime', 'momentjs'], function (moment) {
jQuery(document).ready(function () {
jQuery(function($) {
jQuery('.shipping-time').shipTime();
});
});
});
Any advice would be greatly appreciated!
It's been a while since I've worked with requirejs but since no one smarter has chimed in yet I'm happy to help you keep troubleshooting. Using jQuery with requirejs can be tricky, especially with a large and complex platform like Magento.
Without being able to see all of your code I would consider and investigate the following:
Are you initializing jQuery properly in a no-conflict way if necessary
Are you using require() vs. define() where and as intended
Are you versed in the challenges unique to Magento when using requirejs
Have you reviewed and followed the recommendations regarding the complexities of using moment with requirejs
Here is some corresponding reading on each:
On No-Conflict
require() vs define() plus other good insights
On Magento 2 with RequireJS
On complexities of Moment and RequireJS
https://momentjs.com/docs/#/use-it/require-js/
https://github.com/requirejs/requirejs/issues/1554#issuecomment-226269905
One last thing to try:
In your final code example you pass moment to the function but not jQuery. Have you tried something along these lines:
require(['jquery', 'momentjs', 'shippingtime'], function($, moment) {
$(document).ready(function() {
$('.shipping-time').shipTime();
});
});
Related
I'm trying to build a requirejs module giving client code the options to render stuff with d3.js. The first plugin I want to use is a sankey diagram.
My module so far:
define(['d3'], function(ignore) {
console.log("bef", d3);
require(['sankey.js']);
console.log("aft", d3);
d3.sankey();
return {
...
d3: d3,
renderSankey: function(options) {
...
}
}
The sankey.js script uses the global d3 variable and adds the function sankey(). (I tried both btw, define(['d3'], function(ignore) and define(['d3'], function(d3), exactly the same result).
The error: TypeError: d3.sankey is not a function, no matter if I try to call it directly as the code shows or like this.d3.sankey() in the renderSankey function.
The console output says (both times, before and after the require(...) call:
sankey: d3.sankey()
No matter what I try, it won't work. I feel like I missed something JS specific about shadowing, but why is there a sankey function, when I console.log the object and a row later, when I try to call I get an error? What am I doing wrong?
info:
I'm using this inside a splunk html dashboard, this is maybe important...
I don't want the client code to import the dependicies (with about 100 plugins to come, this would be a pain)
When I just copy the content of the sankey.js into my module, everything works fine
/edit: Here is the Require configuration (given by the Splunk Dashboard)
require.config({
baseUrl: "{{SPLUNKWEB_URL_PREFIX}}/static/js",
waitSeconds: 0 // Disable require.js load timeout
});
The require call you are using to load sankey is asynchronous. It will launch the loading of sankey but by the time require returns, sankey is not loaded. You should change your code to:
define(['d3', 'sankey'], function (d3) {
d3.sankey();
I take it that d3 also leaks the symbol d3 in the global space but AMD modules should not rely on global symbols unless these are part of the runtime environment (e.g. window, document).
You also need to set your RequireJS configuration to make sankey dependent on d3 because the define above does not by itself ensure that d3 will load before sankey. So you need this in your configuration:
shim: {
sankey: ['d3']
}
This makes sankey dependent on d3. (Note that shim can only be used to affect the loading of files that are not proper AMD module. sankey does not call define to register itself, and thus is not a proper AMD module, and we can use shim for it.)
Also, module names should generally not have .js in them so when you want to load the plugin, load it as sankey, not sankey.js.
Okay, I think #Louis and I just misunderstood each other. This may be caused by my own stupidity, since I wasn't aware that a configuration of require.js can be done anywhere (and not only once in the root file). How ever, to still get the Splunk specific part I post this answer (instead of accepting Louis'):
I added a new app to my splunk environment to (a viz app). I actually configure the dependencies first (in the by other splunk apps loadable d3-viz module):
require.config({
paths: {
'd3': '../app/D3_Viz/d3', // d3.js
'sankey': '../app/D3_Viz/sankey', // sankey.js
'XYZ': 'all the paths go here'
},
shim: {
'sankey': ['d3'],
'XYZ': ['d3'],
// all the dependecies go here
}
});
define(['splunkjs/ready!', 'jquery', 'd3'],
function(mvc, $, ignore) {
var d3Vis = {
...
renderSankey: function(options) {
// load dependencies dynamically
require(['sankey'], function() {
// actually render things
});
},
renderXYZ: function(options) {
require(['XYZ'], function() {
...
});
},
...
}
}
return d3Vis;
All my dependencies can be configured in the viz-app (and not in the client code using the app, this has been my fundamental missunderstanding of require.js); the only thing to do is loading the app/viz as a whole (in this example in a HTML dashboard:
require([
"splunkjs/mvc",
"splunkjs/mvc/utils",
"splunkjs/mvc/tokenutils",
"underscore",
"jquery",
"splunkjs/mvc/simplexml",
"splunkjs/mvc/headerview",
"splunkjs/mvc/footerview",
...
"../app/D3_Viz/viz"
],
function(
mvc,
utils,
TokenUtils,
_,
$,
DashboardController,
HeaderView,
FooterView,
...
d3Viz
){
... splunk specific stuff
// No dependencies have to be configured
// in the client code
d3Viz.renderSankey({...});
}
);
JustGage uses Raphael, which as is well-discussed here, is not AMD compliant (and so doesn't work with Require.js).
I have not used Require.js before, nor done a lot of JS, so I am battling to get my head around this. There has been a lot of trial and error ;)
Using the approach suggested here, I have split the Raphael modules out into separate files and included them separately, as well as making a guess as to what to do for JustGage.
require.config({
paths: {
//other links removed
'eve': 'vendor/eve/eve',
'raphael-core': 'vendor/raphael/raphael.core',
'raphael-svg': 'vendor/raphael/raphael.svg',
'raphael-vml': 'vendor/raphael/raphael.vml',
'raphael': 'vendor/raphael/raphael.amd',
'justgage': 'vendor/justgage/justgage.1.0.1.min'
},
shim: {
'eve': {
exports: "eve"
},
'raphael': {
deps: ['eve'],
exports: "Raphael"
},
'justgage': {
deps: ['raphael'],
exports: "JustGage"
}
}
});
But the instructions then say "After the above configuration, you can start using Raphael like other require-js modules" which is not so helpful ;)
I think I need to do something in main.js?
In my cshtml page I have
require(["raphael", "justgage"], function(JustGage) {
$(function() {
var a = new JustGage({
id: "pvgauge",
value: #Model.GaugeValues.PV,
min: #Model.PVGauge.MinValue,
max: #Model.PVGauge.MaxValue,
title: "Personal Volume",
label: "PV",
levelColors: gaugeSettings.levelColors,
levelColorsGradient: gaugeSettings.levelColorsGradient,
showInnerShadow: gaugeSettings.showInnerShadow,
shadowSize: gaugeSettings.shadowSize,
labelFontColor: '#7ACE30',
titleFontColor: gaugeSettings.titleFontColor,
valueFontColor: gaugeSettings.valueFontColor
});
});
});
Now this at least finds JustGage, but now gives the error 'Raphael' is undefined.
(I have also tried just doing a script include directly in the cshtml file but get the error 'Mismatched anonymous define() module: function (eve) {')
Is my understanding correct that Require.js means things are not in global scope? And JustGage is expecting Raphael to be in global scope?
Any help on getting JustGage working? Or recommendations for an equivalent library for "speedo"-type gauges that will work with Require.js?
almost there, you need add it to the function as well, so it's available to JustGage.
require(["raphael", "justgage"], function(raphael,JustGage) {
If justgauge is a module then you should load the dependency in the module, as it will be looking in that module for raphael, however as you've already loaded it, it should work,
it's easier to keep track of your dependencies and load them where needed,
define(['module' , "pathto/raphael"], function (module, raphael) {
This worked for me:
require('eve');
window.Raphael = require('raphael');
require('justgage');
I use dojo 1.8.6 and socket.io 0.9.16, after I load socket.io.js client, dojo.require conflict is happened and no more dojo module can load.
require([ 'socket.io/socket.io' ]) cause error.
TypeError: Cannot read property 'push' of undefined
I can't use "dojox/socket" for some reason.
Anybody have any idea?
As of dojo 1.11 the following is working fine:
packages: [
"dojo",
{name: "socketio", location: "/socket.io", main: "socket.io"}
]
with module loading:
define([
"socketio"
], function (socketio) {
var socket = socketio();
});
I assume its working in prior versions as well but i have not tested it.
Alternatively you could directly refer to the socket.io module as it is AMD compliant.
define([
"/socket.io/socket.io.js"
], function (socketio) {
var socket = socketio();
});
Unfortunately the builder does still report an 311 error (missing dependency) hence not breaking the build. Can't work around this as there is no package.js where to mark as copy only...
The require statement needs to be a valid AMD mid (module identifier).
Usually, people will add the package to their config, e.g.:
var dojoConfig = {
packages: [
{name: 'socketio', location: 'path/to/socket.io/socket.io'}
]
}
and then require it:
require(['socketio'], function (socketio) {
// do something with socketio
});
As far as why you cannot use dojox/socket, I don't see any code to comment on. You might also want to check out https://github.com/bryanforbes/tube , which is a draft of a replacement for dojox/socket.
I'm upgrading from jQuery 1.8 to 1.9 and since jQuery.browser() is removed, I will use jQuery Browser Plugin.
My requirejs config file (loaded using data-main="") looks somewhat like this:
(EDITED - added more code snippets)
main-comp.js
require.config({
paths: {
jquery: 'libs/jquery/jquery1.9.1.min',
utils: 'modules/utils',
myController: "controllers/myController",
browserPlugin: 'libs/jquery/jquery.browser.min'
},
shim: {
browserPlugin: {
deps: ['jquery']
}
}
});
require(['myController', 'jquery'], function (controller, $) {
$(controller.start);
}
);
moduls/utils.js
define(['browserPlugin'], function () {
return {
browser: $.browser
};
});
myController.js
define(['utils'], function (utils) {
function start() {
console.log(utils.browser.msie)
}
return {
start: start
};
});
Everything seemed to work properly, but then I saw that sometimes in IE only I get a 'jQuery' is undefined (it's a capital Q there) or '$' is undefined errors from the jquery.browser.min.js file.
I thought the deps means that jquery will load before the jquery.browser file but apparently this isn't always the case. I tried following this answer and add exports: "$.fn.browser" but with no success.
When running an optimized version (minify+uglify using r.js) I haven't encountered it.
What am I doing wrong?
You need to ensure you reference $ as a parameter in the require callback. Like so:
require(['myController', 'jquery'], function (controller, $) {
$(controller.start);
}
);
This ensures that jQuery is available to use. It is a bit of an odd one as it will expose itself globally anyway so it will sometimes work regardless, but the correct way is to explicitly require it and use it inside the callback as a parameter.
It looks like you are missing jquery dependency in moduls/utils.js, please try:
define(['jquery', 'browserPlugin'], function ($) {
return {
browser: $.browser
};
});
and also, just to be on the safe side, add jquery to your shim :
jquery: {
exports: "$"
},
By the way, why don't you use $.browser in your code and just load the jquery plugin using the shim configuration?
I had the same problem, the script in data-main is loading asynchronously, that means that it may load after the scripts it defines.
The solution is to load another script with the require.config right after the require.js script.
data-main Entry Point Documentation.
I'm having issues trying to load ckeditor via requirejs (I've tried converting the main ckeditor js file into individual modules but that has just caused all hell to break loose) and so I'm now checking to see if there is a very simple way to do this that I've missed.
I know requirejs allows you to load normal js scripts so maybe just loading the ckeditor.js file (un-edited, so it's still an IIFE/self-executing function) - would that work with requirejs or if you're using requirejs for loading modules, does the entire project then need to be module based?
Any help appreciated.
Kind regards,
Mark
Alternatively, you can create a RequireJS shim to load things in the correct order, and alias proper RequireJS module names to the CKEditor distribution files.
This means your module still declares it is dependant on CKEditor, which is a lot nicer than having it just show up by magic.
require.config({
shim: {
'ckeditor-jquery':{
deps:['jquery','ckeditor-core']
}
},
paths: {
"jquery": '/javascript/jquery-1.7.1/jquery.min',
'ckeditor-core':'/javascript/ckeditor-3.6.4/ckeditor',
'ckeditor-jquery':'/javascript/ckeditor-3.6.4/adapters/jquery'
}
});
then in a module you can depend on ckeditor-jquery (or ckeditor-core for that matter, if you don't need the jQuery integration) and know it'll be available:
require(
[
"jquery",
"ckeditor-jquery"
],
function( _jquery_ ) {
$('#editorContent2').ckeditor({
customConfig : '',
skin:'office2003'
});
}
}
Another way to do that:
var require = {
"shim": {
"path/foo/ckeditor/ckeditor": { "exports": "CKEDITOR" }
}
};
define(['moduleX', 'path/foo/ckeditor/ckeditor'], function (x, ckeditor) {
ckeditor.editor.prototype.fooFunc = function() {
};
});
OK, it seems I answered my own question here.
Instead of trying to break ckeditor down into modules I just used RequireJs to load the script in it's entirety.
require(['require', 'dependancy-A', 'dependancy-B', 'dependancy-C'], function(require, A, B, C){
// this = [object DOMWindow]
// CKEDITOR_BASEPATH is a global variable
this.CKEDITOR_BASEPATH = '/ckeditor/';
require(['/ckeditor/ckeditor'], function(){
// Code to create a new editor instance
});
});
```