Login Register

The Memo

Overview

This page serves as an introduction to the art and science of creating one's own dojo widgets, and invoking them in html code just like mainstream Dojo widgets.

The following walk through will take you through all the steps needed to create a simple widget, ie a widget that contains only dom elements, not any nested dojo widgets.

Following this walk through are some instructions for creating compound widgets (ie, widgets that include other dojo widgets).

Getting Started

Let's say that you want to make a memo widget. Just a yellow sticky note to remind yourself of your dentist appointment, or whatever. Something that you can put on the screen and then erase later. Something so that a call like this:

<div dojoType="Memo" title="Reminder">
	Pick up milk on the way home
</div>

will produce something that looks like this:

Reminder
X
Pick up milk on the way home.

The Template

The first step is to write HTML and CSS that prototypes how the widget will look. You can do this in any editor of your choice. I made the prototype above using this HTML:

<div class="memo">
  <div class="title">Reminder</div>
  <div class="close">X</div>
  <div class="contents">Pick up milk on the way home.</div>
</div>

And this CSS:

.memo {
	background: yellow;
	font-family: cursive;
	width: 10em;
}

.title {
	font-weight: bold;
	text-decoration: underline;
	float: left;
}

.close {
	float: right;
	background: black;
	color: yellow;
	font-size: x-small;
	cursor: pointer;
}

.contents {
	clear: both;
	font-style: italic;
}

Note how I put as much of the formatting code into the CSS. This isn't necessary, but it does make it easier for other people to customize the widget, merely by altering the CSS.

Turning it into a widget

To make this memo into a widget, you need to declare a javascript object that connects with the HTML and CSS template above. So, put the HTML in a file called Memo.html, the CSS in a file called Memo.css, and make the Memo.js file below:

dojo.widget.defineWidget(
	// widget name and class
	"acme.widget.Memo",
	
	// superclass
	dojo.widget.HtmlWidget,
	
	// properties and methods
	{
		templatePath: dojo.uri.dojoUri("../acme/widget/Memo.html"),
		templateCssPath: dojo.uri.dojoUri("../acme/widget/Memo.css")
	}
);

Contents and Parameters

The obvious problem with this widget is that no matter what is inside the source div, it always says "Pick up milk on the way home". What you need is for the contents of the source div to be inserted into the generated output. This is what the "containerNode" is for, and you use it like this...

First, in the template, get rid of the static content, and instead mark that the div should hold the content from the source.

<div class="memo">
  <div class="title">Reminder</div>
  <div class="close">X</div>
  <div class="contents" dojoAttachPoint="containerNode"></div>
</div>

Then, in the javascript object, denote that this widget is a container:

dojo.widget.defineWidget(
	// widget name and class
	"acme.widget.Memo",

	// superclass
	dojo.widget.HtmlWidget,
	
	// properties and methods
	{
		isContainer: true,
		templatePath: dojo.uri.dojoUri("../acme/widget/Memo.html"),
		templateCssPath: dojo.uri.dojoUri("../acme/widget/Memo.css")
	}
);

OK, what about the title? The title is specified as an attribute:

<div dojoType="Memo" title="Reminder">
	Pick up milk on the way home
</div>

That means that it's a parameter to the widget. Parameters are specified as normal widget properties. In this case, the widget properties would look like this:

	// properties and methods
	{

		// parameters
		title: "Note",

		// settings
		isContainer: true,
		templatePath: dojo.uri.dojoUri("../acme/widget/Memo.html"),
		templateCssPath: dojo.uri.dojoUri("../acme/widget/Memo.css")
	}

This widget now has a "title" parameter, with a default value of "Note"

How do you stick this parameter's value into the widget? Luckily widget templates have variable substitution, so no coding is necessary. Just modify the template to use this parameter:

<div class="memo">
  <div class="title">${this.title}</div>
  <div class="close">X</div>
  <div class="contents" dojoAttachPoint="containerNode"></div>
</div>

Events

OK, the content of the widget is showing up correctly, but how to you make clicking the X cause the widget to disappear? It's pretty simple, and hardly requires any javascript. The first step is to modify the template to handle click events on the X:

<div class="memo">
  <div class="title">${this.title}</div>
  <div class="close" dojoAttachEvent="onClick">X</div>
  <div class="contents" dojoAttachPoint="containerNode"></div>
</div>

Then you simply add a method to the widget javascript object to handle the click:

		onClick: function(evt){
			this.destroy();
		}

That's it! Your first functioning widget!

Final code

Memo.html

<div class="memo">
  <div class="title">${this.title}</div>
  <div class="close" dojoAttachEvent="onClick">X</div>
  <div class="contents" dojoAttachPoint="containerNode"></div>
</div>

Memo.css

.memo {
	background: yellow;
	font-family: cursive;
	width: 10em;
}

.title {
	font-weight: bold;
	text-decoration: underline;
	float: left;
}

.close {
	float: right;
	background: black;
	color: yellow;
	font-size: x-small;
	cursor: pointer;
}

.contents {
	clear: both;
	font-style: italic;
}

Memo.js

dojo.widget.defineWidget(
	// widget name and class
	"acme.widget.Memo",
	
	// superclass
	dojo.widget.HtmlWidget,
	
	// properties and methods
	{
		// parameters
		title: "Note",

		// settings
		isContainer: true,
		templatePath: dojo.uri.dojoUri("../acme/widget/Memo.html"),
		templateCssPath: dojo.uri.dojoUri("../acme/widget/Memo.css"),
		
		// callbacks
		onClick: function(evt){
			this.destroy();
		}
	}
);