Trying to use Dijit but getting: Dojo is not defined - javascript

I am trying to include a demo dijit widget in my template. However, I keep getting: "Dojo is not defined". I tried to find an answer, but I couldn't. This error is odd as the required dojo.js is indeed loaded by the browser.
What is not working is:
dojo.require("dijit.form.MultiSelect");
However, if I use other dojo modules doing:
require(["dojo/store/JsonRest" ...
It works.
I made pastebin of my template here: http://pastebin.com/9fm13pSP

Is this Dojo 1.7?
For that version, I think Dojo expects the functions define() and require() to be defined in the global namespace.
These functions are then used to require dojo itself. Your dojo.js may have all the libraries in it, but they might not be available to use until you explicitly require them.
This worked for me (using Dojo 1.7.2):
<script>
// Dojo 1.7 (AMD)
require(["dojo"], function(dojo){
dojo.require("dijit.form.MultiSelect");
dojo.ready(function(){
var sel = dojo.byId('dynamic');
var n = 0;
for(var i in dijit){
var c = dojo.doc.createElement('option');
c.innerHTML = i;
c.value = n++;
sel.appendChild(c);
}
new dijit.form.MultiSelect({ name: 'dynamic' }, sel);
});
});
</script>

As Paul Grime pointed out, if you include Dojo 1.7 with the async:true flag set (as you did) it will only expose the require and define functions to the global namespace. This is part of the transition to the new style of AMD modules that was recently introduced.
You can now choose to either
Add that little "require dojo" wrapper around the code
Remove the "async:true" flag and rely on back-compatibility with 1.6
Convert your code to using the new 1.7 AMD asynchronous modules instead of the old synchronous style with "dojo.require".

Related

es5 modular design pattern to es6

I have a website with 100k users/day. Currently we are writing code in Jquery/Vanilla JS using the modular design pattern. A simple js to hide/show loader is as below
"use strict";
var loaderHandler = (function(){
var loader = document.getElementById('main_loader');
return{
showProcessLoader : function(){
loader.style.display = 'block';
loader.style.opacity = '0.5';
},
hideLoader : function(){
loader.style.display = 'none';
}
}
})();
docReady(function() {
loaderHandler.hideLoader();
});
Whenever I want to show loader at some place I just call loaderHandler.showProcessLoader(); and loaderHandler.hideLoader(); to hide it. Similarly, I have other JS files which are written using the same design pattern and I create a single minified JS using a gulp task from all the js that is required on that page. Currently, everything works fine and I am able to call one js file function inside the other without any problem.
I have decided to move my application to the latest es6 now I have the following issues/queries
What is the design pattern in es6 which will be equivalent to my modular design pattern?
I don't intend to rewrite my existing js files but write only new js in es6. So I want the new design pattern shouldn't interfere with the existing architecture and still provide me support to write new js files in es6.
Also, I still should be easily able to call one js file function in other when a single minified file for a page is created.
Edit - I am already using babel to transpile my es6 code to es5 equivalent
1) What is the design pattern in es6 which will be equivalent to my modular design pattern?
Design patterns aren't necessarily built into a language, they're just techniques that a language may or may not provide enough abstraction ability to accomplish. As it seems like you know based on question 2, any design pattern you could do before you can also do in ES6 and even vice versa. In fact, transpilers like babel take code writtin in es6 and convert it like magic to previous versions.
But what it really seems like is that you're eager to use some of the newest features available in ES6 and based on your code above it seems like you need some type of private variable and method encapsulation, which means classes are probably perfect for you.
Converting it is pretty simple, but the only thing you have to keep in mind is that you need to export a new instance of your class as compared to using an IIFE. With a class you'll also gain the ability to make multiple instances of your class if you want to or even do some inheritance, but with your current example there might not be a good use case for those features.
In the example below the id of the element is passed into the constructor, meaning you can re-use this class for any number of elements if you choose to or simply export a singleton instance.
class AbstractLoaderHandler{
constructor(el_id){
this.loader = document.getElementById(el_id)
}
showProcessLoader(){
this.loader.style.display = 'block';
this.loader.style.opacity = '0.5';
}
hideLoader(){
this.loader.style.display = 'none';
}
}
let loaderHandler = new AbstractLoaderHandler('main_loader');
loaderHandler.hideLoader();
<div id="main_loader">Hello World</div>
<button onClick="loaderHandler.showProcessLoader()">Show</button>
<button onclick="loaderHandler.hideLoader()">Hide</button>
3) Also, I still should be easily able to call one js file function in other when a single minified file for a page is created.
Keep in mind that this has to do entirely with the way in which you're bundling your files. All you really need to do to insure this is to keep whatever you create exposed as a global variable.

DOJO reference error: declare is not defined

I was following the jsfiddle link http://jsfiddle.net/phusick/894af and when I put the same code into my application, I was getting "reference error: declare is not defined". I have following declarations on top of my js file:
dojo.require("dojo._base.declare");
dojo.require("dojox.form.CheckedMultiSelect");
Thanks in advance for your help.
With Dojo AMD you can tell which module maps to which parameter, for example dojo/_base/declare which is mapped to a variable called declare.
However, in non-AMD code you don't have this possibility. In stead of that you have to do the following:
dojo.require('dojo._base.declare'); // Import
dojo.declare(/** Parameters */); // Use
And actually, modules in dojo/_base are already inside the Dojo core if I'm not mistaken, so you could leave away the dojo.require() line in this case.
For the following AMD code:
require(["dojo/_base/declare"], function(declare) {
var MyCheckedMultiSelect = declare(CheckedMultiSelect, {
/** Stuff */
});
});
You can write the following in non-AMD:
var MyCheckedMultiSelect = dojo.declare(CheckedMultiSelect, {
/** Stuff */
});
However, make sure that when you're running Dojo 1.7, that you disable async mode, for example:
<script>
dojoConfig = {
parseOnLoad: false,
async: true
};
</script>
This rule applies to most, if not all, modules in dojo/_base and several DOM modules, for example:
dojo/_base/xhr: Methods like put(), get(), ... become dojo.xhrGet(), dojo.xhrPut(), ...
dojo/_base/lang: Methods like mixin(), hitch(), ... become dojo.mixin(), dojo.hitch(), ...
dojo/dom: Methods like byId() become dojo.byId()
dojo/on: You have to use dojo.connect() for this
dijit/registry: Methods like byId() become dijit.byId()
...
However, if you're using Dojo 1.7, then you should probably just leave the code in AMD even if all other code is written in non-AMD code. Eventually you will have to upgrade all your code to AMD-syntax, if you're now investing time to convert the code to non-AMD and you later have to convert it to AMD again, you're doing the same work twice.

Use of dojo/select on non-AMD code

I have on my site legacy JavaScript that uses Sizzle as selector engine.
I recently added the dojo library (v 1.8) for visualization purposes (charts, etc.). Because dojo includes selectors (dojo/select), I am thinking that Sizzle is now redundant and that I could replace it with dojo/select. Is there a way to make dojo/select work with non-AMD code?
Brandon Boone's answer is very useful so you do not have to rewrite your selector strings. I think what you are asking for is how to export dojo/query into global namespace, i.e. into window object through asynchronous nature of AMD. There are two options:
If you use release version, it has dojo/query already packed in dojo.js, so you do not have to take care of asynchronous execution of module factory function, just export the variable:
<script
src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.0/dojo/dojo.js"
data-dojo-config="async:true"
></script>
<script>
// export query module to global namespace (window object)
require(["dojo/query"], function(query) {
window.query = query;
});
</script>
<script>
// query function is now available globally
console.log(query("li"));
</script>
See this example in action at jsFiddle: http://jsfiddle.net/phusick/gvnGu/
If you use baseless dojo, it would be more tricky because you actually have to wait for dojo/query to load:
<script src="dtk-sdk/dojo/dojo.js" data-dojo-config="async:true"></script>
<script>
// wrap your lecacy code into a function so it's not executed immediately
var executeNonAmdCode = function() {
console.log(query("li"));
}
</script>
<script>
require(["dojo/query"], function(query) {
// export query module to global namespace (window object)
window.query = query;
// execute the legacy code
executeNonAmdCode();
});
</script>
According to the docs you can swap out the DOJO selector engine for AMD/Dojo compatible versions of sizzle or slick. So if I were you, I'd keep Sizzle around and change dojo's underlying selector to Sizzle, removing the redundancy without having to touch legacy code.
We can also use other selector engine levels. Both Sizzle and Slick
are excellent selector engines that work with dojo/query. AMD/Dojo
compatible versions (just wrapped with AMD) are available here:
https://github.com/kriszyp/sizzle
https://github.com/kriszyp/slick
Once installed, you can use the selector engine module id as specified
selector engine level. We could set Sizzle as the query engine for our
page:
<script data-dojo-config="selectorEngine: 'sizzle/sizzle'" src="dojo/dojo.js">
</script>
or set Slick as the engine for a particular module:
define(["dojo/query!slick/Source/slick"], function(query){
query(".someClass:custom-pseudo").style("color", "red");
});
To add to #phusick's answer, I just learnt that starting with v1.8 dojo supports this:
<script type="dojo/require">
"myApp.query": "dojo/query"
</script>
The above code will add the query method to the global myApp object (and create myApp if needed).
Source:
http://dojotoolkit.org/reference-guide/1.8/dojo/parser.html#dojo-parser

Managing third party javascript libraries with bundled jQuery

I am working on a website globalization project, which involves (us the vendor) asking our clients to insert a script tag on their home/origin site. The script tag is necessary for helping our clients go global, and part of the solution embodies a UI that gets triggered based on certain end user criteria.
The UI is built through the help of jQuery, which we really can't expect our clients to insert on their pages, not to mention version mismatches will be hard to resolve. Therefore, our third party library downloads its own jQuery version, albeit namespaced differently to avoid any conflicts.
However, such a mechanism requires us to rename all instances of jQuery to something that will help us avoid name clashes with another jQuery instance (if present), and makes the our mangled jQuery (MY_Query in examples below) very hard to manage, let alone upgrade.
For example
jQuery = window.jQuery = window.$ = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context );
},
.
.
.
jQuery.fn = jQuery.prototype = ...
becomes
MY_JQuery = window.MY_JQuery = window.MY_Q = function( selector, context ) {
// The MY_JQuery object is actually just the init constructor 'enhanced'
return new MY_JQuery.fn.init( selector, context );
},
.
.
.
MP_JQuery.fn = MP_JQuery.prototype = ...
In an ideal world, both us and the client would have a single version of jQuery on the site, and we both would use it to our advantage. But that would mean an upgrade of jQuery would require heavy testing on both sides (while the mangled jQuery version is contained) and that any plugin wanted would require the client to add appropriate script tags to their site, spurring a political debate between the two parties on what versions win.
So, can I manage our jQuery version (with plugins) on a client site without having to rename all instances of jQuery with something like MY_Query with the constraints mentioned above?
Why not check to see if they have jQuery already included on the page and if not dynamically load it? If you know the base level jQuery needed you can check for that like this:
if( !jQuery || !jQuery.fn.jquery === "1.4.4"){
var url = "http://code.jquery.com/jquery-1.4.4.js";
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = url;
document.body.appendChild(script);
}
You'd probably want to improve the version detection to make sure that it doesn't have a version after 1.4.4, but I'm sure you could write the code for that yourself ;-)
==== Edit based on feedback
So you need to maintain multiple versions of jquery on the page. Have you tried something like this:
var original_jquery = $().noConflict();
original_jquery.getScript("http://code.jquery.com/jquery-1.4.4.js");
var new_jquery = $().noConflict();
window.$ = original_jquery;
Then use the new_jquery as your version of jquery? I haven't tested this to see if it would work, but you might have some luck with it.
==== Final edit
As you mentioned, my javascript above wasn't exactly correct, so I tried out a few things in the console. And yes, you don't need to save the old version of jQuery because jQuery does that in the noConflict method. So just call getScript, then noConflict but saving to a new variable:
>> $.fn.jquery
"1.4.2"
>> $.getScript("http://code.jquery.com/jquery-1.4.4.js");
undefined
>> $.fn.jquery
"1.4.4"
>> var new_jquery = $.noConflict();
undefined
>> new_jquery.fn.jquery
"1.4.4"
>> $.fn.jquery
"1.4.2"
Have you tried to use JQuery.noConflict(). This sounds like it could help you.

How to isolate different javascript libraries on the same page?

Suppose we need to embed a widget in third party page. This widget might use jquery for instance so widget carries a jquery library with itself.
Suppose third party page also uses jquery but a different version.
How to prevent clash between them when embedding widgets? jquery.noConflict is not an option because it's required to call this method for the first jquery library which is loaded in the page and this means that third party website should call it. The idea is that third party site should not amend or do anything aside putting tag with a src to the widget in order to use it.
Also this is not the problem with jquery in particular - google closure library (even compiled) might be taken as an example.
What solutions are exist to isolate different javascript libraries aside from obvious iframe?
Maybe loading javascript as string and then eval (by using Function('code to eval'), not the eval('code to eval')) it in anonymous function might do the trick?
Actually, I think jQuery.noConflict is precisely what you want to use. If I understand its implementation correctly, your code should look like this:
(function () {
var my$;
// your copy of the minified jQuery source
my$ = jQuery.noConflict(true);
// your widget code, which should use my$ instead of $
}());
The call to noConflict will restore the global jQuery and $ objects to their former values.
Function(...) makes an eval inside your function, it isn't any better.
Why not use the iframe they provide a default sandboxing for third party content.
And for friendly ones you can share text data, between them and your page, using parent.postMessage for modern browser or the window.name hack for the olders.
I built a library to solve this very problem. I am not sure if it will help you of course, because the code still has to be aware of the problem and use the library in the first place, so it will help only if you are able to change your code to use the library.
The library in question is called Packages JS and can be downloaded and used for free as it is Open Source under a Creative Commons license.
It basically works by packaging code inside functions. From those functions you export those objects you want to expose to other packages. In the consumer packages you import these objects into your local namespace. It doesn't matter if someone else or indeed even you yourself use the same name multiple times because you can resolve the ambiguity.
Here is an example:
(file example/greeting.js)
Package("example.greeting", function() {
// Create a function hello...
function hello() {
return "Hello world!";
};
// ...then export it for use by other packages
Export(hello);
// You need to supply a name for anonymous functions...
Export("goodbye", function() {
return "Goodbye cruel world!";
});
});
(file example/ambiguity.js)
Package("example.ambiguity", function() {
// functions hello and goodbye are also in example.greeting, making it ambiguous which
// one is intended when using the unqualified name.
function hello() {
return "Hello ambiguity!";
};
function goodbye() {
return "Goodbye ambiguity!";
};
// export for use by other packages
Export(hello);
Export(goodbye);
});
(file example/ambiguitytest.js)
Package("example.ambiguitytest", ["example.ambiguity", "example.greeting"], function(hello, log) {
// Which hello did we get? The one from example.ambiguity or from example.greeting?
log().info(hello());
// We will get the first one found, so the one from example.ambiguity in this case.
// Use fully qualified names to resolve any ambiguities.
var goodbye1 = Import("example.greeting.goodbye");
var goodbye2 = Import("example.ambiguity.goodbye");
log().info(goodbye1());
log().info(goodbye2());
});
example/ambiguitytest.js uses two libraries that both export a function goodbye, but it can explicitly import the correct ones and assign them to local aliases to disambiguate between them.
To use jQuery in this way would mean 'packaging' jQuery by wrapping it's code in a call to Package and Exporting the objects that it now exposes to the global scope. It means changing the library a bit which may not be what you want but alas there is no way around that that I can see without resorting to iframes.
I am planning on including 'packaged' versions of popular libraries along in the download and jQuery is definitely on the list, but at the moment I only have a packaged version of Sizzle, jQuery's selector engine.
Instead of looking for methods like no conflict, you can very well call full URL of the Google API on jQuery so that it can work in the application.
<script src="myjquery.min.js"></script>
<script>window.myjQuery = window.jQuery.noConflict();</script>
...
<script src='...'></script> //another widget using an old versioned jquery
<script>
(function($){
//...
//now you can access your own jquery here, without conflict
})(window.myjQuery);
delete window.myjQuery;
</script>
Most important points:
call jQuery.noConflict() method IMMEDIATELY AFTER your own jquery and related plugins tags
store the result jquery to a global variable, with a name that has little chance to conflict or confuse
load your widget using the old versioned jquery;
followed up is your logic codes. using a closure to obtain a private $ for convience. The private $ will not conflict with other jquerys.
You'd better not forget to delete the global temp var.

Categories

Resources