Skip to content

Instantly share code, notes, and snippets.

@dkullmann
Created November 7, 2011 17:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dkullmann/1345555 to your computer and use it in GitHub Desktop.
Save dkullmann/1345555 to your computer and use it in GitHub Desktop.
Mustache Iteration Example w/Backbone and an array of objects
jQuery(function() {
var Property = Backbone.Model.extend({
/**
* Primary key-like ID for each model
*/
idAttribute: 'ListingKey',
/**
* Default attributes for each model
*/
defaults: {
/**
* Tabs for the 'Features' section, in order
*/
featureTabs: [ 'interior', 'exterior', 'utilities', 'development', 'additional' ],
/**
* Settings for the 'Features' section of the 'Details' tab
* An ordered list of key value pairs
*/
featureFields: {
interior: [
{ 'Rooms':'Rooms' },
{ 'Bedroom Features':'BedroomFeatures' },
{ 'Bathroom Features':'BathroomFeatures' },
{ 'Full Baths':'BathFull' },
{ '3/4 Baths':'BathThreeQuarter' },
{ 'Half Baths':'BathHalf' },
{ '1/4 Baths':'BathQuarter' },
{ 'Kitchen Features':'KitchenFeatures' },
{ 'Cooking Appliances':'CookingAppliances' },
{ 'Appliances':'Appliances' },
{ 'Eating Areas':'EatingAreas' },
{ 'Interior Features':'InteriorFeatures' },
{ 'Fireplace Rooms':'FireplaceRooms' },
{ 'Fireplace Features':'FireplaceFeatures' },
{ 'Fireplace Fuel':'FirePlaceFuel' },
{ 'Floor Material':'FloorMaterial' },
{ 'Doors':'Doors' },
{ 'Windows':'Windows' },
{ 'Laundry Locations':'LaundryLocations' },
{ '# of Remote Controls':'NumberOfRemoteControls' }
],
exterior: [
{ 'Exterior Construction':'ExteriorConstruction' },
{ 'Building Structure Style':'BuildingStructureStyle' },
{ 'Other Structural Features':'OtherStructuralFeatures' },
{ 'Common Walls':'CommonWalls' },
{ 'Building Size':'BuildingSize' },
{ 'Disability Access':'DisabilityAccess' },
{ 'Foundation Details':'FoundationDetails' },
{ 'Roofing':'Roofing' },
{ 'Fence':'Fence' },
{ 'Patio Features':'PatioFeatures' },
{ 'Sprinklers':'Sprinklers' },
{ 'Security/Safety':'SecuritySafety' },
{ 'Spa Descriptions':'SpaDescriptions' },
{ 'Spa Construction':'SpaConstruction' },
{ 'Pool Descriptions':'PoolDescriptions' },
{ 'Pool Construction':'PoolConstruction' },
{ 'Pool Accessories':'PoolAccessories' },
{ 'Parking Spaces Total':'ParkingSpacesTotal' },
{ 'Parking Type':'ParkingType' },
{ 'Parking Features':'ParkingFeatures' },
{ 'Garage Spaces Total':'GarageSpacesTotal' },
{ 'Covered Spaces Total':'CoveredSpacesTotal' },
{ 'Carport Spaces Total':'CarportSpacesTotal' },
{ 'Open Other Spaces Total':'OpenOtherSpacesTotal' },
{ 'RV Access Dimensions':'RVAccessDimensions' },
{ 'Lot Description':'LotDescription' },
{ 'Lot Size Acres':'LotSizeAcres' },
{ 'Lot Size Description':'LotSizeDimensionDescription' },
{ 'Lot Location':'LotLocation' },
{ 'View':'View' }
],
utilities: [
{ 'Water District':'WaterDistrict' },
{ 'Water':'Water' },
{ 'Water Heater Features':'WaterHeaterFeatures' },
{ 'Sewer':'Sewer' },
{ 'Cooling Type':'CoolingType' },
{ 'Heating Type':'HeatingType' },
{ 'Heating Fuel':'HeatingFuel' },
{ '220 Volt Locations':'Volt220Locations' },
{ 'TV Services':'TVServices' }
],
development: [
{ 'Total Units':'UnitsTotalInComplex' },
{ 'Unit Floor in Building':'UnitFloorInBuilding' },
{ 'Unit Location':'UnitLocation' },
{ 'Mid-High Rise Amenities':'HighMidRiseAmenities' },
{ 'HOA Fees':'HOAFee1' },
{ 'HOA Fee Frequency':'HOAFeeFrequency1' },
{ 'HOA Fees 2':'HOAFee2' },
{ 'HOA Fees 2 Frequency':'HOAFeeFrequency2' },
{ 'Other Association Fees':'OtherAssociationFees' },
{ 'Association Fees Include':'AssociationFeesInclude' },
{ 'Association Amenities':'AssociationAmenities' },
{ 'Association Rules':'AssociationRules' },
{ 'Association Name':'AssociationName' },
{ 'Inclusions':'Inclusions' },
{ 'Community Features':'CommunityFeatures' },
{ 'Playing Courts':'PlayingCourts' },
{ 'Mello Roos Tax':'TaxMelloRoos' },
{ 'Builders Name':'BuildersName' },
{ 'Builders Model Name':'BuildersModelName' },
{ 'Builders Tract Name':'BuildersTractName' },
{ 'Builders Tract Code':'BuildersTractCode' },
{ 'Tax Parcel Number':'TaxParcelNumber' },
{ 'Tax Legal Lot Number':'TaxLegalLotNumber' },
{ 'Tax Legal Tract Number':'TaxLegalTractNumber' },
{ 'Zoning':'Zoning' }
],
additional: [
{ 'Original List Price':'OriginalListPrice' },
{ 'Driving Directions':'DrivingDirections' },
{ 'Cross Streets':'CrossStreets' },
{ 'Thomas Guide':'ThomasGuideFullMapString' },
{ 'Area':'Area' },
{ 'Area Other':'AreaOther' },
{ 'City Other':'CityOther' },
{ 'School District':'SchoolDistrict' },
{ 'High School':'HighSchool' },
{ 'Junior/Middle School':'JuniorMiddleSchool' },
{ 'Elementary School':'ElementarySchool' },
{ 'Stories':'Stories' },
{ 'Total Floors':'TotalFloors' },
{ 'Entry Floor Number':'EntryFloorNumber' },
{ 'Entry Location':'EntryLocation' },
{ 'Other Structures':'OtherStructures' },
{ 'Property Condition':'PropertyCondition' },
{ 'Property Faces Direction':'DirectionFaces' },
{ 'Square Footage Source':'SquareFootageSource' },
{ 'Lot Size Source':'LotSizeSource' },
{ 'Year Built Source':'YearBuiltSource' },
{ 'Will Consider Lease':'WillConsiderLease' },
{ 'Land Lease Type':'LandLeaseType' },
{ 'Land Lease Amount Per Year':'LandLeaseAmountPerYear' },
{ 'Land Lease Expiration Date':'LandLeaseExpirationDate'}
]
}
}
});
var Properties = Backbone.Collection.extend({ model: Property });
var PropertyDetailView = Backbone.View.extend({
el: '#property-details',
template: window.templates.propertyDetails,
render: function( options ) {
if( options.model ) {
this.model = options.model;
}
// Include view methods and model attributes
this.viewData = jQuery.extend({}, this.model.toJSON(), this.viewMethods());
// Render the view
jQuery(this.el).html(Mustache.to_html(this.template, this.viewData));
// Place rendered template into the existing element
jQuery(this.el).find('#property-details-tabs').tabs();
// Allow chaining
return this;
},
/**
* Extra methods to have available to the view
*/
viewMethods: function() {
/* Give the methods access to the model */
var thisView = this;
var thisModel = this.model;
return {
/**
* Build a table of ordered key => value pairs. Can't do this
* in mustache.js because we can't iterate objects unless they have
* the same keys
*/
table: function() {
return function(name, render) {
// Retrieve the actual name
name = render(name);
var rows = '',
rowClass = 'even',
rowCount = 0,
fields = thisModel.attributes.featureFields[name],
table = '<table class="pf-table"><tbody>';
// Need two loops here, one for order and another for key => value pairs
for (i in fields) {
for (label in fields[i]) {
var key = fields[i][label];
var value = thisModel.attributes[key] ? thisModel.attributes[key] : 'n/a';
if( i%2 == 0 ) {
if( rowCount%2 == 0 ) { rowClass = 'even'; }
else { rowClass = 'odd'; }
rowCount++;
rows += '<tr class="pf-row '+rowClass+'">';
}
rows += [ '<td class="pf-cell"><strong class="pf-label">', label, ':</strong><p class="pf-value">', value, '</p></td>' ].join('');
if( i%2 == 1 ) { rows += "</tr>\n"; }
}
}
table += rows + '</tbody></table>';
return table;
};
}
};
}
});
/* Global */
window.Comps = new Properties;
window.Comps.reset(window.backbone_models);
window.DetailView = new PropertyDetailView();
/* Initialize the subject property */
window.DetailView.render({ model: Comps.get( window.subject_property.Property.ListingKey ) });
}
window.templates = {
propertyDetails: [
'<div class="property-detail-header">',
'<h3 class="address">{{FullStreetAddress}}<span class="city-state">{{City}}, {{State}} {{ZipCode}}</span></h3>',
'<span class="price-label">List Price: <span class="price">{{ListPrice}}</span></span>',
'<span class="dom">DOM: <span class="dom-count">{{DOM}}</span></span>',
'<a href="fix-me" class="street-view-link property-link">street view</a>',
'</div>',
'<ul class="property-quick-details">',
'<li class="property-icon"><img src="/img/properties/search/singlefamily-sold.png" alt=""></li>',
'<li>{{ListingStatus}}</li>',
'<li>{{SaleCode}}</li>',
'<li>{{BedroomsTotal}} BDS</li>',
'<li>{{BathsTotal}} BTHS</li>',
'<li>{{BuildingSize}} SF</li>',
'<li>{{LotSizeSQFT}} LOT</li>',
'<li>{{YearBuilt}} YR</li></ul>',
'</ul>',
'<div class="property-description">',
'<h3 class="comp-section-header">Description</h3>',
'<p>{{PublicRemarks}}</p>',
'</div>',
'<div class="property-features">',
'<h3 class="comp-section-header">Features</h3>',
'<div id="property-details-tabs">',
'<ul>',
'{{#featureTabs}}',
'<li><a href="#{{.}}">{{.}}</a></li>',
'{{/featureTabs}}',
'</ul>',
'{{#featureTabs}}',
'<div id="{{.}}" class="properties">',
'{{#table}}{{.}}{{/table}}',
'</div>',
'{{/featureTabs}}',
'</div>',
'</div>'
].join("\n")
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment