< Previous | Next >

Lesson 2: Create a custom Dojo widget

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

  1. In the Enterprise Explorer view, right-click the WebContent/dojo folder and select New > Dojo Widget. The New Dojo Widget wizard appears.
  2. In the Module Name field, enter loan.
  3. In the Widget Name field, enter LoanInput. The HTML template and style sheet relative for the widget paths are populated automatically.
    New Dojo widget wizard
  4. 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.
  5. The LoanInput JavaScript source file for the widget opens in the editor.
  6. 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,
  7. 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() {
    }
  8. In the Enterprise Explorer view, double-click templates/LoanInput.html to open the HTML template for the widget.
  9. Click Next and accept the defaults. Click Finish.
  10. 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.
  11. 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>
  12. Now add Dojo widgets for each of the input fields:
    1. In the workspace, surface the palette by clicking the appropriate tab. You should see several drawers containing Dojo widgets.
    2. Expand the Dojo Form Widgets drawer by clicking on it.
      Dojo Form widgets drawer
    3. Select the CurrencyTextBox and drop it next to the Loan Amount label inside your div tag.
    4. 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.
    5. 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.
    6. 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>
    7. 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.
    8. 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.
    9. Add the data-dojo-props attribute. Inside the attribute, set the following properties, separated by commas:
      1. value : 5
      2. smallDelta : .05
      3. intermediateChanges : true
      4. 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>
    10. From the palette drop a ComboBox widget into the Term (years) div.
    11. 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.
    12. Set 15 as the default value by setting it to True. Click OK.
  13. 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.
    1. Use content assist to add a data-dojo-attach-point attribute to each widget. Name them amount, rate, and term respectively.
    2. 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>
  14. Save and close LoanInput.html and reopen LoanInput.js.
  15. 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:
    1. "dijit/form/CurrencyTextBox"
    2. "dijit/form/NumberSpinner"
    3. "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"
    ],
  16. 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.
  17. 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;
			}
}
	});
});

Lesson checkpoint

You created a custom Dojo widget.

You learned:
  • How to use content assist and templates to rapidly write Dojo code
  • How to modify the HTML template for a custom Dojo widget
  • How to modify the JavaScript file for a custom Dojo widget
< Previous | Next >
Icon that indicates the type of topic Tutorial lesson topic
Timestamp icon Last updated: July 17, 2017 21:58

File name: loan_lesson2.html