I'm diving into Require.js to build a Google Maps application using this link and this link as a guide. My goal is to build a modular application that loads "base" functionality first, and then I can "plug-in" client-specific functionality - without duplicating code. So every project will use the "base" JS, but the client-specific JS will be different each project. Below is a list of my loading dependencies. This is the order I need things to load, with the previous item in the list needing to be fully loaded before moving onto the next:
Load jQuery and Google Maps API (I got this one working)
Load JavaScript to initialize my map on the page with base application functionality
Load additional/client-specific JavaScript.
I can get 1 and 2 to work just fine using this:
main.js:
require.config({
paths:{
jquery: "jquery-1.7.1.min",
jqueryui: "jquery-ui-1.8.22.custom.min",
async: "async",
requiremap: "requiremap"
}
});
require(
[ "jquery", "jqueryui", "requiremap" ],
function( $, jqueryui, requiremap ) {
}
);
requiremap.js:
define(
[ "async!http://maps.google.com/maps/api/js?sensor=false" ],
function() {
require(['js/basemapfunctionality.js'], function() {
});
}
);
But now I need to wait until #2 is completely loaded before loading #3. Is this possible with Require.js, and if so, how? (and if not, are there alternative frameworks that can do this) I tried adding another nested require method to load the additional functionality (illustrated below), but it acts like #2 hasn't loaded yet.
define(
[ "async!http://maps.google.com/maps/api/js?sensor=false" ],
function() {
require(['js/basemapfunctionality.js'], function() {
require(['js/additionalfunctionality.js'], function() {
// now everything should be loaded, but it ain't
});
});
}
);
Got this to work. Just had to break up the loading of Google Maps API, base functionality, and additional functionality into different modules and declare each in main.js.
main.js
require.config({
paths:{
jquery: "jquery-1.7.1.min",
jqueryui: "jquery-ui-1.8.22.custom.min",
async: "async",
requiremap: "requiremap",
basemapfunctionality: "basemapfunctionality",
additionalfunctionality: "additionalfunctionality"
}
});
require(
[ "jquery", "jqueryui", "requiremap", "basemapfunctionality", "additionalfunctionality" ],
function( $, jqueryui, requiremap, basemapfunctionality, additionalfunctionality ) {
}
);
requiremap.js
define([ "async!https://maps.google.com/maps/api/js?sensor=false" ], function() {});
basemapfunctionality.js
define(['requiremap'], function(requiremap) {
// basemap functionality here
}
additionalfunctionality.js
define(['requiremap', 'basemapfunctionality'], function(requiremap, basemapfunctionality) {
// additional functionality here
}
I'm not much into RequireJS, but this issue and the commentary implies a way to resolve your question.
Relevant quote from the link:
This is due to the interaction of $.extend and the order of execution of modules.
In a built file, the 'other/config' module is evaluated before the inner call to
require(['other/controller'], an since $.extend only mixes in properties, it causes the problem.
You can avoid it by using the Object.create() type of approach, where you create a new object whose
prototype is the BaseConfig, so that later, any properties you add to the BaseConfig will show up
automatically on that new object.
See Asynchronously Loading the API. There is a callback parameter where you can indicate a callback function that will be called when the API is fully loaded.
Did you try with Order.js plugin ?
Related
While not that specific issue, the issue described here - https://wordpress.org/support/topic/select2-conflicting-with-acf-v5 is basically my problem as well.
A wordpress site has two wordpress plugins, one uses select2 version 3.5 to handle all select elements, the other (included in a plugin I wrote) uses 4.0 to handle some specific ones. This result in an error of
Error: select2.min.js?ver=3.4.5:21 Uncaught Error: Option 'multiple' is not allowed for Select2 when attached to a element.
Is there any possible solution to this kind of problem? Should I just try to detect that 3.5 is loaded and try to avoid conflicting settings? maybe try to have "my" select2 to load first and hope that since I am more specific, there will not be conflicts with the code that uses 3.5? (my knowledge of jQuery internals is lacking, what does happen when different plugins try to use the same name?)
I am facing the exact same issue with my plugin Popup Maker. I found this select2 multiple versions on same page/site that may be useful, the only issue I forsee there is that we can't always control the order plugins load their JS using wp_enqueue_script.
Ok so what I did was made my script require select2 (DUH), then just inside my scripts enclosure I did something like this.
$.fn.pumSelect2 = $.fn.select2;
Then later instead of calling .select2() I use .pumSelect2().
This works great for my situation which is that I use v4, others use v3.5, some even bootstrap it into their own admin.js file so it loads even though select2 is already loaded.
So all in all its a hack but since we are doing it the right way by loading using wp_enqueue_script.
I also dequeue select2 if its enqueued.
// Deregister older versions, loaded by Types, Advanced Custom Fields etc.
if ( wp_script_is( 'select2', 'registered' ) ) {
wp_deregister_script( 'select2' );
}
wp_register_script( 'select2', $js_dir . 'select2.full' . $suffix, array( 'jquery' ), '4.0.1' );
`
Final Method For Now
After further testing and since so many other plugins use old versions with customizations that will likely break this is what I came up with.
In my select2.full.js file
For the opening section that loads jQuery and calls factory
(function (factory) {
var existingVersion = jQuery.fn.select2 || null;
if (existingVersion) {
delete jQuery.fn.select2;
}
if (typeof define === 'function' && define.amd !== undefined && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
jQuery.fn.pumselect2 = jQuery.fn.select2;
if (existingVersion) {
delete jQuery.fn.select2;
jQuery.fn.select2 = existingVersion;
}
}(function (jQuery) {
Basically I bootstrap it to a new name in this case pumselect2, and if there was previously a loaded version I restore it, otherwise I wipe the slate so that if another is loaded no conflict arises.
Also I modified my wp_enqueue_script handle to be pumselect2 so that it gets loaded even if someone else loads select2.
Hope that helps.
For WordPress plugin authors using select2 my answer here: Jquery Select2 plugin version check could provide some guidance on version checking.
I have a interesting concept I was working on and looking over, through various stack questions on auto loading JavaScript. I dint want to use a third party tool, aside form jquery, so I thought I would role my own. The concept I have is:
var scripts = {
'name' : 'path/to/script_dir/' // Load all scripts in this file.
}
requireScripts(scripts); // Requires all scripts
// Call your classes, methods, objects and so on ....
The requireScript() function would work something like:
function requireScript(hash){
$.each(hash, function(key, value)){
$.ajax({
url: value,
dataType: "script",
async: false,
error: function () {
throw new Error("Could not load script " + script);
}
});
});
}
Note: The above is just a concept, I don't think it will work.
The above would let you load SPECIFIC scripts. so in essence your hash key value would be 'name' : 'path/to/specific/script'. The issue this posses is that your hash would get rather large ....
The other issue I ran into is what if I simplified this to "php pear naming standard" so, as the trend seems to be - we would create a class, and it would be named after its location:
var some_folder_name_class = function(){}
Would be translated by the autoloader as: some/folder/name/class.js and then loaded that way.
To wrap up and get to my point there are two ways of loading javascript file I am looking at, via rolling my own "require" method. One is loading a directory of javascript files via the hash idea implemented above. (the provided code sample of how this hash would be walked through would have to be changed and fixed....I dont think it works to even load a single file)
OR
to have you just do:
new some_class_name() and have a global function listen for the new word, go find the file your trying to call based on the name of the class and load it, this you never have to worry - as long as you follow "pear naming standards" in both class and folder structure your js file will be loaded.
Can either approach be done? or am I dreaming to big?
I see a lot of frameworks do a bunch of require('/path/to/script') and if I could role my own autoloader to just allow me to either load a directory of js files or even have it where it listens for new before a class instantiation then I could make my life SO MUCH easier.
Have you consider using requirejs and probably Lazy loading.
http://www.joezimjs.com/javascript/lazy-loading-javascript-with-requirejs/
Here is sample version:
You can download here.
The sample is based on this folder structure :
public
index.html
scripts
app.js
lib
** jquery-1.10.2.js
** require.js
3 . From Code:
html
`<!DOCTYPE html><html>
<head><title>Sample Test</title>`
<script src="scripts/lib/require.js"></script> <!-- downloaded from link provide above-->
<script src="scripts/app.js"></script></head>
`<body><h1>My Sample Project</h1><div id="someDiv"></div></body></html>`
application configuration app.js
requirejs.config({
baseUrl: 'scripts',
paths: {
app: 'app',
jquery: 'lib/jquery-1.10.2' //your libraries/modules definitions
}
});
// Start the main app logic. loading jquery module
require(['jquery'], function ($) {
$(document).on('ready',function(){
$('#someDiv').html('Hello World');
});
});
jQuery-only option
If you are looking for a jQuery-only solution, have a look at jQuery.getScript(). It would be a great candidate for handling the script loading portion of your problem. You could then write a very small wrapper around it to load all the scripts—something like you wrote above:
var loadScripts = function(scripts) {
$.each(scripts, function(name, path) {
jQuery.getScript("/root/path/" + path + ".js");
})
}
If you are interested in more information on this approach, read this article by David Walsh.
Other great libraries
I strongly recommend taking a look at the current batch of script-loading libraries. I think that you will pleasantly surprised by what is out there. Plus, they come with the benefit of great community support and documentation. RequireJS seems to be the front runner but David Walsh has great articles on curl.js and LABjs.
I've been looking at require.js and I am a bit confused on how to use it for my widgets system.
My widgets system basically allows the user to choose which widget s/he wants to see which gets stored in the database.
So when the user loads the page on the next visit, s/he will see only the widgets s/he selected. In effect only loading the html, javascript needed for the displayed widgets instead of loading all the html and javascript for all the widgets and then hidding the stuff which is not needed.
What I am confused about is how to do this with require.js
Am I supposed to dynamically generate the require.js code below? If the user has saved widget_1, widget_5 and widget_70, I am assuming I need to dynamically generating javascript like so?
require(['widget_1','widget_5','widget_70'], function(w1, w5, w70){
// then do something here?
});
the require line, is that supposed to be dynamically generated based on an sql query?
So if they only select a single widget to save for next time viewing, they will only get:
require(['widget_90'], function(w90){
// then do something here?
});
Is that what I am supposed to be doing?
Always define path's to the libraries that your modules rely on too often, something like below:
<script data-main="scripts/main" src="scripts/require.js"></script>
File: scripts/main.js
require.config({
paths: {
jQuery_1_7_2: 'lib/jquery.1.7.2',
underscore: 'lib/underscore',
.....
.....
}
});
Note: You need to include libraries with-in a module and return as an object, something like below:
File: lib/jquery.1.7.2.js
define([ 'lib/jquery/jquery.1.7.2.min' ], function() {
return jQuery.noConflict(true);
});
Same approach can be followed for other libraries that does not follow modular approach [AMD spec]
Note: The above step of defining library modules can be avoided by using shim feature
Since your page is dynamic, you never know what modules will be loaded.
You can invoke multiple require() calls to load modules. Since requirejs load's scripts asynchronously, the below approach will not harm your page performance.
Module-1 with in HTML view
<html>..
<div id="module_1">
//contents of module 1
</div>
<script type="text/javascript">
require(["scripts/widgets/module_1"], function( module_1 ){
module_1.init();
})
</script>
..</html>
File: scripts/widgets/module_1.js
define(["jQuery_1_7_2","underscore"], function($, _){
// Module functionality goes here
return {
init: function(){
// Module initialiser
}
}
});
Module 2 with-in HTML view
<html>..
<div id="module_2">
//contents of module 2
</div>
<script type="text/javascript">
require(["scripts/widgets/module_2"], function( module_2 ){
module_2.init();
})
</script>
..</html>
File: scripts/widgets/module_2.js
define(["jQuery_1_7_2","underscore"], function($, _){
// Module functionality goes here
return {
init: function(){
// Module initialiser
}
}
});
If you do not mind initializing the module after DOM load, you could use controljs and change the MIME type of the script tags. I believe that would not make too much of difference on the page performance.
I assume:
you have defined path to widgets in require config somewhere
your widgets are sandboxed (can be run without dependencies)
your application can run without widgets
You could generate the array on the server and populate it to js (e.g. as inline script) and then publish some kind of app.ready event, like so:
<script>
require(/*array from the server*/, function(){
// publish application ready event
});
</script>
I've created a jQuery UI widget which is dependent on some other custom JavaScript modules. I fetch these modules using requirejs during the "_create" method of the widget. This actually works great if, I have my end consumers define my "data-main" property. However, in the situation where my consumers are using requirejs on their own, and defining their own "data-main" property, this doesn't work.
Since I'm using requirejs to inject scripts via my widget from a totally different server, I run into a few problems with requirejs's normal way of dealing with this.
First, I can't use a package.json file unless I assume that all of my consumers have a package.json which contains the exact same resources as I have. On top of that, I've got DEV, TEST and PROD server URLs to deal with.
Second I can't use require.config to set my baseUrl during a load on their server, cause it may break everything that they are using require for.
The current implementation I have working requires the consumer to add a script reference to require with my data-main location (external server). Then add a script ref to my widget (external server). This works because nobody else at my company has ever even heard of requirejs :). The second I start showing them how to bundle all of their code into reusable JavaScript modules my solution is broken.
I want to come up with a solution whereas the end consumer can simply reference my single JavaScript widget, which in turn loads everything it needs to function.
Any suggestions on how to do this? I've thought about hacking my own version of require with a static data-main, then just assume they can have multiple requirejs libs. I WOULD HATE TO DO THAT...but I can't really think of a better way.
Here is what I am going to do...
Couple of notes:
I'm using the jQuery UI widget factory pattern (but this isn't exactly a widget)
The widget code lives on a remote server and consumers only reference it, don't download it
I'm using requirejs to load widget dependencies
I want the greatest ease-of-use for the consuming developer
Since it's required that my jQuery UI widget be loaded ASAP so that the consumer has the context of the widget right away ( $(selector).mywidget ) I've decided to tackle my problem inside of the _create method.
This code basically installs requirejs if it doesn't exist, then uses it to install an array of requirements which the aforementioned widget needs to consume. This allows me to assume that the end user can reference my "widget" script by URL, tack on a "data-requiremodule" attribute of the same name, and get a complete list of remote dependencies.
_create: function () {
var widget = this;
widget._establish(widget, function () {
widget._install(widget);
});
},
_getBaseURL: function (scriptId, callback) {
var str = $('script[data-requiremodule="' + scriptId + '"]').attr('src');
if (callback) callback(str.substring(str.search(/scripts/i), 0));
},
_require: function (requirementAry, baseUrl, callback) {
require.config({ baseUrl: baseUrl });
require(requirementAry, function () {
if (callback) callback();
});
},
_establish: function (widget, callback) {
if (typeof require === 'undefined') {
widget._getBaseURL(widget._configurations.widgetName, function (baseUrl) {
var requireUrl = baseUrl + 'scripts/require.min.js';
baseUrl = baseUrl + 'scripts/';
$.getScript(requireUrl, function (data, textStatus) {
widget._require(widget._configurations.requiredLibs, baseUrl, function () {
callback(textStatus);
});
});
});
}
},
I'm not showing my "_configurations" object here...but you get the idea. I hope this helps someone else besides me :).
I am toying around with a pretty intensive ajax based jquery web application. It is getting to a point where I almost loose track of what events that should trigger what actions etc.
I am sort of left with a feeling that my javascript structure is wrong, on a more basic level. How do you guys structure your javascript/jquery code, the event handling etc., any advise for a newbie javascript developer.
AMDS!
It's been awhile since first answers got posted to this question and many things have changed.
First and foremost, the JS browser world seems to be moving towards AMDs (asynchronous module definition) for code organization.
The way that works is you write ALL your code as AMD modules, e.g.:
define('moduleName', ['dependency1', 'dependency2'], function (dependency1, dependency2) {
/*This function will get triggered only after all dependency modules loaded*/
var module = {/*whatever module object, can be any JS variable here really*/};
return module;
});
And then modules get loaded using AMD loaders like curl.js or require.js etc, for example:
curl(
[
'myApp/moduleA',
'myApp/moduleB'
],
).then(
function success (A, B) {
// load myApp here!
},
function failure (ex) {
alert('myApp didn't load. reason: ' + ex.message);
}
);
Advantages are:
You only have to include single <script> element on your page that loads AMD loader itself (some of them are quite tiny).
After that all JS files will be fetched automatically in asynchronous NON BLOCKING! fashion, thus way faster!
Necessary modules will get executed only after its dependencies got loaded.
Modular (which means code that is easier to maintain and re-use).
Global variables pollution can be completely curbed if used correctly.
Honestly, once concept has clicked in your head, you'll never go back to your old ways.
P.S: jQuery does register itself as AMD module starting from version 1.7.
More information on AMDS:
https://github.com/cujojs/curl
http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition
http://requirejs.org/
http://www.bennadel.com/blog/2275-Using-RequireJS-For-Asynchronous-Script-Loading-And-JavaScript-Dependency-Management.htm
https://github.com/Integralist/Blog-Posts/blob/master/2012-01-04-Beginners-guide-to-AMD-and-RequireJS.md
For javascript code I found the following links from Christian Heilmann indispensable
The module pattern
Configuring scripts
I also really like the method described by Peter Michaux here
For jQuery, I heartily recommend reading the guides on Authoring and I found this tutorial on jQuery plugin patterns very good
To keep my events in control I use a publish/subscribe mechanism
jQuery.subscribe = function( eventName, obj, method ){
$(window).bind( eventName, function() {
obj[method].apply( obj, Array.prototype.slice.call( arguments, 1 ) );
});
return jQuery;
}
jQuery.publish = function(eventName){
$( window ).trigger( eventName, Array.prototype.slice.call( arguments, 1 ) );
return jQuery;
}
Here's an example of its use
// a couple of objects to work with
var myObj = {
method1: function( arg ) {
alert( 'myObj::method1 says: '+arg );
},
method2: function( arg1, arg2 ) {
alert( arg1 );
//republish
$.publish( 'anEventNameIMadeUp', arg2 );
}
}
var myOtherObj = {
say: function(arg){
alert('myOtherObj::say says: ' + arg);
}
}
// you can then have all your event connections in one place
//myObj::method2 is now listening for the 'start' event
$.subscribe( 'start', myObj, 'method2' );
//myOtherObj::say is now listening for the 'another' event
$.subscribe( 'anotherEvent', myOtherObj, 'say' );
//myObj::method1 is now listening for the 'anEventNameIMadeUp' event
$.subscribe( 'anEventNameIMadeUp', myObj, 'method1' );
//so is myOtherObj::say
$.subscribe( 'anEventNameIMadeUp', myOtherObj, 'say' );
// ok, trigger some events (this could happen anywhere)
$.publish( 'start', 'message1', 'message2' );
$.publish( 'anotherEvent', 'another message' );
I definitely recommend reading up on the object literal pattern in addition to the module pattern; here's a good writeup:
http://ajaxian.com/archives/show-love-to-the-object-literal
(function($, window, slice)
{
$.subscribe = function(eventName, obj, method)
{
$(window).bind(eventName, function()
{
obj[method].apply(obj, slice.call(arguments, 1));
});
return $;
};
$.publish = function(eventName)
{
$(window).trigger(eventName, slice.call(arguments, 1));
return jQuery;
};
})(jQuery, window, Array.prototype.slice);
To add to the existing answers, here's a great post that covers more advanced techniques that build on the Module Pattern.
Once your Javascript code reaches a certain size, you'll inevitably want to refactor it by breaking it into multiple files / modules / sub-modules. If you're not sure how to accomplish this using the module pattern, this article is a must-read.
My js files usually follow a naming convention similar to this :
xxx.utility.js
mypage.events.js
xxx.common.js
/lib/
/OS-DoNotDistribute/lib/
Where
'mypage' is the name of the html,
aspx, php, etc file.
'xxx' is the concept. (i.e. orders.common.js)
'utility' signifies it's a reusable
library script (i.e. ajax.utility.js, controlfader.utility.js)
'common' is reusable functionality
for this app, but not reusable across
other projects
'lib' is a subdirectory for any external or library scripts
'OS-DoNotDistribute' is a subdirectory to ensure no OS licensed code is distributed if the app is ever sold.
Also, for ajax, I have a special naming convention for call back functions, so it's easy to tell what they are.
I'm not sure it that's close to what you were looking for, but I hope it helps.
I really like these articles:
http://www.virgentech.com/blog/2009/10/building-object-oriented-jquery-plugin.html
http://stefangabos.ro/jquery/jquery-plugin-boilerplate-revisited/
They helped me to understand how telerik creates extensions for asp.net mvc.
I like the idea of AMDs (see nix's answer).
But I typically compile all my JS files into one JS file.
In that case the asynchronous part is not needed. So I wrote a little "Infile Module Loader".
Here it is: https://codereview.stackexchange.com/questions/14530/a-little-infile-amd
We can use mvc pattern in our javascript-jquery applications.
(Backbone.js, knockout.js vs.... ) are mature libraries we can use for this aim.