Last active
May 17, 2017 16:41
-
-
Save jplwood/b00e8d01302169468f1d114d578c6600 to your computer and use it in GitHub Desktop.
ng1 excel file upload and client side XLSX parsing
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
angular.module('acrSelect.portal.directives') | |
.directive('organizationImport', function () { | |
return { | |
restrict: 'E', | |
templateUrl: '/app/templates/organization/organizationImport.html?v=' + window.ApplicationBuildVersion, | |
scope: { | |
'organizations': '=', | |
'timeZones': '=', | |
'utils': '=' | |
}, | |
link: function ($scope, $element, attrs) { | |
}, | |
controller: ['$scope', 'organizationChannel', 'organizationService', 'Upload', function ($scope, organizationChannel, organizationService, Upload) { | |
$scope.cancelImport = function () { | |
$scope.importFile = null; | |
organizationChannel.organizationImportStateChanged({ importing: false }); | |
} | |
/* | |
* Function to import excel file and import an organization | |
* @param {Object} file - xlsx file selected by user | |
*/ | |
function importOrganization(file, organizations) { | |
var reader = new FileReader(); | |
reader.onload = function (e) { | |
try { | |
var data = e.target.result; | |
var arr = fixData(data); | |
var wb = XLSX.read(btoa(arr), { type: 'base64' }); | |
if (wb.SheetNames && wb.SheetNames.length === 1 && wb.SheetNames[0] === "Organization") { | |
var importedOrg = extractJson(wb); | |
var errors = validateImportedOrganization(organizations, importedOrg); | |
if (errors) { | |
throw errors; | |
} else { | |
saveImportedOrganization(importedOrg); | |
} | |
} else { | |
throw "Incorrect file template. You may only use a file exported from this page in different environment." | |
} | |
} catch (ex) { | |
notifyErrorModal("Import was unsuccessful<br><small>" + ex + "</small>"); | |
} | |
}; | |
reader.readAsArrayBuffer(file); | |
} | |
$scope.importOrganization = importOrganization; // Add import fn to the scope | |
function saveImportedOrganization(organization) { | |
setLoadingState(true); | |
return organizationService.createOrganization(organization).then(function (data) { | |
//Not using service message to specify that this was an import, not just a create. | |
setLoadingState(false); | |
$scope.importFile = null; | |
notifySuccessModal(data.message + "<br><small>Successfully imported organization <br><span class='label label-primary'>ID: " + data.organizationId + "</span> " + organization.organizationName); | |
organizationChannel.organizationAdded({ organizationId: data.organizationId }); | |
}, function (reason) { | |
notifyErrorModal(reason); | |
}); | |
} | |
function validateImportedOrganization(orgs, org) { | |
var errors = ""; | |
// Check that this org id isn't blank and doesn't already exist, throw error if it does | |
if (!org.organizationId) { | |
errors += "The organization ID cannot be blank.<br>"; | |
} else if ($scope.utils.checkIdAvailable(orgs, org.organizationId)) { | |
errors += "The organization ID <code>" + org.organizationId + "</code> already exists in this environment.<br>" | |
} | |
// Check that this org name isn't blank and doesn't already exist, throw error if it does | |
if (!org.organizationName) { | |
errors += "The organization Name cannot be blank.<br>"; | |
} else if ($scope.utils.checkNameAvailable(orgs, org.organizationName)) { | |
errors += "The organization name <code>" + org.organizationName + "</code>, already exists in this environment.<br>" | |
} | |
return errors; | |
} | |
/* | |
* Helper function to turn the excel workbook into a JS object | |
* @param {Object} workbook - XLSX object representing excel workbook | |
*/ | |
function extractJson(workbook) { | |
var organizations = XLSX.utils.sheet_to_row_object_array(workbook.Sheets["Organization"]); | |
if (organizations.length > 0) { | |
var importOrg = organizations[0]; | |
importOrg.integrationTypes = parseObjProp(importOrg, "integrationTypes"); | |
importOrg.paidFeatures = parseObjProp(importOrg, "paidFeatures"); | |
importOrg.timeZone = $scope.utils.getTimeZoneObj($scope.timeZones, importOrg.timeZoneId); | |
return importOrg; | |
} else { | |
return null; | |
} | |
} | |
/* | |
* Helper function to parse a JSON string from an object property | |
* @param {Object} obj - object to operate on | |
* @param {string} prop - property name on object that has value that should be parsed | |
*/ | |
function parseObjProp(obj, prop) { | |
if (obj.hasOwnProperty(prop) && (typeof obj[prop] === "string" || obj[prop] instanceof String)) { | |
try { | |
return JSON.parse(obj[prop]); | |
} catch (ex) { | |
throw "The <i>" + prop + "</i> field is not in the correct format. It must be serialized JSON."; | |
} | |
} | |
} | |
/* | |
* Magical function taken from SheetJS example, cleans up data before XLSX reads it. | |
* @param {Array} data - data to be cleaned | |
*/ | |
function fixData(data) { | |
var o = "", l = 0, w = 10240; | |
for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w))); | |
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w))); | |
return o; | |
} | |
/** | |
* Set the loading state of this org detail directive | |
* @param {boolean} isLoading - whether the details are loading or not | |
*/ | |
function setLoadingState(isLoading) { | |
$scope.loading = isLoading; | |
} | |
}] | |
}; | |
} | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment