Dojo - Issue loading widget cross-domain - dojo

I'm working on a project that requires that some custom Dojo widgets (i.e., widgets we have written ourselves) are loaded from another server. Despite my best efforts over several days, I cannot seem to get Dojo to load the widgets.
Dojo is loaded from the Google CDN, the widget is loaded from www.example.com, and the website is located at www.foo.com.
I cannot post the actual project files (this is a project for a company), but I have reproduced the error with smaller test files.
Test.html (on www.foo.com):
<html>
<div id="content"></div>
<script>
var djConfig = {
isDebug: true,
modulePaths: {
'com.example': 'http://example.com/some/path/com.example'
}
}
</script>
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.4.3/dojo/dojo.xd.js.uncompressed.js"></script>
<script type="text/javascript">
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.addOnLoad(function() {
dojo.require("com.example.widget.Test", false);
dojo.addOnLoad(function() {
new com.example.widget.Test().placeAt(dojo.byId('content'));
});
});
</script>
</html>
Test.xd.js (at www.example.com/some/path/com.example/widget/Test.xd.js):
dojo.provide("com.example.widget.Test");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare("com.example.widget.Test", [dijit._Widget, dijit._Templated], {
templateString: "<div dojoAttachPoint=\"div\">This is a test</div>",
postCreate: function() {
console.log("In postCreate");
console.log(this.div);
this.div.innerHTML += '!!!';
}
});
In Firebug, I am seeing an error after a delay of a few seconds saying that the cross-domain resource com.example.widget.Test cannot be loaded. However, in the 'Net' tab I am able to see that Test.xd.js is successfully downloaded, and I am able to set a breakpoint and see that the dojo.declare executes and completes without error.
I appreciate any help. Please let me know if there is any other information I can provide.

There is a different way for handling the module declarations in XD-loader. This is due to how the loader handles 'module-ready' event. You will most likely experience, that the dojo.addOnLoad never runs, since it 'knows' that certainly - some required modules are not declared.
Even so, they may very well be declared - and the change in 1.7+ versions of dojotoolkit seem to reckognize that fact. The reason for this, i believe, is that the mechanism for 'module-ready' is not implemented correctly in your myModule.xd.js modules.
It is basically a 'header' or 'closure' of the declaration, involving a few steps - wrapping everything in your basic module from dojo.provide and eof
Standard example boiler module file '{{modulePath}}/my/Tree.js'
dojo.provide("my.Tree");
dojo.require("dijit.Tree");
dojo.declare("my.Tree", dijit.Tree, {
// class definition
});
X-Domain example boiler module file '{{modulePath}}/my/Tree.xd.js
dojo._xdResourceLoaded(function(){
return {
depends: [
["provide", "my.Tree"],
["require", "dijit.Tree"]
],
defineResource: function(dojo) {
///////////////////////////////
/// Begin standard declaration
dojo.provide("my.Tree");
dojo.require("dijit.Tree");
dojo.declare("my.Tree", dijit.Tree, {
// class definition
});
/// End standard declaration
///////////////////////////////
}
}
})();

Related

dojo i want to know same function that jquery $(document).ready() in dojo

I have to perform some functions before load a html Page. jquery's $ (document). ready () is executed before the html Page be loaded. But I do not know that dojo have same function. Please advise me
Your question is unclear to me, when you write:
$(document).ready(function() {
// Your code
});
Then that code is only executed after the page is loaded + rendered and not before (like you said).
That being said, Dojo has a similar module called dojo/domReady!. You can use it in two ways, for example:
require([ "dojo/domReady!" ], function() {
// Your code
});
Now the code is only being executed after the page is loaded + rendered (just like the jQuery .ready() function).
If you also want to wait until all widgets are parsed, then you have to use the dojo/ready module:
require([ "dojo/ready" ], function(ready) {
ready(function() {
// Your code
});
});
Now that code is only executed after the page is loaded + rendered and if parseOnLoad is enabled, it will also wait until all declarative widgets on that page are parsed.
More information can be found in the reference guide.

understanding dojo AMD loading- functions are undefined

I have been trying to get someone to explain to me how the dojo AMD loading works and to get a simple piece of code to work. I understand that if using for example the CDN, one has to call the dojo library and load all modules you wish to use. I have tried to implement other javascript functions based on activity from the main page and I will always get the function either undefined or an error related to a dojo control undefined. It seems that all the modules that initially load are not available to the rest of the code. Any helpful explanations would be really appreciated.
<link rel="stylesheet" type=
"text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dojo/resources
/dojo.css" />
<link rel="stylesheet" type=
"text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dijit/themes/
tundra/tundra.css" />
<link rel="stylesheet" type=
"text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dojox/mobile/themes/
iphone/iphone.css" />
<title> DOJO </title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/
dojo/dojo.js"
data-dojo-config="async:true"></script>
<script type="text/javascript" src="Scripts/login.js"></script>
<script type="text/javascript">
require(["dojox/mobile/parser",
"dojo/parser",
"dojo/on",
"dojo/request/xhr",
"dijit/form/Form",
"dojo/store/Observable",
"dojo/store/Memory",
"dijit/Toolbar",
"dijit/Dialog",
"dojo/io/script",
"dojo/query",
"dojo/_base/lang",
"dijit/layout/ContentPane",
"dojox/mobile/Button",
"dojox/mobile/deviceTheme",
"dojox/mobile/compat",
"dojox/mobile/Heading",
"dojox/mobile/TextBox",
"dojox/mobile/Opener",
"dijit/form/TextBox",
"dijit/form/HorizontalSlider",
"dijit/form/ValidationTextBox",
"dijit/Calendar",
"dojox/mobile/ScrollableView",
"dojo/dom",
"dojo/domReady!",
"dojox/mobile"],
function (dom, domReady ,mobile, ScrollableView,
parser, query, domClass, domStyle, on, event, xhr,Form,
lang, Button, deviceTheme, compat, Heading) {
dojox.mobile.parser.parse();
});
</script>
From my understanding is that the way I have the code above is that my interface will load correctly and all widgets in the body of html will be displayed and it works fine. The problem is that I have a form that gets input from the user and on a button click event calls a function that handles the webrequests. I could not get this to work and it is merely a problem with where I am placing this function. I have added a simplified version:
What I have done is add that function to a script file to separate it from the rest of the code:
var dojoXhr;
function correctInput(div, td, msg) {
dojo.domStyle.set(div, 'display', '');
td.innerHTML = msg;
}
require(["dojo/_base/declare", "dojo/parser", "dojo/query", "dojo/dom-class",
"dojo/dom-style", "dojo/on",
"dojo/_base/event",
"dojo/request/xhr", "dijit/form/ValidationTextBox", "dojo/domReady!"],
function chklogin(declare, parser, query, dom-class, dom-style,
on, event, xhr,ValidationTextBox, domReady) {
var lname = dijit.byId('login').get('value');
var psswd = dijit.byId('password').get('value');
var feedback = document.getElementById('feedback');
var feedbackTD = dojo.query('td.feedback')[0];
if (lname == '' || psswd == '') {
correctInput(feedback, feedbackTD, 'Please enter a valid login!');
dojo.domStyle.set(feedback, 'display', '');
dojo.domStyle.set(document.getElementById('msgBodyOutter'), 'display', 'none');
feedbackTD.innerHTML = "Please enter a valid login!";
return;
}
if (!(lname == 'login') || !(psswd == 'password')) {
correctInput(feedback, feedbackTD, 'Please enter a valid login!');
return;
}
else {
dojo.domStyle.set(feedback, 'display', '');
dojo.domStyle.set(document.getElementById('msgBodyOutter'), 'display', 'none');
feedbackTD.innerHTML = "THATS IT BRO!";
return;
}
});
I got advice on the dojo forum to put my function in a define function and then use a require to call it all. I could not figure out how to do this.
It seems that all the modules that initially load are not available to
the rest of the code.
You are using a CDN to load the dojo toolkit. When you use CDN you are required to define the location of the module packages. You need to edit the dojoConfig for the code to work.
See this article about Using Custom Modules with a CDN. The important part is the packages object.
<script data-dojo-config="async: 1, dojoBlankHtmlUrl: '/blank.html',
packages: [ {
name: 'custom',
location: location.pathname.replace(/\/[^/]+$/, '') + '/js/custom'
} ]"
src="//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js">
</script>
Edit: Below is a simple dojo application.
So in my case create a module called chklogin, then require it, and
when the user clicks the button it will call that module chklogin from
within the main require[] function. Correct?
I would say yes. You are correct. I think your concept is a viable option. I hope this example helps with implementing define() to create your own modules. I will try to help where I can as you develop your idea. You can download the project here while available.
Directory Structure:
/index.html
/js/config.js
/js/controller/Controller.js
/js/modules/MyFirstModule.js
/index.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css">
<script src="js/config.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js"></script>
<script>
require(["app/Controller", "dojo/domReady!"], function(Controller) {
//Initiate the entire application by calling main method of our Controller class.
Controller.main();
//Call our getter method of the Controller class to show how to access a private variable.
console.log(Controller.getWelcomeMessage());
});
</script>
</head>
<body class="claro" id="appBody"></body>
</html>
/js/config.js
We use packages to reference the CDN dojo files. Now we can call dojo classes by our package name
For example, "dojo/domReady!", "dijit/form/Button", "dojox/app/main". The dojo files
are stored on the google servers, which is referenced by the
<script src='http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js'>< /script>
in the index.html file.
Here we create our own custom packages. This could be for your modules, widgets, etc. The package
locations will map to the javascript directory that you store your custom dojo files in.
For example, myModules can be found in the /js/modules directory. You will reference any custom
dojo files via "myModules/MyModule", which locates and loads "/myModules/MyModule.js" file.
For an explanation of the baseURL, see: http://dojotoolkit.org/documentation/tutorials/1.9/hello_dojo/
"Defining and Requiring Modules". This code registers the correct location of our own packages so
we can load Dojo from the CDN whilst still being able to load local modules.
I created a package called "app" as you can see below. This is how I initialize my app in my project.
This was designed to allow me to keep the separation of code the best I know how. It is loaded and
called in the index.html page. So i give it a package name of app. It is physically located in the
js/controller/Controller.js file.
This dojoConfig object is used in the index.html and must be loaded prior to < script src='...dojo.js' > tag.
var dojoConfig = {
async: true,
tlmSiblingOfDojo: false,
baseUrl: location.pathname.replace(/\/[^/]*$/, ''),
packages: [
{ name: "myModules", location: "js/modules" },
{ name: "app", location: "js/controller", main: "Controller" }
]
};
if you choose to host the dojo files on your own server, you can reference them like below. Assuming the dojo js files are located in the "/js/dojo/*" directory.
packages: [
{ name: "dojo", location: "dojo/dojo" },
{ name: "dijit", location: "dojo/dijit" },
{ name: "dojox", location: "dojo/dojox" },
{ name: "myModules", location: "js/modules" },
{ name: "app", location: "js/controller", main: "Controller" }
]
/js/controller/Controller.js
Here is the controller which I use to initialize the web app.
define(["myModules/MyFirstModule"], function(MyFirstModule) {
//Private Variables...
var privateVariable1 = "Welcome to my Dojo Application!";
var privateVariable2;
/**
* init. This is a private function that is only available within this object.
*/
init = function() {
// proceed directly with startup
console.log("Startup functions are firing...");
//Render our "form" which only contains a single text box.
renderForm();
},
renderForm = function() {
MyFirstModule.createForm("appBody");
}
/**
* Enclose all public methods in the return object
*/
return {
/**
* main. This is a public function that can be called from other code.
*/
main: function() {
//Run init() method.
init();
},
/**
* getWelcomeMessage. This public function returns the value of the privateVariable1.
* This mimics a getter method.
*/
getWelcomeMessage: function() {
return privateVariable1;
}
};
}); //end define
/js/modules/MyFirstModule.js
This is an example of a custom Module. It is required by the Controller class as a dependency.
define([
//The required dependencies for this module.
"dojo/dom", "dojo/on", "dijit/form/TextBox", "dijit/form/Button"
], function(dom, on, TextBox, Button){
// Once all modules in the dependency list have loaded, this
// function is called to define the myModules/myFirstModule module.
//
// The dojo/dom module is passed as the first argument to this
// function; additional modules in the dependency list would be
// passed in as subsequent arguments (on, TextBox, and Button).
// Private variables
var firstNameTextBox;
var submitButton;
privateFunction = function() {
console.log("I am a private function. I can only be called from this class.");
};
// This returned object becomes the defined value of this module when called elsewhere.
return {
/**
* createForm. This method creates a simple form. Textbox and button.
* #param placeMeHere This is where to place the form elements. In this demo, the are placed in the
* body of the html document. This is executed in the Controller class.
*/
createForm: function(placeMeHere) {
//Create new TextBox.
firstNameTextBox = new TextBox({
name: "firstname",
value: "" /* no or empty value! */,
placeHolder: "type in your name"
}, "firstname");
//Place me in the DOM.
firstNameTextBox.placeAt(placeMeHere);
//Render
firstNameTextBox.startup();
//Create Button
submitButton = new Button({
label: "Say Hi"
}, "submitButton");
submitButton.placeAt(placeMeHere);
submitButton.startup();
//Greet the user.
on(submitButton, "click", function(evt){
console.log("Hi there, " + firstNameTextBox.get("value"));
});
}
};
});

on reloading/refreshing the page the dojo/ready function is not called

When refreshing/reloading a page, the dojo/ready function is not called, so the page is not loaded properly. Sometimes it is working properly; some times not.
window.onload = function() {
setTimeout(function(){document.body.style.opacity="100";},100);
require(["dojo/ready"], function(ready){
ready(function(){
alert("ready");
});
});
};
This is my window onload code. Sometimes I am getting the alert ready, sometimes not. I cannot figure out the issue.
Thanks in advance
I'd suggest to not use window.onload.
Instead, include your script as a js file like this:
<script type="text/javascript" src="/appRoot/js/my.js"></script>
Then in your my.js file:
require([ "dojo", "dojo/domReady!" ], function(dojo) {
// Code in here will be run only when the page is ready.
});
I am using this with dojo 1.7, but this is valid through 1.9.
See also the dojo/domReady! documentation.

Getting Unknown Provider error when injecting a Service into an Angular unit test

I'm fairly new to Angular and have reviewed all the similarly related questions on Stack Overflow but none have helped me. I believe I have everything set up correctly but am still getting an 'Unknown Provider' error when attempting to inject a service into a unit test. I have laid out my code below - hopefully someone can spot an obvious error!
I define my modules in a seperate .js file like this:
angular.module('dashboard.services', []);
angular.module('dashboard.controllers', []);
Here is where I define a service called EventingService (with logic removed for brevity):
angular.module('dashboard.services').factory('EventingService', [function () {
//Service logic here
}]);
Here is my controller that uses the EventingService (this all works fine at runtime):
angular.module('dashboard.controllers')
.controller('Browse', ['$scope', 'EventingService', function ($scope, eventing) {
//Controller logic here
}]);
Here is my unit test - its the line where I attempt to inject the EventingService that causes an error when I run the unit test:
describe('Browse Controller Tests.', function () {
beforeEach(function () {
module('dashboard.services');
module('dashboard.controllers');
});
var controller, scope, eventingService;
beforeEach(inject(function ($controller, $rootScope, EventingService) {
scope = $rootScope.$new();
eventingService = EventingService
controller = $controller('Browse', {
$scope: scope,
eventing: eventingService
});
}));
it('Expect True to be True', function () {
expect(true).toBe(true);
});
});
When I run the test I get this error:
Error: Unknown provider: EventingServiceProvider <- EventingService
I have ensured that my jasmine specrunner.html file has all the necessary source files (this is an Asp.Net MVC project):
<!-- Include source files here... -->
#Scripts.Render("~/bundles/jquery")
<script type="text/javascript" src="#Url.Content("~/Scripts/angular.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Scripts/angular-mocks.js")"></script>
<script type="text/javascript" src="#Url.Content("~/App/scripts/app.js")"></script> <!-- Angular modules defined in here -->
<script type="text/javascript" src="#Url.Content("~/App/scripts/services/eventing.js")"></script> <!-- My Eventing service defined here -->
<script type="text/javascript" src="#Url.Content("~/App/scripts/controllers/browse.js")"></script> <!-- My Browse controller defined here -->
<!-- Include spec files here... -->
<script type="text/javascript" src="#Url.Content("~/App/tests/browse.js")"></script> <!-- The actual unit test here -->
I just can not fathom why Angular is throwing this error complaining about my EventingService. My controller works fine at runtime - it's just when I try to test it that I am getting an error so I am curious as to whether I have screwed something up with the mocking/injection.
The Angular help on testing is rubbish so I am stumped at present - any help or suggestions anyone can give would be very appreciated. Thanks.
I just ran into this and solved it by switching to getting the service using the $injector explicitly:
var EventingService, $rootScope;
beforeEach(inject(function($injector) {
EventingService = $injector.get('EventingService');
$rootScope = $injector.get('$rootScope');
}));
I wish I could tell you why this works and why the simple
beforeEach(inject(function(EventingService) { .... }));
does not, but I don't have the time to investigate the internals. Always best to use one coding style and stick to it.
This style is better in that the name of the variable that you use in your tests is the correct name of the Service. But it is a bit verbose.
There is another angular magic feature that uses strange variable names like $rootScope but I don't like the hacky look of that.
Note that the most of the time people get this error because they didn't include the modules:
beforeEach(module('capsuling'));
beforeEach(module('capsuling.capsules.services'));
If your controllers (defined under dashboard.controllers module) depend on some services which are enclosed in different module (dashboard.services) than you need to reference the dependency modules in your module signature:
angular.module('dashboard.services', []);
angular.module('dashboard.controllers', ['dashboard.services']);
While this question is fairly old i lost significant time solving a problem similar to this one, i.e.:
Error: Unknown provider: SomeServiceProvider <- SomeService
Hence, i'm leaving here another possible cause to this issue. Hopefully, it would helpful to someone.
In my case, i had in my project two modules with the exactly same name but with different dependencies being created, i.e., two different .js files with:
angular.module('moduleName', [dependencies]))
From angular documentation:
Passing one argument retrieves an existing angular.Module, whereas passing more than one argument creates a new angular.Module
Conclusion: It turns out that what was being injected in the test was the module with the wrong dependencies. Removing the second argument from the module that was erroneously being created solved the problem.
Have you tried defining an additional module that depends on your other aggregated modules like so:
angular.module( 'dashboard', [ 'dashboard.services', 'dashboard.controllers' ] )
So you can in the beforeEach specify the one module that has both submodules defined in it like so:
describe('Browse Controller Tests.', function () {
beforeEach(function () {
module('dashboard');
});
var controller, scope, eventingService;
beforeEach(inject(function ($controller, $rootScope, EventingService) {
scope = $rootScope.$new();
eventingService = EventingService
controller = $controller('Browse', {
$scope: scope,
eventing: eventingService
});
}));
it('Expect True to be True', function () {
expect(true).toBe(true);
});
});

dojo 1.8: create widget and startup upon dojo/on

Hi I am looking for tutorial based on Dojo 1.8.
What I am looking for is:- create and instantiate widget pragmatically after dojo page fully loaded and parsed, triggered after dojo/on button. I am not sure of which tutorial in Dojo website, for me to learn.
Please advise.
Thanks in advance.
Clement
There isn't one tutorial that fully answer all your question but the following will be helpful:
Dojo Events tutorial and dojo/on reference
dojo/ready reference
dojo/parser reference
To capture both the full loading of the page and parsing you need to use a combination of dojo/ready and dojo/parser. (I'm assuming that the parsing you refer to is the dojo widget parser, rather than the standard browser parsing of HTML).
To run code after parsing you'll need to add parseOnLoad: false to your dojoConfig and run the parser manually; otherwise, there is no way of capturing when it is complete.
<script type="text/javascript" async="true">
require([
"dojo/ready",
"dojo/parser",
"dojo/on,
"dojo/query"
], function(
ready, parser, on, $
){
ready(function(){
// Only run after the page is fully loaded
parser.parse().then(function(instances){
// Only run after parser has parsed the page
var myButton = $("#myButtonid"); // Find your button
if(myButton.length > 0){ // Check button is found
on(myButton[0], "click", function(evt){
// ... add your code here to create and
// instantiate widget
});
}
});
});
}
</script>
Don't forget that you need to turn off automatic parsing of widgets in you dojoConfig, hence, something like this (in the head):
<script type="text/javascript">
dojoConfig= {
"parseOnLoad": false,
"async": true
// ...other settings
};
</script>