Created
March 10, 2012 04:27
-
-
Save cswing/2010137 to your computer and use it in GitHub Desktop.
Dojo: Implementing a ViewModelStore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<!-- | |
Copyright Craig Swing, 2012. All rights reserved. | |
--> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> | |
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.7/dojo/resources/dojo.css" /> | |
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.7/dijit/themes/dijit.css" /> | |
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.7/dijit/themes/claro/claro.css" /> | |
<style type="text/css"> | |
body { | |
padding: 2em; | |
} | |
#filter { | |
padding: 0.5em 0; | |
} | |
div.order { | |
border: solid 1px #CCCCCC; | |
background: #eeeeee; | |
width: 800px; | |
height: 350px; | |
padding: 1em; | |
margin-bottom: 1em; | |
} | |
</style> | |
<title>Dojo Store API - ViewModelStore</title> | |
</head> | |
<body class="claro"> | |
<div><a target="_blank" href="http://swingingcode.blogspot.com/2012/03/dojo-implementing-viewmodelstore.html">Blog Post</a></div> | |
<div id="filter"> | |
<div class="dijitInline">Customer:<div id="customerNode"></div></div> | |
<div class="dijitInline">Status:<div id="statusNode"></div></div> | |
</div> | |
<div id="content"></div> | |
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7/dojo/dojo.js.uncompressed.js" data-dojo-config="isDebug: true"></script> | |
<script type="text/javascript"> | |
require(["dojo/domReady!", "dojo/dom-construct", "dojo/parser", "dojo/store/Memory", "dojo/currency", "dijit/form/ComboBox"], function(dr, domConstruct, p, MemoryStore, curr, ComboBox) { | |
// The ViewModelStore | |
dojo.declare("ViewModelStore", [MemoryStore], { | |
referenceProperty: null, | |
setData: function(data){ | |
if(data.items){ | |
this.idProperty = data.identifier; | |
data = this.data = data.items; | |
}else{ | |
this.data = data; | |
} | |
this.index = {}; | |
// when a reference to an item has not been registered, | |
// a setter function is added and will be called when | |
// the item is registered. | |
this._referenceSetters = {}; | |
// loop through the flat list of items | |
dojo.forEach(this.data, function(itm, idx) { | |
var itmId = itm[this.idProperty]; | |
this.index[itmId] = idx; | |
for(var prop in itm) { | |
this._registerItem(itm, prop); | |
} | |
// process the queue of deferred setters for this object. | |
if (this._referenceSetters[itmId]) { | |
dojo.forEach(this._referenceSetters[itmId], function(fnSet) { | |
fnSet(itm); | |
}); | |
this._referenceSetters[itmId] = null; | |
} | |
}, this); | |
delete this._referenceSetters; | |
}, | |
_inspectValue: function(val, fnSetter) { | |
var refProperty = this.referenceProperty || '_reference'; | |
// not a 'referece', so return the value. | |
if (!val || !dojo.isObject(val) || !val[refProperty]) { | |
fnSetter(val); | |
return; | |
} | |
var refId = val[refProperty]; | |
var refItm = this.get(refId); | |
// the referenced item has already been loaded, return it. | |
if (refItm) { | |
fnSetter(refItm); | |
return; | |
} | |
// we don't have the reference yet, qo queue a deferred setter that | |
// will set the value once the item is registered. | |
if (! this._referenceSetters[refId]) { | |
this._referenceSetters[refId] = []; | |
} | |
this._referenceSetters[refId].push(fnSetter); | |
}, | |
_registerItem: function(itm, prop) { | |
var propValue = itm[prop]; | |
if (dojo.isArray(propValue)) { | |
dojo.forEach(propValue, function(propItm, propIdx) { | |
this._inspectValue(propValue[propIdx], function(refItm) { | |
propValue[propIdx] = refItm; | |
}); | |
}, this); | |
} else { | |
this._inspectValue(itm[prop], function(refItm) { | |
itm[prop] = refItm; | |
}); | |
} | |
} | |
}); | |
// credit where due: names & addresses from http://www.fakenamegenerator.com | |
var store = new ViewModelStore({data: [ | |
{ id: 'customer::1', _type: 'customer', name: 'Anderson, Jose', address: { _reference: 'address::1' } }, | |
{ id: 'address::1', _type: 'address', address1: '2272 Stratford Drive', address2: 'Honolulu, HI 96814' }, | |
{ id: 'customer::2', _type: 'customer', name: 'Gomez, Marcus', address: { _reference: 'address::2' } }, | |
{ id: 'address::2', _type: 'address', address1: '2718 College Avenue', address2: 'Dayton, OH 45459' }, | |
{ id: 'customer::3', _type: 'customer', name: 'Kelley, Eleanor', address: { _reference: 'address::3' } }, | |
{ id: 'address::3', _type: 'address', address1: '1611 Mandan Road', address2: 'Steelville, MO 65565' }, | |
{ id: 'customer::4', _type: 'customer', name: 'Deen, Martha', address: { _reference: 'address::4' } }, | |
{ id: 'address::4', _type: 'address', address1: '4104 Poe Lane', address2: 'Kansas City, KS 66215' }, | |
{ id: 'customer::5', _type: 'customer', name: 'Marquez, Elaine', address: { _reference: 'address::5' } }, | |
{ id: 'address::5', _type: 'address', address1: '3800 Deans Lane', address2: 'Bedford Village, NY 10506' }, | |
{ id: 'product::1', _type: 'product', name: 'Ball Original Classic Pectin Small Batch', price: 1.07 }, | |
{ id: 'product::2', _type: 'product', name: 'Ball 4-Pk 16 Oz. Wide Mouth Class Canning Jars with Lids', price: 4.48 }, | |
{ id: 'product::3', _type: 'product', name: 'Compost Wizard Universal Composter Base', price: 61.00 }, | |
{ id: 'product::4', _type: 'product', name: 'Exaco 187-Gallon Composter', price: 270.56 }, | |
{ id: 'product::5', _type: 'product', name: 'Behlan Country 10\' x 6\' Outdoor Kennel', price: 299.00 }, | |
{ id: 'product::6', _type: 'product', name: 'PetSafe Wireless Pet Containment System', price: 249.00 }, | |
{ id: 'product::7', _type: 'product', name: 'Red Toolbox Toolbox House Woodworking Kit', price: 15.41 }, | |
{ id: 'product::8', _type: 'product', name: 'Top Choice 2 x 6 x 8 #2 Prime Treated Lumber', price: 4.27 }, | |
{ id: 'orderStatus::1', _type: 'orderStatus', name: 'Pending', displayOrder: 10 }, | |
{ id: 'orderStatus::2', _type: 'orderStatus', name: 'Back Ordered', displayOrder: 30 }, | |
{ id: 'orderStatus::3', _type: 'orderStatus', name: 'Shipped', displayOrder: 20 }, | |
{ id: 'order::1', _type: 'order', orderNumber: 1234, customer: { _reference: 'customer::1' }, orderStatus: { _reference: 'orderStatus::1' }, | |
lineItems:[ { _reference: 'orderLine::1' }, { _reference: 'orderLine::2' } ]}, | |
{ id: 'orderLine::1', _type: 'orderLine', order: { _reference: 'order::1' }, price: 1.07, quantity: 3, product: { _reference: 'product::1' } }, | |
{ id: 'orderLine::2', _type: 'orderLine', order: { _reference: 'order::1' }, price: 4.48, quantity: 1, product: { _reference: 'product::2' } }, | |
{ id: 'order::2', _type: 'order', orderNumber: 1235, customer: { _reference: 'customer::2' }, orderStatus: { _reference: 'orderStatus::1' }, | |
lineItems:[ { _reference: 'orderLine::3' }, { _reference: 'orderLine::4' }]}, | |
{ id: 'orderLine::3', _type: 'orderLine', order: { _reference: 'order::2' }, price: 4.48, quantity: 1, product: { _reference: 'product::2' } }, | |
{ id: 'orderLine::4', _type: 'orderLine', order: { _reference: 'order::2' }, price: 61.00, quantity: 1, product: { _reference: 'product::3' } }, | |
{ id: 'order::3', _type: 'order', orderNumber: 1236, customer: { _reference: 'customer::2' }, orderStatus: { _reference: 'orderStatus::3' }, | |
lineItems:[ { _reference: 'orderLine::5' }, { _reference: 'orderLine::6' } ]}, | |
{ id: 'orderLine::5', _type: 'orderLine', order: { _reference: 'order::3' }, price: 270.56, quantity: 1, product: { _reference: 'product::4' } }, | |
{ id: 'orderLine::6', _type: 'orderLine', order: { _reference: 'order::3' }, price: 299.00, quantity: 2, product: { _reference: 'product::5' } } | |
]}); | |
var customer = new ComboBox({ | |
store: store, | |
query: { _type: 'customer' }, | |
labelAttr: 'name' | |
}, dojo.byId('customerNode')); | |
customer.startup(); | |
var status = new ComboBox({ | |
store: store, | |
query: { _type: 'orderStatus' }, | |
labelAttr: 'name' | |
}, dojo.byId('statusNode')); | |
status.startup(); | |
var fnDisplayOrders = function() { | |
var contentNode = dojo.byId("content"); | |
var displayedOrder = false; | |
domConstruct.empty(contentNode); | |
var result = store.query({ | |
_type: 'order', | |
customer: customer.get('item'), | |
orderStatus: status.get('item'), | |
}); | |
result.forEach(function(order) { | |
displayedOrder = true; | |
var div = dojo.create('div', {}, contentNode); | |
dojo.addClass(div, 'order'); | |
var header = dojo.create('div', {}, div); | |
dojo.addClass(header, 'orderHeader'); | |
header.innerHTML = dojo.replace( | |
'Order #: {orderNumber}<br/>{customer.name}<br/>{customer.address.address1}<br/>{customer.address.address2}', | |
order ); | |
dojo.create('hr', {}, div); | |
var table = dojo.create('table', { width: '100%' }, div); | |
var itemsHeaderRow = | |
dojo.create('tr', {}, | |
dojo.create('thead', {}, table)); | |
dojo.create('th', { style: 'text-align:left;'}, itemsHeaderRow).innerHTML = 'Product'; | |
dojo.create('th', { style: 'text-align:right;'}, itemsHeaderRow).innerHTML = 'Unit<br/>Price'; | |
dojo.create('th', { style: 'text-align:right;'}, itemsHeaderRow).innerHTML = 'Quantity'; | |
dojo.create('th', { style: 'text-align:right;'}, itemsHeaderRow).innerHTML = 'Extended<br/>Amount'; | |
var items = dojo.create('tbody', {}, table); | |
var fnCreateRightAlignedCell = function(tr, content) { | |
var td = dojo.create('td', {}, tr); | |
dojo.style(td, 'text-align', 'right'); | |
td.innerHTML = content; | |
}; | |
dojo.forEach(order.lineItems, function(lineItem) { | |
var tr = dojo.create('tr', {}, items); | |
dojo.create('td', {}, tr).innerHTML = lineItem.product.name; | |
fnCreateRightAlignedCell(tr, curr.format(lineItem.price)); | |
fnCreateRightAlignedCell(tr, lineItem.quantity); | |
fnCreateRightAlignedCell(tr, curr.format(lineItem.price * lineItem.quantity)); | |
}); | |
}); | |
if (displayedOrder == false) { | |
var div = dojo.create('div', {}, contentNode); | |
dojo.addClass(div, 'order'); | |
div.innerHTML = "There were no orders to display."; | |
} | |
}; | |
dojo.connect(customer, 'onChange', fnDisplayOrders); | |
dojo.connect(status, 'onChange', fnDisplayOrders); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment