Created
July 16, 2014 02:36
-
-
Save jasonhinkle/163f862542fa44fa7fdc to your computer and use it in GitHub Desktop.
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
/** | |
* View logic for Packages | |
*/ | |
/** | |
* application logic specific to the Package listing page | |
*/ | |
var page = { | |
packages: new model.PackageCollection(), | |
collectionView: null, | |
package: null, | |
modelView: null, | |
isInitialized: false, | |
isInitializing: false, | |
fetchParams: { filter: '', orderBy: '', orderDesc: '', page: 1 }, | |
fetchInProgress: false, | |
dialogIsOpen: false, | |
/** | |
* | |
*/ | |
init: function() { | |
// ensure initialization only occurs once | |
if (page.isInitialized || page.isInitializing) return; | |
page.isInitializing = true; | |
if (!$.isReady && console) console.warn('page was initialized before dom is ready. views may not render properly.'); | |
// make the new button clickable | |
$("#newPackageButton").click(function(e) { | |
e.preventDefault(); | |
page.showDetailDialog(); | |
}); | |
// let the page know when the dialog is open | |
$('#packageDetailDialog').on('show',function() { | |
page.dialogIsOpen = true; | |
}); | |
// when the model dialog is closed, let page know and reset the model view | |
$('#packageDetailDialog').on('hidden',function() { | |
$('#modelAlert').html(''); | |
page.dialogIsOpen = false; | |
}); | |
// save the model when the save button is clicked | |
$("#savePackageButton").click(function(e) { | |
e.preventDefault(); | |
page.updateModel(); | |
}); | |
// initialize the collection view | |
this.collectionView = new view.CollectionView({ | |
el: $("#packageCollectionContainer"), | |
templateEl: $("#packageCollectionTemplate"), | |
collection: page.packages | |
}); | |
// initialize the search filter | |
$('#filter').change(function(obj) { | |
page.fetchParams.filter = $('#filter').val(); | |
page.fetchParams.page = 1; | |
page.fetchPackages(page.fetchParams); | |
}); | |
// make the rows clickable ('rendered' is a custom event, not a standard backbone event) | |
this.collectionView.on('rendered',function(){ | |
// attach click handler to the table rows for editing | |
$('table.collection tbody tr').click(function(e) { | |
e.preventDefault(); | |
var m = page.packages.get(this.id); | |
page.showDetailDialog(m); | |
}); | |
// make the headers clickable for sorting | |
$('table.collection thead tr th').click(function(e) { | |
e.preventDefault(); | |
var prop = this.id.replace('header_',''); | |
// toggle the ascending/descending before we change the sort prop | |
page.fetchParams.orderDesc = (prop == page.fetchParams.orderBy && !page.fetchParams.orderDesc) ? '1' : ''; | |
page.fetchParams.orderBy = prop; | |
page.fetchParams.page = 1; | |
page.fetchPackages(page.fetchParams); | |
}); | |
// attach click handlers to the pagination controls | |
$('.pageButton').click(function(e) { | |
e.preventDefault(); | |
page.fetchParams.page = this.id.substr(5); | |
page.fetchPackages(page.fetchParams); | |
}); | |
page.isInitialized = true; | |
page.isInitializing = false; | |
}); | |
// backbone docs recommend bootstrapping data on initial page load, but we live by our own rules! | |
this.fetchPackages({ page: 1 }); | |
// initialize the model view | |
this.modelView = new view.ModelView({ | |
el: $("#packageModelContainer") | |
}); | |
// tell the model view where it's template is located | |
this.modelView.templateEl = $("#packageModelTemplate"); | |
if (model.longPollDuration > 0) { | |
setInterval(function () { | |
if (!page.dialogIsOpen) { | |
page.fetchPackages(page.fetchParams,true); | |
} | |
}, model.longPollDuration); | |
} | |
}, | |
/** | |
* Fetch the collection data from the server | |
* @param object params passed through to collection.fetch | |
* @param bool true to hide the loading animation | |
*/ | |
fetchPackages: function(params, hideLoader) { | |
// persist the params so that paging/sorting/filtering will play together nicely | |
page.fetchParams = params; | |
if (page.fetchInProgress) { | |
if (console) console.log('supressing fetch because it is already in progress'); | |
} | |
page.fetchInProgress = true; | |
if (!hideLoader) app.showProgress('loader'); | |
page.packages.fetch({ | |
data: params, | |
success: function() { | |
if (page.packages.collectionHasChanged) { | |
// TODO: add any logic necessary if the collection has changed | |
// the sync event will trigger the view to re-render | |
} | |
app.hideProgress('loader'); | |
page.fetchInProgress = false; | |
}, | |
error: function(m, r) { | |
app.appendAlert(app.getErrorMessage(r), 'alert-error',0,'collectionAlert'); | |
app.hideProgress('loader'); | |
page.fetchInProgress = false; | |
} | |
}); | |
}, | |
/** | |
* show the dialog for editing a model | |
* @param model | |
*/ | |
showDetailDialog: function(m) { | |
// show the modal dialog | |
$('#packageDetailDialog').modal({ show: true }); | |
// if a model was specified then that means a user is editing an existing record | |
// if not, then the user is creating a new record | |
page.package = m ? m : new model.PackageModel(); | |
page.modelView.model = page.package; | |
if (page.package.id == null || page.package.id == '') { | |
// this is a new record, there is no need to contact the server | |
page.renderModelView(false); | |
} else { | |
app.showProgress('modelLoader'); | |
// fetch the model from the server so we are not updating stale data | |
page.package.fetch({ | |
success: function() { | |
// data returned from the server. render the model view | |
page.renderModelView(true); | |
}, | |
error: function(m, r) { | |
app.appendAlert(app.getErrorMessage(r), 'alert-error',0,'modelAlert'); | |
app.hideProgress('modelLoader'); | |
} | |
}); | |
} | |
}, | |
/** | |
* Render the model template in the popup | |
* @param bool show the delete button | |
*/ | |
renderModelView: function(showDeleteButton) { | |
page.modelView.render(); | |
app.hideProgress('modelLoader'); | |
// initialize any special controls | |
try { | |
$('.date-picker') | |
.datepicker() | |
.on('changeDate', function(ev){ | |
$('.date-picker').datepicker('hide'); | |
}); | |
} catch (error) { | |
// this happens if the datepicker input.value isn't a valid date | |
if (console) console.log('datepicker error: '+error.message); | |
} | |
$('.timepicker-default').timepicker({ defaultTime: 'value' }); | |
// populate the dropdown options for customerId | |
// TODO: load only the selected value, then fetch all options when the drop-down is clicked | |
var customerIdValues = new model.CustomerCollection(); | |
customerIdValues.fetch({ | |
success: function(c){ | |
var dd = $('#customerId'); | |
dd.append('<option value=""></option>'); | |
c.forEach(function(item,index) { | |
dd.append(app.getOptionHtml( | |
item.get('id'), | |
item.get('name'), // TODO: change fieldname if the dropdown doesn't show the desired column | |
page.package.get('customerId') == item.get('id') | |
)); | |
}); | |
if (!app.browserSucks()) { | |
dd.combobox(); | |
$('div.combobox-container + span.help-inline').hide(); // TODO: hack because combobox is making the inline help div have a height | |
} | |
}, | |
error: function(collection,response,scope) { | |
app.appendAlert(app.getErrorMessage(response), 'alert-error',0,'modelAlert'); | |
} | |
}); | |
// populate the dropdown options for service | |
// TODO: load only the selected value, then fetch all options when the drop-down is clicked | |
var serviceValues = new model.ServiceCollection(); | |
serviceValues.fetch({ | |
success: function(c){ | |
var dd = $('#service'); | |
dd.append('<option value=""></option>'); | |
c.forEach(function(item,index) { | |
dd.append(app.getOptionHtml( | |
item.get('id'), | |
item.get('id'), // TODO: change fieldname if the dropdown doesn't show the desired column | |
page.package.get('service') == item.get('id') | |
)); | |
}); | |
if (!app.browserSucks()) { | |
dd.combobox(); | |
$('div.combobox-container + span.help-inline').hide(); // TODO: hack because combobox is making the inline help div have a height | |
} | |
}, | |
error: function(collection,response,scope) { | |
app.appendAlert(app.getErrorMessage(response), 'alert-error',0,'modelAlert'); | |
} | |
}); | |
if (showDeleteButton) { | |
// attach click handlers to the delete buttons | |
$('#deletePackageButton').click(function(e) { | |
e.preventDefault(); | |
$('#confirmDeletePackageContainer').show('fast'); | |
}); | |
$('#cancelDeletePackageButton').click(function(e) { | |
e.preventDefault(); | |
$('#confirmDeletePackageContainer').hide('fast'); | |
}); | |
$('#confirmDeletePackageButton').click(function(e) { | |
e.preventDefault(); | |
page.deleteModel(); | |
}); | |
} else { | |
// no point in initializing the click handlers if we don't show the button | |
$('#deletePackageButtonContainer').hide(); | |
} | |
}, | |
/** | |
* update the model that is currently displayed in the dialog | |
*/ | |
updateModel: function() { | |
// reset any previous errors | |
$('#modelAlert').html(''); | |
$('.control-group').removeClass('error'); | |
$('.help-inline').html(''); | |
// if this is new then on success we need to add it to the collection | |
var isNew = page.package.isNew(); | |
app.showProgress('modelLoader'); | |
page.package.save({ | |
'shipDate': $('input#shipDate').val(), | |
'shipTime': $('input#shipTime').val()+' '+$('input#shipTime-time').val(), | |
'customerId': $('select#customerId').val(), | |
'trackingNumber': $('input#trackingNumber').val(), | |
'description': $('textarea#description').val(), | |
'service': $('select#service').val(), | |
'destination': $('input#destination').val() | |
}, { | |
wait: true, | |
success: function(){ | |
$('#packageDetailDialog').modal('hide'); | |
setTimeout("app.appendAlert('Package was sucessfully " + (isNew ? "inserted" : "updated") + "','alert-success',3000,'collectionAlert')",500); | |
app.hideProgress('modelLoader'); | |
// if the collection was initally new then we need to add it to the collection now | |
if (isNew) { page.packages.add(page.package) } | |
if (model.reloadCollectionOnModelUpdate) { | |
// re-fetch and render the collection after the model has been updated | |
page.fetchPackages(page.fetchParams,true); | |
} | |
}, | |
error: function(model,response,scope){ | |
app.hideProgress('modelLoader'); | |
app.appendAlert(app.getErrorMessage(response), 'alert-error',0,'modelAlert'); | |
try { | |
var json = $.parseJSON(response.responseText); | |
if (json.errors) { | |
$.each(json.errors, function(key, value) { | |
$('#'+key+'InputContainer').addClass('error'); | |
$('#'+key+'InputContainer span.help-inline').html(value); | |
$('#'+key+'InputContainer span.help-inline').show(); | |
}); | |
} | |
} catch (e2) { | |
if (console) console.log('error parsing server response: '+e2.message); | |
} | |
} | |
}); | |
}, | |
/** | |
* delete the model that is currently displayed in the dialog | |
*/ | |
deleteModel: function() { | |
// reset any previous errors | |
$('#modelAlert').html(''); | |
app.showProgress('modelLoader'); | |
page.package.destroy({ | |
wait: true, | |
success: function(){ | |
$('#packageDetailDialog').modal('hide'); | |
setTimeout("app.appendAlert('The Package record was deleted','alert-success',3000,'collectionAlert')",500); | |
app.hideProgress('modelLoader'); | |
if (model.reloadCollectionOnModelUpdate) { | |
// re-fetch and render the collection after the model has been updated | |
page.fetchPackages(page.fetchParams,true); | |
} | |
}, | |
error: function(model,response,scope) { | |
app.appendAlert(app.getErrorMessage(response), 'alert-error',0,'modelAlert'); | |
app.hideProgress('modelLoader'); | |
} | |
}); | |
} | |
}; | |
/** BELOW WAS COPY/PASTED FROM purchases.js AND THEN SEARCH/REPLACE "page" with "page2" **/ | |
/** | |
* application logic specific to the Purchase listing page2 | |
*/ | |
var page2 = { | |
purchases: new model.PurchaseCollection(), | |
collectionView: null, | |
purchase: null, | |
modelView: null, | |
isInitialized: false, | |
isInitializing: false, | |
fetchParams: { filter: '', orderBy: '', orderDesc: '', page2: 1 }, | |
fetchInProgress: false, | |
dialogIsOpen: false, | |
/** | |
* | |
*/ | |
init: function() { | |
// ensure initialization only occurs once | |
if (page2.isInitialized || page2.isInitializing) return; | |
page2.isInitializing = true; | |
if (!$.isReady && console) console.warn('page2 was initialized before dom is ready. views may not render properly.'); | |
// make the new button clickable | |
$("#newPurchaseButton").click(function(e) { | |
e.preventDefault(); | |
page2.showDetailDialog(); | |
}); | |
// let the page2 know when the dialog is open | |
$('#purchaseDetailDialog').on('show',function() { | |
page2.dialogIsOpen = true; | |
}); | |
// when the model dialog is closed, let page2 know and reset the model view | |
$('#purchaseDetailDialog').on('hidden',function() { | |
$('#modelAlert').html(''); | |
page2.dialogIsOpen = false; | |
}); | |
// save the model when the save button is clicked | |
$("#savePurchaseButton").click(function(e) { | |
e.preventDefault(); | |
page2.updateModel(); | |
}); | |
// initialize the collection view | |
this.collectionView = new view.CollectionView({ | |
el: $("#purchaseCollectionContainer"), | |
templateEl: $("#purchaseCollectionTemplate"), | |
collection: page2.purchases | |
}); | |
// initialize the search filter | |
$('#filter').change(function(obj) { | |
page2.fetchParams.filter = $('#filter').val(); | |
page2.fetchParams.page2 = 1; | |
page2.fetchPurchases(page2.fetchParams); | |
}); | |
// make the rows clickable ('rendered' is a custom event, not a standard backbone event) | |
this.collectionView.on('rendered',function(){ | |
// attach click handler to the table rows for editing | |
$('table.collection tbody tr').click(function(e) { | |
e.preventDefault(); | |
var m = page2.purchases.get(this.id); | |
page2.showDetailDialog(m); | |
}); | |
// make the headers clickable for sorting | |
$('table.collection thead tr th').click(function(e) { | |
e.preventDefault(); | |
var prop = this.id.replace('header_',''); | |
// toggle the ascending/descending before we change the sort prop | |
page2.fetchParams.orderDesc = (prop == page2.fetchParams.orderBy && !page2.fetchParams.orderDesc) ? '1' : ''; | |
page2.fetchParams.orderBy = prop; | |
page2.fetchParams.page2 = 1; | |
page2.fetchPurchases(page2.fetchParams); | |
}); | |
// attach click handlers to the pagination controls | |
$('.page2Button').click(function(e) { | |
e.preventDefault(); | |
page2.fetchParams.page2 = this.id.substr(5); | |
page2.fetchPurchases(page2.fetchParams); | |
}); | |
page2.isInitialized = true; | |
page2.isInitializing = false; | |
}); | |
// backbone docs recommend bootstrapping data on initial page2 load, but we live by our own rules! | |
this.fetchPurchases({ page2: 1 }); | |
// initialize the model view | |
this.modelView = new view.ModelView({ | |
el: $("#purchaseModelContainer") | |
}); | |
// tell the model view where it's template is located | |
this.modelView.templateEl = $("#purchaseModelTemplate"); | |
if (model.longPollDuration > 0) { | |
setInterval(function () { | |
if (!page2.dialogIsOpen) { | |
page2.fetchPurchases(page2.fetchParams,true); | |
} | |
}, model.longPollDuration); | |
} | |
}, | |
/** | |
* Fetch the collection data from the server | |
* @param object params passed through to collection.fetch | |
* @param bool true to hide the loading animation | |
*/ | |
fetchPurchases: function(params, hideLoader) { | |
// persist the params so that paging/sorting/filtering will play together nicely | |
page2.fetchParams = params; | |
if (page2.fetchInProgress) { | |
if (console) console.log('supressing fetch because it is already in progress'); | |
} | |
page2.fetchInProgress = true; | |
if (!hideLoader) app.showProgress('loader'); | |
page2.purchases.fetch({ | |
data: params, | |
success: function() { | |
if (page2.purchases.collectionHasChanged) { | |
// TODO: add any logic necessary if the collection has changed | |
// the sync event will trigger the view to re-render | |
} | |
app.hideProgress('loader'); | |
page2.fetchInProgress = false; | |
}, | |
error: function(m, r) { | |
app.appendAlert(app.getErrorMessage(r), 'alert-error',0,'collectionAlert'); | |
app.hideProgress('loader'); | |
page2.fetchInProgress = false; | |
} | |
}); | |
}, | |
/** | |
* show the dialog for editing a model | |
* @param model | |
*/ | |
showDetailDialog: function(m) { | |
// show the modal dialog | |
$('#purchaseDetailDialog').modal({ show: true }); | |
// if a model was specified then that means a user is editing an existing record | |
// if not, then the user is creating a new record | |
page2.purchase = m ? m : new model.PurchaseModel(); | |
page2.modelView.model = page2.purchase; | |
if (page2.purchase.id == null || page2.purchase.id == '') { | |
// this is a new record, there is no need to contact the server | |
page2.renderModelView(false); | |
} else { | |
app.showProgress('modelLoader'); | |
// fetch the model from the server so we are not updating stale data | |
page2.purchase.fetch({ | |
success: function() { | |
// data returned from the server. render the model view | |
page2.renderModelView(true); | |
}, | |
error: function(m, r) { | |
app.appendAlert(app.getErrorMessage(r), 'alert-error',0,'modelAlert'); | |
app.hideProgress('modelLoader'); | |
} | |
}); | |
} | |
}, | |
/** | |
* Render the model template in the popup | |
* @param bool show the delete button | |
*/ | |
renderModelView: function(showDeleteButton) { | |
page2.modelView.render(); | |
app.hideProgress('modelLoader'); | |
// initialize any special controls | |
try { | |
$('.date-picker') | |
.datepicker() | |
.on('changeDate', function(ev){ | |
$('.date-picker').datepicker('hide'); | |
}); | |
} catch (error) { | |
// this happens if the datepicker input.value isn't a valid date | |
if (console) console.log('datepicker error: '+error.message); | |
} | |
$('.timepicker-default').timepicker({ defaultTime: 'value' }); | |
// populate the dropdown options for statusCodeId | |
// TODO: load only the selected value, then fetch all options when the drop-down is clicked | |
var statusCodeIdValues = new model.StatusCodeCollection(); | |
statusCodeIdValues.fetch({ | |
success: function(c){ | |
var dd = $('#statusCodeId'); | |
dd.append('<option value=""></option>'); | |
c.forEach(function(item,index) { | |
dd.append(app.getOptionHtml( | |
item.get('id'), | |
item.get('id'), // TODO: change fieldname if the dropdown doesn't show the desired column | |
page2.purchase.get('statusCodeId') == item.get('id') | |
)); | |
}); | |
if (!app.browserSucks()) { | |
dd.combobox(); | |
$('div.combobox-container + span.help-inline').hide(); // TODO: hack because combobox is making the inline help div have a height | |
} | |
}, | |
error: function(collection,response,scope) { | |
app.appendAlert(app.getErrorMessage(response), 'alert-error',0,'modelAlert'); | |
} | |
}); | |
if (showDeleteButton) { | |
// attach click handlers to the delete buttons | |
$('#deletePurchaseButton').click(function(e) { | |
e.preventDefault(); | |
$('#confirmDeletePurchaseContainer').show('fast'); | |
}); | |
$('#cancelDeletePurchaseButton').click(function(e) { | |
e.preventDefault(); | |
$('#confirmDeletePurchaseContainer').hide('fast'); | |
}); | |
$('#confirmDeletePurchaseButton').click(function(e) { | |
e.preventDefault(); | |
page2.deleteModel(); | |
}); | |
} else { | |
// no point in initializing the click handlers if we don't show the button | |
$('#deletePurchaseButtonContainer').hide(); | |
} | |
}, | |
/** | |
* update the model that is currently displayed in the dialog | |
*/ | |
updateModel: function() { | |
// reset any previous errors | |
$('#modelAlert').html(''); | |
$('.control-group').removeClass('error'); | |
$('.help-inline').html(''); | |
// if this is new then on success we need to add it to the collection | |
var isNew = page2.purchase.isNew(); | |
app.showProgress('modelLoader'); | |
page2.purchase.save({ | |
'statusCodeId': $('select#statusCodeId').val(), | |
'quantity': $('input#quantity').val(), | |
'description': $('input#description').val() | |
}, { | |
wait: true, | |
success: function(){ | |
$('#purchaseDetailDialog').modal('hide'); | |
setTimeout("app.appendAlert('Purchase was sucessfully " + (isNew ? "inserted" : "updated") + "','alert-success',3000,'collectionAlert')",500); | |
app.hideProgress('modelLoader'); | |
// if the collection was initally new then we need to add it to the collection now | |
if (isNew) { page2.purchases.add(page2.purchase) } | |
if (model.reloadCollectionOnModelUpdate) { | |
// re-fetch and render the collection after the model has been updated | |
page2.fetchPurchases(page2.fetchParams,true); | |
} | |
}, | |
error: function(model,response,scope){ | |
app.hideProgress('modelLoader'); | |
app.appendAlert(app.getErrorMessage(response), 'alert-error',0,'modelAlert'); | |
try { | |
var json = $.parseJSON(response.responseText); | |
if (json.errors) { | |
$.each(json.errors, function(key, value) { | |
$('#'+key+'InputContainer').addClass('error'); | |
$('#'+key+'InputContainer span.help-inline').html(value); | |
$('#'+key+'InputContainer span.help-inline').show(); | |
}); | |
} | |
} catch (e2) { | |
if (console) console.log('error parsing server response: '+e2.message); | |
} | |
} | |
}); | |
}, | |
/** | |
* delete the model that is currently displayed in the dialog | |
*/ | |
deleteModel: function() { | |
// reset any previous errors | |
$('#modelAlert').html(''); | |
app.showProgress('modelLoader'); | |
page2.purchase.destroy({ | |
wait: true, | |
success: function(){ | |
$('#purchaseDetailDialog').modal('hide'); | |
setTimeout("app.appendAlert('The Purchase record was deleted','alert-success',3000,'collectionAlert')",500); | |
app.hideProgress('modelLoader'); | |
if (model.reloadCollectionOnModelUpdate) { | |
// re-fetch and render the collection after the model has been updated | |
page2.fetchPurchases(page2.fetchParams,true); | |
} | |
}, | |
error: function(model,response,scope) { | |
app.appendAlert(app.getErrorMessage(response), 'alert-error',0,'modelAlert'); | |
app.hideProgress('modelLoader'); | |
} | |
}); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment