Skip to content

Instantly share code, notes, and snippets.

@jasonhinkle
Created July 16, 2014 02:36
Show Gist options
  • Save jasonhinkle/163f862542fa44fa7fdc to your computer and use it in GitHub Desktop.
Save jasonhinkle/163f862542fa44fa7fdc to your computer and use it in GitHub Desktop.
/**
* 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