The Dojo toolkit includes dozens of standard widgets, including
input fields, combo boxes and radio buttons. You can also create custom
widgets to encapsulate reusable UI elements or a specific piece of
functionality. In this lesson you create a new custom Dojo widget.
About this task
Dojo widgets are composed of three files that the New Dojo
Widget wizard creates for you:
- An HTML file
- A JavaScript file
- A CSS file
You then edit the HTML template and the JavaScript file.
Procedure
- In the Enterprise Explorer view, right-click the WebContent/dojo
folder and select . The New Dojo Widget wizard
appears.
- In the Module Name field, enter loan.
- In the Widget Name field, enter LoanInput. The HTML template and style sheet relative for the widget paths
are populated automatically.
- Click Finish. Three files
are created under a folder named dojo/loan:
- templates/LoanInput.html
- The UI template for the widget.
- themes/LoanInput.css
- Provides the styling for the widget.
- LoanInput.js
- Provides the JavaScript backend
and business logic portion of the widget.
- The LoanInput JavaScript source
file for the widget opens in the editor.
- Under the templateString field, add three
additional fields that will be used to hold the results of our calculation – principal, interestPaid,
and monthlyPayment - they should all have default
values of 0. Ensure that you add a comma after each
field.
templateString : dojo.cache("loan", "templates/LoanInput.html"),
principal: 0,
interestPaid: 0,
monthlyPayment: 0,
- Under the postCreate function, add a new
function named calculate. Ensure that you add a comma
after the postCreate function. Leave the new calculate function
empty for now.
postCreate : function() {
},
// this function will perform the calculations for our loan payment
calculate: function() {
}
- In the Enterprise Explorer view, double-click templates/LoanInput.html to
open the HTML template for the widget.
- Click Next and accept the defaults.
Click Finish.
- Within the existing div create three additional child div
tags. You can use content assist by typing <d and
then pressing Ctrl + Space. In the pop-up window, select <>
div to insert the tag.
- Within each new div tag add a text label – Loan
Amount:, Interest Rate:, and Term
(years):. When complete your code should look like this:
<div class="LoanInput">
<div>Loan Amount: </div>
<div>Interest Rate: </div>
<div>Term (years): </div>
</div>
- Now add Dojo widgets for each of the input fields:
- In the workspace, surface the palette by clicking the
appropriate tab. You should see several drawers containing Dojo widgets.
- Expand the Dojo Form Widgets drawer
by clicking on it.
- Select the CurrencyTextBox and
drop it next to the Loan Amount label inside your div tag.
- Within the newly created input element, type data- and
use content assist (Ctrl + Space) to show a list of attributes. Click data-dojo-props to
insert it. To follow HTML5 standards, beginning in Dojo Toolkit SDK
1.7 attributes are set by default through data-dojo-props.
- Inside the data-dojo-props attribute, type cu and
use content assist (Ctrl + Space) to show a list of attributes. Click currency to
insert it.
- Inside the currency attribute, type USD.
Your code should look like this:
<div>Loan Amount: <input type="text"
data-dojo-type="dijit.form.CurrencyTextBox"
data-dojo-props="currency: 'USD'">
</div>
- Next, insert the Dojo widget markup for the Interest
Rate field. Place your cursor inside the second div tag after the
label, type <input d> and with your cursor
next to the d, use content assist (Ctrl + Space) to show a list of
attributes. Click data-dojo-type to insert
it.
- Inside the data-dojo-type attribute, invoke content
assist again to show a list of available dojo widgets. Begin typing dijit.form.N until
you see NumberSpinner. Click NumberSpinner to
insert it into your page.
- Add the data-dojo-props attribute. Inside the attribute,
set the following properties, separated by commas:
- value : 5
- smallDelta : .05
- intermediateChanges : true
- constraints : {min: 0}
You can use content assist to insert these properties the same way you added the currency
attribute previously. When you are finished setting the properties for the attribute, your code
should look like
this:<div>Interest Rate: <input data-dojo-type="dijit.form.NumberSpinner"
data-dojo-props="value: 5, smallDelta: 0.05, intermediateChanges: true, constraints: {min: 0}"> </input></div>
- From the palette drop a ComboBox widget
into the Term (years) div.
- Additional configuration for some widgets is available
when you drop them from the palette, such as the ComboBox. In the
Insert Combo Box dialog box you can add values for your ComboBox.
Add values for 1, 2, 3, 4, 5, 10, 15, 30.
- Set 15 as the default value by setting it to True.
Click OK.
- Next, add the data-dojo-attach-point and data-dojo-attach-event attributes
to each of your input widgets. The value specified for the data-dojo-attach-point attribute
is the name that the widget instance can be referenced by from the LoanInput.js file.
The data-dojo-attach-event attribute adds event handling
to the widgets.
- Use content assist to add a data-dojo-attach-point attribute
to each widget. Name them amount, rate,
and term respectively.
- Add data-dojo-attach-event="onChange: calculate" for
each widget. Each time that an onChange event takes place on this
widget it calls the calculate function that you added to the LoanInput.js
file. The final result of your LoanInput.html file should look like
this:
<div class="LoanInput">
<div>Loan Amount: <input type="text"
data-dojo-type="dijit.form.CurrencyTextBox"
data-dojo-props="currency: 'USD'"
data-dojo-attach-point="amount"
data-dojo-attach-event="onChange: calculate"></div>
<div>Interest Rate: <input data-dojo-type="dijit.form.NumberSpinner"
data-dojo-props="value:5,
smallDelta:0.05,
intermediateChanges:true,
constraints:{min: 0}"
data-dojo-attach-point="rate"
data-dojo-attach-event="onChange: calculate">
</div>
<div>Term (years): <select name="select"
data-dojo-type="dijit.form.ComboBox"
data-dojo-props="autocomplete:false"
data-dojo-attach-point ="term"
data-dojo-attach-event="onChange: calculate">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>10</option>
<option selected="selected">15</option>
<option>30</option>
</select>
</div>
</div>
- Save and close LoanInput.html and
reopen LoanInput.js.
- Add Dojo module dependencies for the three widgets used
in the html file. These dependencies will load the necessary resources
to create the widgets when the page is run. The second argument of
the define function is an array of dependencies.
Directly after the "dijit/_WidgetsInTemplateMixin", dependency,
add the following module paths separated by commas:
- "dijit/form/CurrencyTextBox"
- "dijit/form/NumberSpinner"
- "dijit/form/ComboBox"
Your code should look like this:
define("loan/LoanInput",
[ "dojo", "dijit", "dijit/_Widget",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"dijit/form/CurrencyTextBox",
"dijit/form/NumberSpinner",
"dijit/form/ComboBox",
"dojo/text!loan/templates/LoanInput.html"
],
- Now add the following code for the calculate function that
you created earlier in Step 7. You can experiment with content assist
if you want. Note that standard JavaScript objects
such as the Math object are available in content assist. The variables
we defined earlier, principal, interestPaid,
and monthlyPayment are all available as well.
// this function will perform the calculations for our loan repayment
calculate: function() {
this.principal = this.amount.attr('value');
if(this.principal == NaN) {
this.monthlyPayment = 0;
this.principal = 0;
this.interestPaid = 0;
} else {
var interestRate = this.rate.attr('value') / 1200;
var termInMonths = this.term.attr('value') * 12;
this.monthlyPayment = Math.pow(1 + interestRate, termInMonths) - 1;
this.monthlyPayment = interestRate + (interestRate / this.monthlyPayment);
this.monthlyPayment = this.monthlyPayment * this.principal;
this.interestPaid = (this.monthlyPayment * termInMonths) - this.principal;
}
}
The calculate function stores the principal of the loan,
computes the monthly payment, and the amount of interest paid.
- Save and close all of the files that make up the custom
widget.
Results
LoanInput.js should now look like this:
define("loan/LoanInput", [ "dojo", "dijit", "dijit/_Widget",
"dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin", "dijit/form/CurrencyTextBox", "dijit/form/NumberSpinner", "dijit/form/ComboBox",
"dojo/text!loan/templates/LoanInput.html" ], function(dojo, dijit,
_Widget, _TemplatedMixin, _WidgetsInTemplateMixin, CurrencyTextBox, NumberSpinner, ComboBox) {
dojo.declare("loan.LoanInput", [ dijit._Widget, dijit._TemplatedMixin,
dijit._WidgetsInTemplateMixin ], {
// Path to the template
templateString : dojo.cache("loan", "templates/LoanInput.html"),
principal: 0,
interestPaid: 0,
monthlyPayment: 0,
// Override this method to perform custom behavior during dijit construction.
// Common operations for constructor:
// 1) Initialize non-primitive types (i.e. objects and arrays)
// 2) Add additional properties needed by succeeding lifecycle methods
constructor : function() {
},
// When this method is called, all variables inherited from superclasses are 'mixed in'.
// Common operations for postMixInProperties
// 1) Modify or assign values for widget property variables defined in the template HTML file
postMixInProperties : function() {
},
// postCreate() is called after buildRendering(). This is useful to override when
// you need to access and/or manipulate DOM nodes included with your widget.
// DOM nodes and widgets with the dojoAttachPoint attribute specified can now be directly
// accessed as fields on "this".
// Common operations for postCreate
// 1) Access and manipulate DOM nodes created in buildRendering()
// 2) Add new DOM nodes or widgets
postCreate : function() {
},
//this function will perform the calculations for our loan payment
calculate: function() {
this.principal = this.amount.attr('value');
if(this.principal == NaN) {
this.monthlyPayment = 0;
this.principal = 0;
this.interestPaid = 0;
} else {
var interestRate = this.rate.attr('value') / 1200;
var termInMonths = this.term.attr('value') * 12;
this.monthlyPayment = Math.pow(1 + interestRate, termInMonths) - 1;
this.monthlyPayment = interestRate + (interestRate / this.monthlyPayment);
this.monthlyPayment = this.monthlyPayment * this.principal;
this.interestPaid = (this.monthlyPayment * termInMonths) - this.principal;
}
}
});
});