amd in dojo and beyond
DESCRIPTION
AMD in Dojo and beyond. By Karthick S. Agenda. Dojo fundamentals Introduction to AMD AMD Benefits AMD Development Strategies - Module vs Widget Use Case Using Dijit Widgets Creation of custom widgets Grids and Stores. JavaScript Pre-requisites. Objects Prototypal Inheritance - PowerPoint PPT PresentationTRANSCRIPT
AMD in Dojo and beyond
By Karthick S
Agenda Dojo fundamentals Introduction to AMD AMD Benefits AMD Development Strategies - Module vs
Widget Use Case Using Dijit Widgets Creation of custom widgets Grids and Stores
JavaScript Pre-requisites Objects Prototypal
Inheritance Closures Callbacks Anonymous functions Prototypes Variable Hoisting Bind, Call and Apply
Why Dojo ? Support for industry standard AMD across the
toolkit Field proven performance of Enterprise Web
Apps Comprehensive Dijit library Flexible to write custom widgets Backing of enterprise bigwigs like IBM, AOL,
and Sun Early adopters of Deferreds and Promises,
Aspects, Client-side pubsub, Offline storage etc
Lots of community packages like grid, xstyle, etc
What is AMD ? Stands for Asynchronous Module Definition Born out of CommonJS and inspired by Dojo
XHR+eval Load ONLY the needed modules
asynchronously Also can load non-AMD plugins like HTML,
JSON, etc Supported from Dojo v1.7 onwards https://github.com/amdjs/amdjs-api/wiki/AMD
Benefits of AMD Say goodbye to globals - AMD provides better
encapsulation Can load and manage 3rd party packages Loads the modules only once and caches
them Better reusability and maintainability Baseless Dojo Supports cross domain loading of JS modules Better minification and portability
AMD APIs
requiredefine
AMD Code Structure dojoLib/dojo dojoLib/dijit dojoLib/dojox dojoLib/dgrid dojoLib/<your-custom-package>/<your-
custom-modules>
e.g.: dojoLib/myApp/myModuleOne
Dojo Library -> Package -> Module/Widget
AMD Code Structure - Contd Dojo comes organized into packages. Packages are collections of modules. Modules are nothing but individual JS files with
define API Modules have 1:1 mapping with the JS files
Dojo Code Sample – Before and After AMDdojo.ready(function(){var myButton = dojo.byId("myButton”);
Before AMD - >dojo.connect(myButton, "onclick", function(evt){ dojo.style(myDiv, "backgroundColor", "blue");});});
require(["dojo/on", "dojo/dom", "dojo/dom-style", "dojo/domReady!"], function(on, dom, domStyle, mouse) {
var myButton = dom.byId("myButton”); After AMD - > on(myButton, "click", function(evt){
domStyle.set(myDiv, "backgroundColor", "blue"); });});
AMD Constructs and Concepts In the Dojo 1.6 and before, dojo.js is loaded
with base API like ready, connect, style, etc. AMD uses “base-less” dojo, i.e. none of the
APIs are loaded by default. Load them whenever we need to use them
using require Wrap the JavaScript code into modules using
define Create custom widgets using define, declare
and new
Using Modules Using require() API.
Syntaxrequire(<module-identifiers-array>, <anonymous-callback-
function>);Argument 1 - DependenciesArgument 2 - Callback Function
Examplerequire([“myPkg/myModule”,
“dojo/dom”, ”dojo/domReady!],
function(myModule,dom){myModule.initApp();
dom.byId(“testDiv”).innerHTML=“AMD is the way to go!”; });
Using Modules – contd.Module Identifier Mappings to the path of the individual JS file(.js). We can specify relative paths as well(like ./) We need to specify all the dependencies here
Callback Function An anonymous function which will be called back, after
loading the dependencies specified in the moduleID array. Arguments are the returned objects of the loaded modules The moduleIDs and the argsList should be in the same
order Special plugins like domReady! don’t return any object
Popular APIs dojo/on - Event handling dojo/dom - DOM manipulations dojo/query - Advanced CSS Selectors dojo/topic - Event publish/subscribe dojo/aspect - Aspect oriented programming
(AOP) dijit/registry - Widget manipulations dojo/_base/fx - Base effects dojo/_base/array - Array manipulations
Dojo Plugins Extend the AMD Loader to provide special
functionalities They do not return any object when included in
require All the plugin module identifiers will end or have
exclamation point (!) Exclamation point is used to indicate process , to
the loader Popular plugins are
“dojo/text!” “dojo/domReady!” “dojo/il8n!”
Dojo Plugins Extend the AMD Loader to provide special
functionalities They do not return any object when included in
require All the plugin module identifiers will end or have
exclamation point (!) Exclamation point is used to indicate process , to
the loader Popular plugins are
“dojo/text!” “dojo/domReady!” “dojo/il8n!”
Example: dojo/text Loads the content of the file into a string object Replaces dojo.cache Used to load the template HTML in widgets
require([“dojo/text!./names.txt”, “dojo/domReady!”], function(names){
var names = names.split(“\n”);console.log(“Names loaded=“,
names.length);});
Defining Modules Use the define() API Code is resolved only when needed.
Syntaxdefine(<module-identifiers-array>, <anonymous-callback-function>);Argument 1 - Dependencies for the moduleArgument 2 - Factory Function - returns an object/value
ExampleFile should -> ”<baseURL>/myPkg/myModule.js”
define([“dojo/dom”],function(dom){return {moduleName: “Test Module”,initApp: function(){dom.byId(‘testDiv’).innerHTML = “Success”;}};});
Dojo 1.6 and before - Using DataGriddojo.require("dojox.grid.DataGrid");dojo.require("dojo.data.ItemFileWriteStore");var grid, store;dojo.ready(function(){store = new dojo.data.ItemFileWriteStore({url: “employees.json”});grid = new dojox.grid.DataGrid({store: store,query: { id: "*" },structure: [{ name: "First Name", field: "first", width: "84px" },{ name: "Last Name", field: "last", width: "84px" },{ name: “Company”, field: “company”, width: "70px" },{ name: “Department”, field: “dept”, width: "70px" },{ name: “Salary”, field: “salary”, width: "60px" }}, "grid"); grid.startup();});
Dojo 1.7 and after - Using DataGridvar grid, dataStore, store;require(["dojox/grid/DataGrid”, "dojo/store/Memory“, "dojo/data/ObjectStore”,
"dojo/_base/xhr”, "dojo/domReady!"], function(DataGrid, Memory, ObjectStore,xhr){xhr.get({url: "employees.json",handleAs: "json"}).then(function(data){store = new Memory({ data: data.items });dataStore = new ObjectStore({ objectStore: store }); grid = new DataGrid({store: dataStore,query: { id: "*" },structure: [{ name: "First Name", field: "first", width: "84px" },{ name: "Last Name", field: "last", width: "84px" },{ name: “Company”, field: “company”, width: "70px" }, { name: “Department”, field:
“dept”, width: "70px" }, ]}, "grid"); grid.startup();});});
Widget Creation declare
SyntaxArg1 - Class/Widget name - OptionalArg2 - Subclass array - Subclasses are called Mixins in DojoArg3 - Class Object
Example
Without AMDdojo.provide(“myPkg.myWidget”);
dojo.require(“dijit._WidgetBase”);dojo.require(“dijit._TemplatedMixin”);
dojo.declare(“myPkg.myWidget”,[dijit._WidgetBase, dijit._TemplatedMixin], {templateString: dojo.cache(“myPkg”, “templates/myWidget.html”);
});
Widget Creation - With AMDdefine([ "dojo/_base/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin", "dojo/text!./templates/myWidget.html"], function(declare, _WidgetBase, _TemplatedMixin, template) { return declare([_WidgetBase, _TemplatedMixin], { templateString: template }); });
Widget Lifecycle All dojo widgets extend the base class,
diiit_WidgetBase Optionally extend dijit_templatedMixin if we
need template or layout for the widget All widgets have a set of lifecycle methods to
them These lifecycle methods are your access to
write custom logic
this.inherited(arguments); - To call the superclass overridden method
Widget Lifecycle Methods constructor - Initialization code.
parameters are mixed into the widget instance
postMixInProperties - Before DOM rendering and creation of DOM nodes. Add or change the instance properties.
buildRendering -dijit._Templated takes care.The template is fetched/read, nodes created and events hooked up during buildRendering. The end result is assigned to this.domNode.
Setters are called
postCreate -Widget has been rendered on the DOM, except for its child widgets. Sizing operations should be done here.
Startup - Called after parsing and creation of child widgets has completed. If the widget does JS sizing, then startup() should call resize(), which does the sizing.
destroy
The Dijit Collection Context, popup, and dropdown menus Form element replacements like buttons, combo boxes,
checkboxes, radio buttons, and text boxes Date and time selection widgets WYSIWYG Editor Horizontal and Vertical Sliders Progress Bars Tabs and Accordions Tree Structures (including Drag and Drop) Dialogs and Tooltips Layout widgets with slide controls and splitters
Requiring Proper Modules and Resources It comes bundled with four supported themes: -> nihilo, soria, tundra, and claro
Each theme contains images and CSS files CSS files must be explicitly included into each HTML page:
<style type="text/css"> @import “//ajax.googleapis.com/ajax/libs/dojo/1.8/dojo/resources/dojo.css"; @import //ajax.googleapis.com/ajax/libs/dojo/1.8/dijit/themes/claro/claro.css";</style>
<body class="claro">
dojoConfig dojoConfig
dojoConfig = { isDebug:true, async:true}
Note: parseOnLoad was a common property in djConfig, but this is no longer recommended. See information about the parser below.
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.8/dojo/dojo.js" data-dojo-config="isDebug:true, async:true" type="text/javascript"></script>
<body class="claro"> <button data-dojo-type='dijit/form/Button'>Clicky</button> </body>
dojo/parser We need to load dojo/parser and explicitly tell it to parse.
After the DOM is ready of course. The AMD way to determine this is with the dojo/domReady plugin. AMD is instructed that the loaded dependency is a plugin with an exclamation point, such as: dojo/domReady!.
<body class="claro"> <button data-dojo-type='dijit/form/Button'>Clicky</button> <script> require([ 'dojo/parser', “dijit/form/Button”, 'dojo/domReady!' ], function(parser){ parser.parse(); // tell dojo to check the DOM for widgets }); </script></body>
Require Dijit widgets AMD Loader is asynchronous and smart enough to
find and load un-required modules.
But Widget should be required explicitly, to get maximum performance from your application,
AMD and Dojo require that you explicitly define the modules and dependencies you want to use in your application.
Creating Widgets The Basic select Element
<select name="character" id="character"> <option value="">Select a character</option> <option value="Leonard">Dr. Leonard Leakey Hofstadter</option> <option value="Sheldon" selected="selected">Dr. Sheldon Lee Cooper</option> <option value="Rajesh">Dr. Rajesh Ramayan Koothrappali</option> <option value="Howard">Howard Joel Wolowitz</option></select>
dijit/form/FilteringSelect
Creating Widgets Declarative way
<select name="character" id="characterNode" data-dojo-type="dijit/form/FilteringSelect" data-dojo-props='autoComplete:true, pageSize:10' > <option value="">Select a character</option> <option value="Leonard">Dr. Leonard Leakey Hofstadter</option> <option value="Sheldon" selected="selected">Dr. Sheldon Lee Cooper</option> <option value="Rajesh">Dr. Rajesh Ramayan Koothrappali</option> <option value="Howard">Howard Joel Wolowitz</option></select>
When we call parser.parse(), Dojo will find this element and instantiate and initialize the widget.
Creating Widgets Programmatic Method
require([ 'dijit/form/FilteringSelect', 'dojo/domReady!'], function(FilteringSelect){ var filteringSelect = new FilteringSelect({ autoComplete: true, pageSize: 10 },'characterNode'); });
dojo/parser was removed from the list of dependencies, as it’s not needed for programmatic instantiation of widgets.
Creating More Widgetsrequire([ 'dijit/form/FilteringSelect', 'dijit/form/DateTextBox', 'dijit/form/Textbox', 'dijit/form/Textarea', 'dijit/form/Checkbox', 'dijit/form/RadioButton', 'dojo/domReady!'], function(FilteringSelect, DateTextBox, Textbox, Textarea, Checkbox, RadioButton){ var filteringSelect = new FilteringSelect({ autoComplete: true, pageSize: 10 },'characterNode'); var input = new Textbox({/*options*/},'myInputNode'); var textarea = new Textarea({/*options*/},'myTextareaNode'); var mySelect = new FilteringSelect({/*options*/},'mySelectNode'); var date = new DateTextBox({/*options*/},'myDateNode'); var checkbox = new CheckBox({/*options*/},'myCheckboxNode'); var radio1 = new RadioButton({/*options*/},'myRadio1Node');});
Accessing Dijit Widgets and their Properties Dijit has its own dijit/registry.byId method which retrieves the Dijit widget
registered with the ID specified.
If the element to be made a Dijit has an ID, the widget ID will be that same value. If the source element doesn’t have an ID attribute, a widget ID will be generated.
require([ 'dojo/parser', 'dijit/registry', 'dijit/form/FilteringSelect', 'dojo/domReady!'], function(parser, registry, FilteringSelect){ parser.parse(); var filteringSelect = registry.byId('characterNode'); console.log('filteringSelect', filteringSelect);});
Getter and setters If we wanted to access the pageSize property for which the Dijit
widget was created from, we would access it with a Dijit getter:
var pageSize = registry.byId('characterNode').get('pageSize'); // returns 10
If we wanted to change the pageSize for the widget, we would code:
registry.byId('characterNode').set('pageSize',20); //now pageSize is 20
Listening to Widget Events Dijit widgets use dojo/on method to listen to DOM events on the given
widget:
filteringSelect.on('change', function(value){ console.log('value', value); });
It’s important to note that those are DOM events. If you wish to listen to a widget method, you should use dojo/aspect:
require([ 'dojo/aspect' // other deps...], function(aspect){ aspect.after(filteringSelect, 'validate', function(value){ console.log('validate', value); });});
Dojo Object Stores new data store API called Dojo Object Store. This new store API is based on the HTML5 IndexedDB object store API simplify and ease the interaction and construction of Dojo stores. This new API follows HTTP/REST naming conventions is compatible with the dojox.storage providers (for local storage, cookie
storage, and WebSQL storage), Separate UI from data concerns Dojo Object Store API is an interface between different data consumers to
different data producers. Dojo core comes with two key implementations that are commonly needed:
dojo/store/Memory and dojo/store/JsonRest.
dojo/store/Memory This is a very simple in-memory store. This is highly useful for quickly creating a store, particularly for smaller
datasets. A Memory store can be created by simply providing a plain array of objects
as the data source for this store, and then you can start querying and interacting with the store
The Memory store is a synchronous store, which means it directly returns values, making it very easy to use.
var product = productStore.get("slinky");var someData = [ {id:1, name:"One"}, {id:2, name:"Two"} ]; store = new dojo.store.Memory({data: someData}); store.get(1) store.query({name:"One"}) store.query(function(object){ return object.id > 1; }) store.put({id:3, name:"Three"}); store.remove(3);
dojo/store/JsonRest dojo/store/JsonRest is a lightweight object store implementation of an
HTTP-based (RFC 2616) client with RESTful data interaction capabilities. This store implements the new Dojo Object Store API. JsonRest provides full read, write, and notification capabilities through
standards based HTTP/REST interaction with the server using GET, PUT, POST, and DELETE commands.
This data store allows you to communicate with server side database/persistent data storage using the Dojo Data API with JavaScript and efficiently handles create, read, update, and delete (CRUD) operations
require(["dojo/store/JsonRest"], function(JsonRestStore){
var store = new JsonRestStore({target: "/Table/" }); store.get(3).then(function(object){}); store.query("foo=bar").then(function(results){}); store.put({ foo: "bar" }, { id: 3 }); // store the object with the given identity store.remove(3); // delete the object});
Object Store API Methods get(id) - This will trigger a GET request to {target}{id}.
query(query, options) - This will trigger a GET request to {target}{query}. If query is an object, it will be serialized using dojo.objectToQuery. If query is a string, it is appended to the URL as-is. If options includes a sort property, it will be serialized as a query parameter as well; see Sortingfor more information.
remove(id) - This will trigger a DELETE request to {target}{id}.
put(object, options) - If object includes an identity property, or options includes an id, this will trigger a PUT request to {target}{id} with the request body being the provided object serialized as JSON. If no identity is provided, then a POST request is made to the store’s target URL (no id appended) with the object as the body. If the options.incremental property is true, then a POST request is made to {target}{id} with the object as the body. You may also include an options.overwrite property. If overwrite is set to true, then an If-Match: * header is included. If overwrite is set to false, then an If-None-Match: * header is included.
add(object, options) - This behaves exactly like put(object, options), except that options.overwrite is set to false, indicating that a new object must be created.
dojo.store.Observable dojo.store.Observable is an object store wrapper that adds support for notification of data
changes to query result sets. The query result sets returned from a Observable store will include a observe function that can be
used to monitor for changes. The observe function provides indication of the previous and new index values of changed objects to properly
update result arrays. The result sets returned from store.query() calls from a Observable store will have a observe method. The
observe method has the following signature: resultSet.observe(listener); The listener function is called with following arguments: listener(object, removedFrom, insertedInto);
store = dojo.store.Observable(new dojo.store.Memory({data: someData}));var results = store.query({rating:5});// do something with the initial result setresults.forEach(insertRow);var observeHandle = results.observe(function(object, removedFrom, insertedInto){ if(removedFrom > -1){ // existing object removed removeRow(removedFrom); }}); store.put({rating: 5, id: 3}); store.remove(2);observeHandle.cancel();
dojo.store.Cache dojo.store.Cache is a object store wrapper for caching data from one store in another store. This store
follows the Dojo Object Store API. The Cache store provides caching capabilities for stores. The Cache store takes two stores, a master store and
caching store. The master store is considered the data authority, all modifications go to the master store, and when data is
not available in the cache, it is retrieved from the master store. The caching store is used to record cached data from master store. Doing get() and query() call results are
added to the cache (unless they don’t meet provided criteria), but only get() uses the cache, whereas query() uses the master store.
If you want to a query to come from the cache, directly call query() on the caching store. Data modifications are also mirrored in the caching store. A typical usage of dojo.store.Cache would be to use a JsonRest store as the master store, and a Memory store as the caching store.
restStore = new dojo.store.JsonRest(...); memoryStore = new dojo.store.Memory(); store = new dojo.store.Cache(restStore, memoryStore); store.get(1) -> Returns the object with an id of 1 by making a GET request store.get(1) -> Returns the object, using the local memory cache store.put({id:2, name:"two"}) -> Stores the object in both master and cache store store.get(2) -> Returns the object, using the local memory cache
Introduction to the DataGrid The DataGrid is the central component of many applications due to its effective and usable
presentation of tabular data. In this tutorial we will look at how to define a grid's layout and discuss the scrolling mechanism the DataGrid uses.
dojox/grid/DataGrid As you probably guessed, the DataGrid is made up of several different parts. At the highest level, a DataGrid is made up of views. Views break the DataGrid up into sections and render the header andcontent for each section. Headers and contents contain rows (although the header only contains one row) which are populated by sub-
rows of cells. To define how a DataGrid will look, we will be passing different objects and arrays to the structure property of
the DataGrid constructor. Cell Definition object
name: the string to use in the header cell field: the name of the field of the data record to display width: a string containing the CSS width (with units) of the column hidden: a boolean that when true will hide the column
Introduction to the DataGrid The DataGrid is the central component of many applications due to its effective and usable
presentation of tabular data. In this tutorial we will look at how to define a grid's layout and discuss the scrolling mechanism the DataGrid uses.
dojox/grid/DataGrid As you probably guessed, the DataGrid is made up of several different parts. At the highest level, a DataGrid is made up of views. Views break the DataGrid up into sections and render the header andcontent for each section. Headers and contents contain rows (although the header only contains one row) which are populated by sub-
rows of cells. To define how a DataGrid will look, we will be passing different objects and arrays to the structure property of
the DataGrid constructor. Cell Definition object
name: the string to use in the header cell field: the name of the field of the data record to display width: a string containing the CSS width (with units) of the column hidden: a boolean that when true will hide the column
DataGrid SubRowgrid = new DataGrid({ store: store, query: { id: "*" }, structure: [ [ { name: "First Name", field: "first", width: "84px", rowSpan: 2 }, { name: "Last Name", field: "last", width: "84px", rowSpan: 2 }, { name: "Bats", field: "bats", width: "70px", rowSpan: 2 }, { name: "Throws", field: "throws", width: "70px", rowSpan: 2 }, { name: "G", field: "totalG", width: "60px" }, { name: "AB", field: "totalAB", width: "60px" }, { name: "R", field: "totalR", width: "60px" }, { name: "RBI", field: "totalRBI", width: "60px" }, { name: "BB", field: "totalBB", width: "60px" }, { name: "K", field: "totalK", width: "60px" } ],[ { name: "Games as Batter", field: "totalGAB", colSpan: 2 }, { name: "H", field: "totalH" }, { name: "2B", field: "total2B" }, { name: "3B", field: "total3B" }, { name: "HR", field: "totalHR" } ] ]}, "grid");
DataGrid Views We've made it a little easier to view our data, however once you scroll to the right you can't see whose
records you're looking at. By defining a view definition, we can lock sections of columns from scrolling left and right. A view definition is an object with some specific properties set on it:
cells: an array or an array of arrays of cell definitions noscroll: a boolean that when true will prevent the view from scrolling horizontally width: a string specifying the CSS width of the view — this is only needed when your cells are defined with
relative widths like percentages
DataGrid Viewsgrid = new DataGrid({ store: store, query: { id: "*" }, structure: [ { noscroll: true, cells: [ { name: "First Name", field: "first", width: "84px" }, { name: "Last Name", field: "last", width: "84px" } ] },{ cells: [ [ { name: "Bats", field: "bats", width: "70px", rowSpan: 2 }, { name: "Throws", field: "throws", width: "70px", rowSpan: 2 }, { name: "G", field: "totalG", width: "60px" }, { name: "AB", field: "totalAB", width: "60px" }, { name: "R", field: "totalR", width: "60px" }, { name: "RBI", field: "totalRBI", width: "60px" }, { name: "BB", field: "totalBB", width: "60px" }, { name: "K", field: "totalK", width: "60px" } ],[ { name: "Games as Batter", field: "totalGAB", colSpan: 2 }, { name: "H", field: "totalH" }, { name: "2B", field: "total2B" }, { name: "3B", field: "total3B" }, { name: "HR", field: "totalHR" } ] ] } ]}, "grid");
Populating your Grid using dojo/dataViewsThe DataGrid is the central component of many applications due to its effective and usable presentation of tabular data. In this tutorial we will look at how to populate a grid and manipulate data in a grid. There are two ways to access the data in the store; the first is letting the DataGrid query the store for you. To do this, we
can pass three parameters to the DataGrid constructor: store: The data store. query: The query to pass to the store. The syntax will depend on the store being used. queryOptions: Options to pass to the store during querying. The options will depend on the store being used, and is not
required. Since we want every record, we'll pass { id: "*" }: require([ "dojox/grid/DataGrid", "dojo/store/Memory", "dojo/data/ObjectStore", "dojo/_base/xhr", "dojo/domReady!" ], function(DataGrid, Memory, ObjectStore, xhr){ var grid, dataStore; xhr.get({ url: "hof-batting.json", handleAs: "json" }).then(function(data){ dataStore = new ObjectStore({ objectStore:new Memory({ data: data.items }) }); grid = new DataGrid({ store: dataStore, query: { id: "*" }, queryOptions: {}, structure: [ { name: "First Name", field: "first", width: "25%" }, { name: "Last Name", field: "last", width: "25%" }, { name: "G", field: "totalG", width: "10%" }, { name: "AB", field: "totalAB", width: "10%" }, { name: "R", field: "totalR", width: "10%" }, { name: "H", field: "totalH", width: "10%" }, { name: "RBI", field: "totalRBI", width: "10%" } ] }, "grid"); grid.startup(); }); });
Populating your Grid using dojo/dataViewsrequire([ "dojox/grid/DataGrid", "dojo/store/Memory", "dojo/data/ObjectStore", "dojo/_base/xhr", "dojo/domReady!"], function(DataGrid, Memory, ObjectStore, xhr){ var grid, dataStore; xhr.get({ url: "hof-batting.json", handleAs: "json" }).then(function(data){ dataStore = new ObjectStore({ objectStore:new Memory({ data: data.items }) }); grid = new DataGrid({ store: dataStore, query: { id: "*" }, queryOptions: {}, structure: [ { name: "First Name", field: "first", width: "25%" }, { name: "Last Name", field: "last", width: "25%" }, { name: "G", field: "totalG", width: "10%" }, { name: "AB", field: "totalAB", width: "10%" }, { name: "R", field: "totalR", width: "10%" }, { name: "H", field: "totalH", width: "10%" }, { name: "RBI", field: "totalRBI", width: "10%" } ] }, "grid"); grid.startup(); });});
Populating your Grid using dojo/dataViews Formatting Data
{ name: "G", field: "totalG", width: "10%", formatter: function(games){ return games + " <em>games</em>"; }}, DataGrid as a View One very important point should be made before concluding this tutorial: the DataGrid is simply
aview of a dojo/data store. This means the DataGrid will react to changes in the store (row addition or deletion, and record field
updates) if the store supports the notification API of dojo/data, and it will sort the data according to the rules of the store you're using. However, it is not designed to do sorting apart from the store.
This means that if formatting your data will change the sort order, theDataGrid won't notice the formatted changes.