Dojo amd loading cross-domain modules at runtime - dojo

I want to load Dojo1.9 amd modules from an ad-hoc server on the www, but I won't know from where until runtime (with url params).
In essence, I want to do the equivalent of this:
require(['http://www.foo.com/SomeRandomModule'], function( SomeRandomModule ) {
// use SomeRandomModule
});

Quick and dirty way
Might have some unexpected quirks when it comes to the module system and relative paths, I haven't used it enough to say:
require([ "//host/myext/mod1/mod2.js" ],function(mod2){
// If current webpage is http:// or https:// or file://
// it tries to use the same protocol
});
Better way
Configure require() to treat all modules that start with a certain package name (e.g. foo) as coming from a particular URL. From your starter page, something like:
<script src="dojo/dojo.js"
data-dojo-config="packages:[{name:'myext',location:'//host/js/myext'}], async: 1, >
</script>
This lets you vastly improve your first example to:
require([ "myext/mod1/mod2" ],function(mod2){
});
If you are using a Dojo Bootstrap installation instead, you can avoid touching your data-dojo-config and instead put it inside the run.js startup file:
require({
baseUrl: '',
packages: [
'dojo',
'dijit',
'dojox',
'myapp',
{ name: 'myext', location: '//host/js/myext', map: {} }
]
}, [ 'myapp' ]);

Related

intern.js How to test legacy non modular code

I'm using intern.js as a test framework to test dojo modules and it works well.
Now I have to test some non modular legacy code but I can't.
This is an example of a simple file to test:
var Component = function() {
this.itWorks = function() {
return true;
}
};
And this is the test
define([
'intern!object',
'intern/chai!assert',
'intern/order!controls/component',
], function (registerSuite, assert) {
registerSuite({
name: 'test legacy code',
'simple test': function () {
console.log(Component);
}
});
});
The test fails sayng that "Component is not defined".
I've notice that it works only if I write
window.Component = Component
At the bottom of file to test.
I can't modify all the file to test, is it possible to test the file in a different way?
This should work fine. One possible issue is where you're loading component from. The 'controls/component' dependency in 'intern/order!controls/component' is, barring any special loader config, relative to the file doing the loading. That means that if the project is setup like this:
project/
controls/
component.js
tests/
intern.js
componentTest.js
and component is being loaded from componentTest.js, then the dependency should be 'intern/order!../controls/component.js'. (It will actually work without the '../' in this case since controls is a top level directory in the project.)
Another potential issue is that a non-AMD identifier should use the .js suffix. This tells the loader that the thing being loaded is a generic script rather than an AMD module.
Also note that the order plugin is only needed to load multiple legacy files in a specific order. If order doesn't matter, or you're just loading one script, you can just use the script itself '../controls/component.js' as the dependency.
<"/"https://stackoverflow.com/tags" term="legacy" /">
<"/!-- begin snippet: js hide: false console: true babel: false --"/">
"var Component" = function() {
"this.itWorks" = function() {
return=true;
}
};
<"/"!-- end snippet --"/">

EJS Statements in Plain HTML File and in TypeScript

I'm trying to wrap my head around a seed project for Angular 2 which has a lot of moving parts, and I came across something that I don't understand... In the index.html there are what appear to be ejs statements:
<!-- src/client/index.html -->
<title><%= APP_TITLE %></title>
Although I understand WHAT it's doing (allowing the title to be defined in a config file), I don't understand HOW it's doing it. While I do see express, I don't see ejs as a dependency in the package.json
To make it more confusing, there are similar ejs-like statements in some typescript files that look like this:
// src/client/app/system-config.ts
System.config(JSON.parse('<%= SYSTEM_CONFIG_DEV %>'));
// src/client/app/app.module.ts
#NgModule({
imports: [BrowserModule, HttpModule, RouterModule.forRoot(routes), AboutModule, HomeModule, SharedModule.forRoot()],
declarations: [AppComponent],
providers: [{
provide: APP_BASE_HREF,
useValue: '<%= APP_BASE %>' // <------- this!?!?
}],
bootstrap: [AppComponent]
})
So, this same interpolation is working outside of a template!? How does this work? What tool or package is facilitating this replacement? I can't figure it out. I believe this is the code for running the server:
/**
* Starts a new `express` server, serving the built files from `dist/prod`.
*/
export function serveProd() {
let root = resolve(process.cwd(), Config.PROD_DEST);
let server = express();
server.use(Config.APP_BASE, express.static(root));
server.use(fallback('index.html', { root }));
server.listen(Config.PORT, () =>
openResource('http://localhost:' + Config.PORT + Config.APP_BASE)
);
};
I know Express comes with EJS support out-of-the-box, however, it requires the file to have an .ejs extension. I know there is a way to force it to parse regular .html files, but that code does not seem exist in the angular seed project.
I finally figured out what it was just a few minutes after posting my question. Drumroll please...
It's gulp-template, not EJS. It's simply underscore templating that gulp is replacing with config values at build time. So, mystery solved.

gridx modules won't load in my rational/worklight environment

as i attempt to load modules with the creation of a gridx/grid, my script goes to that strange place where errors are handled by code that looks like gobbledy gook.
if i create the grid without the modules attribute the rows are displayed just fine. i am coding with worklight 6.1 in rational app developer 9.1, using dojo 1.9 that's (delivered with RAD).
my dojo includes are specified like this:
function dojoInit() {
require([ "dojo/ready", "dojo/parser", "dojox/mobile", "dojo/dom",
"dijit/registry", "dojox/mobile/ScrollableView",
"dojox/mobile/Heading", "dojox/mobile/ScrollablePane",
"dojox/mobile/Pane", "dojox/mobile/TextArea", "dojox/mobile/ContentPane",
"dojo/Deferred", "dojo/store/Memory",
"gridx/Grid", "gridx/core/model/cache/Sync", "dojox/mobile/Container",
"gridx/modules/SingleSort"],
function(ready) { ...
Here are my stylesheet links:
<link rel="stylesheet" href="css/dojo.css" />
<link rel="stylesheet" href="css/claro.css" />
<link rel="stylesheet" href="css/document.css" />
<link rel="stylesheet" href="css/Gridx.css" />
<link rel="stylesheet" href="css/Gridx_rtl.css" />
i moved the css files from gridx/resources/claro/Gridx.css and other locations within the dojo toolkit library to a known relative location, temporarily, in order to eliminate the possibility that the css files could not be resolved. and i am specifying just the 'claro' class in the div wherein this grid is placed. there is no difference in the behavior of the grid in either case.
My grid is created like this:
toStore=new dojo.store.Memory({ idProperty: 'PICYNO', data: resultSet });
toColumns=[
{ id: 'PICYNO', field: 'PICYNO', name: 'Cycle' , width: '80px' , editable: true },
{ id: 'PIDSC1', field: 'PIDSC1', name: 'Description' , width: '300px', editable: true },
{ id: 'PICYCS', field: 'PICYCS', name: 'Status' , width: '60px' , editable: true },
{ id: 'PPICSDJ',field: 'PPICSDJ', name: 'Date' , width: '80px' , editable: true },
{ id: 'PICYIT', field: 'PICYIT', name: 'Items' , width: '60px' , editable: true },
{ id: 'PICYLO', field: 'PICYLO', name: 'Locations' , width: '60px' , editable: true }
];
var cacheClass = "gridx/core/model/cache/Sync";
var tsGrid = new gridx.Grid({
id: 'idHeaderGrid',
cacheClass: cacheClass,
store: toStore,
// modules:[modules.SingleSort, modules.SelectRow],
// modules:[gridx.modules.SingleSort],
// modules:[gridx/modules/SingleSort],
// modules: [ SingleSort ],
// modules: [ Sort ],
structure: toColumns
});
tsGrid.placeAt('idGridContentPane');
tsGrid.startup();
if i comment all the lines that specifiy 'modules:' as you see, then the grid is displayed (but it's ugly, as if the stylesheets weren't applied at all.)
if i try any variation of specifying the standard sort module, this function will tank. i know it's probably because i'm not specifying my environment correctly, but i can't see how.
Any known problems with any of the versions that i'm using? any suggestion is appreciated.
--------- Updated ------------
I have progressed to the extent that i can display a grid, but the formatting is still off.
Based on the results of experimenting with a non-worklight project where i was able to materialize the grid with modules, and also realizing that with either type of project (web or worklight), i was able to resolve dojo and Gridx objects even though the javascript resources are configured differently, i decided to try a local require statement to specify the dojo modules in the immediate context and it worked. The original dojo configuration in worklight was ocnfigured in the main.js object that's automatically generated with a worklight application. it looked like this:
function wlCommonInit() {
require([ "layers/core-web-layer", "layers/mobile-ui-layer" ], dojoInit);
}
function dojoInit() {
require([ "dojo/ready", "dojo/parser", "dojox/mobile", "dojo/dom",
"dijit/registry", "dojox/mobile/ScrollableView",
"dojox/mobile/Heading", "dojox/mobile/ScrollablePane",
"dojox/mobile/Pane", "dojox/mobile/TextArea", "dojox/mobile/ContentPane",
"dojo/Deferred", "dojo/store/Memory", "dojox/mobile/Container",
"gridx/modules/SingleSort", "gridx/modules/ColumnResizer", "gridx/modules/RowHeader"
],
function(ready) {
ready(function() {
ccInit();
});
});
}
I removed the module declarations from the main.js and added them in the ccInit.js application where the grid is created, like this:
function populateGrid() {
require([
'dojo/store/Memory',
'gridx/Grid',
'gridx/core/model/cache/Sync',
'gridx/modules/SingleSort',
'gridx/modules/ColumnResizer',
'gridx/modules/RowHeader'
], function(Store, Grid, Cache, Sort, ColumnResizer, RowHeader) {
. . .
var tsGrid = new gridx.Grid({
id: 'idHeaderGrid',
cacheClass: Cache,
store: toStore,
modules: [ Sort, ColumnResizer, RowHeader ],
structure: toColumns,
selectRowTriggerOnCell: true
});
...
The grid is created successfully when it is created within an immediate require context as shown. Lots of dojo calls and even a grid without modules will work if i use the non-immediate approach.
The syles are still messed up, though. Column headings are blank and the table looks nothing like a claro-styled grid. I am sure that i have set up the css includes in the html header correctly (using my working web project as a model). Is there some worklight initialization or 'skin' overlay that's messing this up?
Thanks for any comment.
--- workaround is to refer to all classes, locally.
I solved the problem with stylesheets by creating the gridx.css in the common\css folder, then I edited it by replacing each #import with a copy/paste of the imported css source. So my gridx.css is a merge of all the source code from all the imports. i point to that css\gridx in my header link and i get reasonable results.
So in summary, i had to explicitly require the gridx classes in the custom function rather than in the dojo require statement in the main.js. And i had to merge all of the gridx styles and refer to them locally as well. The problem where gridx.css and other style sheets are not resolved through relative path includes that point to the dojo toolkit seems like a bug. Those stylesheets seem to be loaded in the run-time-generated server as evidenced by the console messages that look like this:
Failed to load resource: the server responded with a status of 404 (Not Found) http://myWLdevServer.mycomputer.local:10080/JustGridx/apps/services/preview/JustGridx/common/0/default/dojo/gridx/resources/claro/Gridx.css
If a developer is supposed to do some kind of server config to point to those CSS files, then I'm not seeing it.
I am leaving this post as unsolved in case someone agrees with me that this is a bug at worst or is not intuitive and should be documented at best.
From the comments by user3208130:
Sorry for not following up for all this time. i did finally work
around the problem by not importing anything. I copied the main
gridx.css from gridx\resources into my project, and then for each of
the imports listed in that file, i copy/pasted the source from the
various locations within the gridx collection as well as all of the
claro css files since gridx only uses that font. i had to turn off
theme switching depending on the device since claro looks awful on
windows8 and android otherwise.
I know this makes no sense, but i tried every variation of relative and explicit path that i could imagine for the import
statements in both of the html header and within the main css files
and nothing else worked. i suspected that the css files are not copied
automatically when device environments are created but i couldn't
prove that.

Running Dojo on RequireJS

I am using Dojo 1.9.1 and RequireJS
I implemented it using this code:
<script src="require.js"></script>
<script type="text/javascript">
requirejs.config({
baseUrl: location.pathname.replace(/\/[^/]+$/, '') + '/js/', // magic!
packages: [
{
name: 'dojo',
location: "http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/"
}
]
});
</script>
...
..
<script>
require(["dojo/domReady!"], function() {
......
});
</script>
it will throw some exceptions about has.js not work correctly
Uncaught TypeError: Object function (){} has no method 'add' has.js:8
Uncaught Error: Load timeout for modules: dojo/domReady!_unnormalized2
Does any one have an explanation, or an idea about how to solve it?
The CDN version of Dojo is built assuming that you are using the Dojo loader in order to decrease code size. Part of the code removal is the alternative has.js implementation that is used if a loader doesn’t include one (like RequireJS). You can use a regular downloaded version of Dojo with RequireJS and it will work fine, but you can’t use the CDN version.

Including dojo/dom library to Spring Roo

How is it possible to include and use the dojo/dom library in Spring roo.
This:
<script type="text/javascript">
dojo.require('dojo/dom');
dojo.ready(function remAttr(){
dojo.removeAttr('theId', 'value');
}
);
</script>
results in:
"NetworkError: 404 Introuvable - http://localhost:8131/suivitrc/resources/dojo/dom.js"
dom.js
Could not load 'dojo/dom'; last tried '../dojo/dom.js'
Can anyone please help?
I think the version of dojo in roo is currently less than 1.7. This means you can remove the following line from your code because the remoteAttr function is part of dojo.js:
dojo.require('dojo/dom');
see here: http://dojotoolkit.org/reference-guide/1.7/dojo/removeAttr.html
The namespace => to module path is retreived by replacing periods (.), in short - you need to replace the slash with a dot. Your require should be
dojo.require('dojo.dom'); // blocking call? djConfig.async must be false
Since the error is in regards to the dojo.require specified path, this means your dojo.js is found and loaded (dojo.require is not undefined) - and baseUrl is not of concern to dojo modules.
The thing is, youre using the legacy loader to pull in an AMD module, in 1.7+ the require statement has a different look to it.
// AMD loader form is
function callbackFunctionOnComplete(dojoDom) { }
require([ "dojo/dom" ], callbackFunctionOnComplete); // non-blocking
So, how dojo.require works is following, assume that the parameter we pass as string is called 'module;
dojo.require = function(module) {
var parts = module.split('.');
1 - get toplevel namespace (global)
var packageName = parts.shift(); // first part is the package name
2 - get the filename (minus .js)
var id = parts.pop(); // the last bit
3 - translate everything in between to a path (relative to packagelocation)
var mid = parts.join("/");
4 - lookup package (from toplevel) location
var fullpath = // in pseudo
foreach dojoconfig.packages
iff obj.name == packageName
set to obj.location
5 append the rest and start downloading module
fullpath += mid + id + '.js'
transport.get(..... fullpath .....)
You need to configure dojo with dojo config. I prefer the form explained here:
http://dojotoolkit.org/reference-guide/1.7/dojo/_base/config.html#explicitly-creating-a-dojoconfig-object-before-including-the-dojo-core.
And you need to tell dojo where to find its stuff. An example:
var dojoConfig =
{
baseUrl : "/yourApp/js", // defines the js folder in your webapp
tlmSiblingOfDojo: false,
async: true,
parseOnLoad:true,
packages: [
{ name: "app", location: "app"}, // where it is in the js folder
{ name: "dojo", location: "lib/dojo" }, // where it is in the js folder
{ name: "dijit", location: "lib/dijit" },
{ name: "dojox", location: "lib/dojox" }
]
};
Also the require form you are using is deprecated. See http://livedocs.dojotoolkit.org/dojo/require