How to Create a Custom Dojo Component

I published an article about how to create custom Dojo components in Wazi. This article shows you how to create a custom Dojo component from scratch. It illustrates very important concepts like the dojo attach point, the widget structure, and the widget template. I wish you will enjoy this article: http://olex.openlogic.com/wazi/2012/how-to-create-a-custom-dojo-component/.

Iterate over a JSON object

One of the most useful advantages of the JSON format is that it is browser friendly. You donot need to write complicated code for navigating or iterating over a JSON structure. In this post, I will show you how to iterate over a JSON object.

Assume that you are having the following JSON object.

<script type="text/javascript">
var personStr = "{\"Name\":\"Hazem Saleh\",\"Occupation\":\"Software Engineer\",\"Nationality\":\"Egyptian\",\"Age\":\"102\"}";

var personObject = eval("(" + personStr + ")");
</script>

You may notice that I put the JavaScript String between parentheses. This is mandatory to avoid the json invalid label browser error.

if you want to simply iterate over the JSON object you should use the standard JavaScript for in loop as follows.

<script type="text/javascript">
for (var key in personObject) {
  if (personObject.hasOwnProperty(key)) {
    alert(key + " -> " + personObject[key]);
  }
}
</script>

I wish that this tip can be helpful to you.

Java encoding similiar to JavaScript encodeURIComponent

You may have a REST service that returns an encoded output to a JavaScript client which decodes this output in the client side. Unfortunately, this scenario will not always work because of the mismatch between both the Java java.net.URLEncoder encode() API and the JavaScript encodeURIComponent().

To be able to make the java.net.URLEncoder encode() behavior equivalent to the JavaScript encodeURIComponent(), all what you should do is the following String replacements.

public static String encodeURIComponent(String component)   {     
	String result = null;      
	
	try {       
		result = URLEncoder.encode(component, "UTF-8")   
			   .replaceAll("\\%28", "(")                          
			   .replaceAll("\\%29", ")")   		
			   .replaceAll("\\+", "%20")                          
			   .replaceAll("\\%27", "'")   			   
			   .replaceAll("\\%21", "!")
			   .replaceAll("\\%7E", "~");     
	catch (UnsupportedEncodingException e) {       
		result = component;     
	}      
	
	return result;   
}   

After that you can safely decode the output in the client side using the JavaScript decodeURIComponent().

References:

http://stackoverflow.com/questions/607176/java-equivalent-to-javascripts-encodeuricomponent-that-produces-identical-outpu

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURIComponent

http://docs.oracle.com/javase/1.4.2/docs/api/java/net/URLEncoder.html

Refreshing Dijit tree in Dojo (code that works)

Refreshing the Dijit tree in Dojo with a new data store does not have a ready-made API in Dojo (Iam talking about Dojo 1.4). In this post, I will show a technique with example that will illustrate how to refresh the Dijit tree with a new data store.

The solution is about extending the dijit.Tree to support this feature as shown in the refreshModel method.

<script type="text/javascript">// <![CDATA[
	dojo.extend(dijit.Tree, {
		refreshModel: function () {

			// reset the itemNodes Map
			this._itemNodesMap = {};

			// reset the state of the rootNode
			this.rootNode.state = "UNCHECKED";

			// Nullify the tree.model's root-children
			this.model.root.children = null;

			// remove the rootNode
			if (this.rootNode) {
				this.rootNode.destroyRecursive();
			}

			// reload the tree
			this._load();
		}
	});
// ]]></script>

Let’s see now an example of refreshing the tree using this new introduced API.


	

<button id="refreshTreeButton" class="buttonClass" onclick="refreshTreeInformation();" type="button">Refresh Tree</button><script type="text/javascript">// <![CDATA[
	dojo.addOnLoad(function() {	
		var store = new dojo.data.ItemFileWriteStore({
			url: "sampleData.json"
		});				

		var treeModel = new dijit.tree.ForestStoreModel({
			store: store,
			query: {"type": "parent"},
			rootId: "root",
			rootLabel: "Groups",
			childrenAttrs: ["children"]
		});

		var treeObject = new dijit.Tree({
			model: treeModel
		}, "treeDiv");
	});

	function refreshTreeInformation() {		
		var treeObject = dijit.byId("treeDiv");
		var newStore = new dojo.data.ItemFileWriteStore({
			url: "sampleData2.json"
		});						

		treeObject.model.store = newStore;		
		treeObject.model.query = {"type": "parent"};	
		treeObject.rootId = "root";	
		treeObject.rootLabel = "Groups";	
		treeObject.childrenAttrs = ["children"];						

		treeObject.refreshModel();
	}			
// ]]></script>

In the refreshTreeInformation function, the tree object is retrieved, a new store is loaded, and assigned to the tree model object. Finally calling the refreshModel method will make the displayed tree insync with the underlying model. you can download the code from here.

I wish this tip can help.

Getting the Selected Dijit Tree node in Dojo

This post shows you how to get the selected node in a Dijit tree.

Let’s assume we have the following dijit tree data store.

{
"identifier":"id",
"label":"name",
"items":[
{
	"type": "parent",
	"name": "Countries",
	"id": "countries",
	"children":[
		{"type":"Leaf", "name":"Country 1", "id":"country1"},
		{"type":"Leaf", "name":"Country 2", "id":"country2"},
		{"type":"Leaf", "name":"Country 3", "id":"country3"},
		{"type":"Leaf", "name":"Country 4", "id":"country4"},
		{"type":"Leaf", "name":"Country 5", "id":"country5"},
		{"type":"Leaf", "name":"Country 6", "id":"country6"}
	]
}]}

Using the following JavaScript code the tree is loaded with the desired hierarchy.

<script type="text/javascript">// <![CDATA[
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require("dijit.Tree");
dojo.require("dijit.tree.ForestStoreModel");				

var store = new dojo.data.ItemFileWriteStore({
	url: "sampleData.JSON"
});

var treeModel = new dijit.tree.ForestStoreModel({
	store: store,
	query: {"type": "parent"},
	rootId: "root",
	rootLabel: "Groups",
	childrenAttrs: ["children"]
});

var treeObject = new dijit.Tree({
	model: treeModel
}, "treeDiv");

//...
// ]]></script>

In order to get the selected tree node object you should use the “selectedItem” attribute in the Dijit tree object as follows

dijit.byId("[Tree Node ID]").attr("selectedItem");

In our example to show the id of the selected leaf node when clicking the “Get Selected Node” button, the following code will do the job:

if (dijit.byId("treeDiv").attr("selectedItem") != null) {
	if (dijit.byId("treeDiv").attr("selectedItem").type == "Leaf") {
		document.getElementById("selectedNode").innerHTML =
                "Selected Node is " + dijit.byId("treeDiv").attr("selectedItem").id;
	}
}

This code is tested in Dojo 1.4 environment. download the code from here.

Accessing parent window elements from child window in JavaScript

In JavaScript you can access the parent window elements from the child window. Let’s see an example. Let’s assume that the parent page code is as follows:

<html>
    <head>
        <title>Parent Window</title>
    </head>
    <body>   
	<input type="text" id="data" value="23444" />
	<a href="#" onclick="javascript:openChildWindow();">Open Child Popup window</a>
    </body>
    <script>
	function openChildWindow() {
		window.open('child.htm','childWindow','width=400,height=400');		
	}
    </script>
</html>

The hyperlink in the parent window opens a new child window using the window.open JavaScript API.

In the child window, Let’s see how to access the "data" input field of the parent window.

<html>
    <head>
        <title>Child Window</title>
    </head>
    <body onload="initializeMainDiv();">   
		<div id="mainDiv"></div>
    </body>
    <script>
	function initializeMainDiv() {
		document.getElementById("mainDiv").innerHTML = "Parent window data field value is: " + 
			window.opener.document.getElementById("data").value
	}
    </script>
</html>

In the child window, when the page is initialized, the "data" input field of the parent window is accessed through the window.opener JavaScript API.

window.open Invalid argument in IE

You may face the following error message in IE while working with the window.open JavaScript API:

Message: Invalid argument.
Line: 21
Char: 4
Code: 0
URI: ...

This error happens because IE does not allow spaces in the window name, for example the following code will cause the invalid argument error in IE:

window.open('test.htm','New Window','width=400,height=400');

To resolve this error, the solution is simple just remove the spaces from the window name and it will work fine:

window.open('test.htm','NewWindow','width=400,height=400');

Finally, the other interesting fact is that IE does not allow the window name to have dashes “-“, so you have to remove it from the window name to make the window.open API working fine in IE.

TypeError: this._arrayOfTopLevelItems is undefined

You may find this Dojo error when you are trying to create a JSON store object from a JSON string as follows:

var store = new dojo.data.ItemFileWriteStore({
	data: jsonString
});		

To resolve this issue, all what you should do is to convert the json string to a json object by using the dojo.fromJson as follows:

var store = new dojo.data.ItemFileWriteStore({
	data: dojo.fromJson(jsonString)
});

Reading the Dojo DateTextBox in your custom format

In Dojo 1.4, you can use the DateTextBox component for showing an input calendar for the user, as follows:

<label for="sampleDate">Select the Date: </label>
<input id="sampleDate" dojoType="dijit.form.DateTextBox"></input>
<button id="sampleButton" class="buttonClass" id="getDateValue" 
dojoType="dijit.form.Button" type="button" 
onclick="getDateValue();">Get Date Value</button>

However, getting the date value using the value property dijit.byId("sampleDate").value will result in a value like this:

Wed Nov 30 2011 00:00:00 GMT+0200

If you want to simply format the date object in the “yyyy-MM-dd” format (for example), you can use the dojo.date.locale.format as follows:

dojo.date.locale.format(dijit.byId("sampleDate").value, {datePattern: "yyyy-MM-dd", selector: "date"})

The complete getDateValue JavaScript function is as follows:

<script type="text/javascript">
function getDateValue() {
    alert("Default Date: " + dijit.byId("sampleDate").value);
    alert("Formatted Date: " + dojo.date.locale.format(dijit.byId("sampleDate").value, 
    {datePattern: "yyyy-MM-dd", selector: "date"}));
}
</script>

I wish that this tip can be useful to you.