ui-grid.importer.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. /*!
  2. * ui-grid - v4.4.6 - 2018-04-06
  3. * Copyright (c) 2018 ; License: MIT
  4. */
  5. (function () {
  6. 'use strict';
  7. /**
  8. * @ngdoc overview
  9. * @name ui.grid.importer
  10. * @description
  11. *
  12. * # ui.grid.importer
  13. *
  14. * <div class="alert alert-success" role="alert"><strong>Stable</strong> This feature is stable. There should no longer be breaking api changes without a deprecation warning.</div>
  15. *
  16. * This module provides the ability to import data into the grid. It
  17. * uses the column defs to work out which data belongs in which column,
  18. * and creates entities from a configured class (typically a $resource).
  19. *
  20. * If the rowEdit feature is enabled, it also calls save on those newly
  21. * created objects, and then displays any errors in the imported data.
  22. *
  23. * Currently the importer imports only CSV and json files, although provision has been
  24. * made to process other file formats, and these can be added over time.
  25. *
  26. * For json files, the properties within each object in the json must match the column names
  27. * (to put it another way, the importer doesn't process the json, it just copies the objects
  28. * within the json into a new instance of the specified object type)
  29. *
  30. * For CSV import, the default column identification relies on each column in the
  31. * header row matching a column.name or column.displayName. Optionally, a column identification
  32. * callback can be used. This allows matching using other attributes, which is particularly
  33. * useful if your application has internationalised column headings (i.e. the headings that
  34. * the user sees don't match the column names).
  35. *
  36. * The importer makes use of the grid menu as the UI for requesting an
  37. * import.
  38. *
  39. * <div ui-grid-importer></div>
  40. */
  41. var module = angular.module('ui.grid.importer', ['ui.grid']);
  42. /**
  43. * @ngdoc object
  44. * @name ui.grid.importer.constant:uiGridImporterConstants
  45. *
  46. * @description constants available in importer module
  47. */
  48. module.constant('uiGridImporterConstants', {
  49. featureName: 'importer'
  50. });
  51. /**
  52. * @ngdoc service
  53. * @name ui.grid.importer.service:uiGridImporterService
  54. *
  55. * @description Services for importer feature
  56. */
  57. module.service('uiGridImporterService', ['$q', 'uiGridConstants', 'uiGridImporterConstants', 'gridUtil', '$compile', '$interval', 'i18nService', '$window',
  58. function ($q, uiGridConstants, uiGridImporterConstants, gridUtil, $compile, $interval, i18nService, $window) {
  59. var service = {
  60. initializeGrid: function ($scope, grid) {
  61. //add feature namespace and any properties to grid for needed state
  62. grid.importer = {
  63. $scope: $scope
  64. };
  65. this.defaultGridOptions(grid.options);
  66. /**
  67. * @ngdoc object
  68. * @name ui.grid.importer.api:PublicApi
  69. *
  70. * @description Public Api for importer feature
  71. */
  72. var publicApi = {
  73. events: {
  74. importer: {
  75. }
  76. },
  77. methods: {
  78. importer: {
  79. /**
  80. * @ngdoc function
  81. * @name importFile
  82. * @methodOf ui.grid.importer.api:PublicApi
  83. * @description Imports a file into the grid using the file object
  84. * provided. Bypasses the grid menu
  85. * @param {File} fileObject the file we want to import, as a javascript
  86. * File object
  87. */
  88. importFile: function ( fileObject ) {
  89. service.importThisFile( grid, fileObject );
  90. }
  91. }
  92. }
  93. };
  94. grid.api.registerEventsFromObject(publicApi.events);
  95. grid.api.registerMethodsFromObject(publicApi.methods);
  96. if ( grid.options.enableImporter && grid.options.importerShowMenu ){
  97. if ( grid.api.core.addToGridMenu ){
  98. service.addToMenu( grid );
  99. } else {
  100. // order of registration is not guaranteed, register in a little while
  101. $interval( function() {
  102. if (grid.api.core.addToGridMenu){
  103. service.addToMenu( grid );
  104. }
  105. }, 100, 1);
  106. }
  107. }
  108. },
  109. defaultGridOptions: function (gridOptions) {
  110. //default option to true unless it was explicitly set to false
  111. /**
  112. * @ngdoc object
  113. * @name ui.grid.importer.api:GridOptions
  114. *
  115. * @description GridOptions for importer feature, these are available to be
  116. * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
  117. */
  118. /**
  119. * @ngdoc property
  120. * @propertyOf ui.grid.importer.api:GridOptions
  121. * @name enableImporter
  122. * @description Whether or not importer is enabled. Automatically set
  123. * to false if the user's browser does not support the required fileApi.
  124. * Otherwise defaults to true.
  125. *
  126. */
  127. if (gridOptions.enableImporter || gridOptions.enableImporter === undefined) {
  128. if ( !($window.hasOwnProperty('File') && $window.hasOwnProperty('FileReader') && $window.hasOwnProperty('FileList') && $window.hasOwnProperty('Blob')) ) {
  129. gridUtil.logError('The File APIs are not fully supported in this browser, grid importer cannot be used.');
  130. gridOptions.enableImporter = false;
  131. } else {
  132. gridOptions.enableImporter = true;
  133. }
  134. } else {
  135. gridOptions.enableImporter = false;
  136. }
  137. /**
  138. * @ngdoc method
  139. * @name importerProcessHeaders
  140. * @methodOf ui.grid.importer.api:GridOptions
  141. * @description A callback function that will process headers using custom
  142. * logic. Set this callback function if the headers that your user will provide in their
  143. * import file don't necessarily match the grid header or field names. This might commonly
  144. * occur where your application is internationalised, and therefore the field names
  145. * that the user recognises are in a different language than the field names that
  146. * ui-grid knows about.
  147. *
  148. * Defaults to the internal `processHeaders` method, which seeks to match using both
  149. * displayName and column.name. Any non-matching columns are discarded.
  150. *
  151. * Your callback routine should respond by processing the header array, and returning an array
  152. * of matching column names. A null value in any given position means "don't import this column"
  153. *
  154. * <pre>
  155. * gridOptions.importerProcessHeaders: function( headerArray ) {
  156. * var myHeaderColumns = [];
  157. * var thisCol;
  158. * headerArray.forEach( function( value, index ) {
  159. * thisCol = mySpecialLookupFunction( value );
  160. * myHeaderColumns.push( thisCol.name );
  161. * });
  162. *
  163. * return myHeaderCols;
  164. * })
  165. * </pre>
  166. * @param {Grid} grid the grid we're importing into
  167. * @param {array} headerArray an array of the text from the first row of the csv file,
  168. * which you need to match to column.names
  169. * @returns {array} array of matching column names, in the same order as the headerArray
  170. *
  171. */
  172. gridOptions.importerProcessHeaders = gridOptions.importerProcessHeaders || service.processHeaders;
  173. /**
  174. * @ngdoc method
  175. * @name importerHeaderFilter
  176. * @methodOf ui.grid.importer.api:GridOptions
  177. * @description A callback function that will filter (usually translate) a single
  178. * header. Used when you want to match the passed in column names to the column
  179. * displayName after the header filter.
  180. *
  181. * Your callback routine needs to return the filtered header value.
  182. * <pre>
  183. * gridOptions.importerHeaderFilter: function( displayName ) {
  184. * return $translate.instant( displayName );
  185. * })
  186. * </pre>
  187. *
  188. * or:
  189. * <pre>
  190. * gridOptions.importerHeaderFilter: $translate.instant
  191. * </pre>
  192. * @param {string} displayName the displayName that we'd like to translate
  193. * @returns {string} the translated name
  194. *
  195. */
  196. gridOptions.importerHeaderFilter = gridOptions.importerHeaderFilter || function( displayName ) { return displayName; };
  197. /**
  198. * @ngdoc method
  199. * @name importerErrorCallback
  200. * @methodOf ui.grid.importer.api:GridOptions
  201. * @description A callback function that provides custom error handling, rather
  202. * than the standard grid behaviour of an alert box and a console message. You
  203. * might use this to internationalise the console log messages, or to write to a
  204. * custom logging routine that returned errors to the server.
  205. *
  206. * <pre>
  207. * gridOptions.importerErrorCallback: function( grid, errorKey, consoleMessage, context ) {
  208. * myUserDisplayRoutine( errorKey );
  209. * myLoggingRoutine( consoleMessage, context );
  210. * })
  211. * </pre>
  212. * @param {Grid} grid the grid we're importing into, may be useful if you're positioning messages
  213. * in some way
  214. * @param {string} errorKey one of the i18n keys the importer can return - importer.noHeaders,
  215. * importer.noObjects, importer.invalidCsv, importer.invalidJson, importer.jsonNotArray
  216. * @param {string} consoleMessage the English console message that importer would have written
  217. * @param {object} context the context data that importer would have appended to that console message,
  218. * often the file content itself or the element that is in error
  219. *
  220. */
  221. if ( !gridOptions.importerErrorCallback || typeof(gridOptions.importerErrorCallback) !== 'function' ){
  222. delete gridOptions.importerErrorCallback;
  223. }
  224. /**
  225. * @ngdoc method
  226. * @name importerDataAddCallback
  227. * @methodOf ui.grid.importer.api:GridOptions
  228. * @description A mandatory callback function that adds data to the source data array. The grid
  229. * generally doesn't add rows to the source data array, it is tidier to handle this through a user
  230. * callback.
  231. *
  232. * <pre>
  233. * gridOptions.importerDataAddCallback: function( grid, newObjects ) {
  234. * $scope.myData = $scope.myData.concat( newObjects );
  235. * })
  236. * </pre>
  237. * @param {Grid} grid the grid we're importing into, may be useful in some way
  238. * @param {array} newObjects an array of new objects that you should add to your data
  239. *
  240. */
  241. if ( gridOptions.enableImporter === true && !gridOptions.importerDataAddCallback ) {
  242. gridUtil.logError("You have not set an importerDataAddCallback, importer is disabled");
  243. gridOptions.enableImporter = false;
  244. }
  245. /**
  246. * @ngdoc object
  247. * @name importerNewObject
  248. * @propertyOf ui.grid.importer.api:GridOptions
  249. * @description An object on which we call `new` to create each new row before inserting it into
  250. * the data array. Typically this would be a $resource entity, which means that if you're using
  251. * the rowEdit feature, you can directly call save on this entity when the save event is triggered.
  252. *
  253. * Defaults to a vanilla javascript object
  254. *
  255. * @example
  256. * <pre>
  257. * gridOptions.importerNewObject = MyRes;
  258. * </pre>
  259. *
  260. */
  261. /**
  262. * @ngdoc property
  263. * @propertyOf ui.grid.importer.api:GridOptions
  264. * @name importerShowMenu
  265. * @description Whether or not to show an item in the grid menu. Defaults to true.
  266. *
  267. */
  268. gridOptions.importerShowMenu = gridOptions.importerShowMenu !== false;
  269. /**
  270. * @ngdoc method
  271. * @methodOf ui.grid.importer.api:GridOptions
  272. * @name importerObjectCallback
  273. * @description A callback that massages the data for each object. For example,
  274. * you might have data stored as a code value, but display the decode. This callback
  275. * can be used to change the decoded value back into a code. Defaults to doing nothing.
  276. * @param {Grid} grid in case you need it
  277. * @param {object} newObject the new object as importer has created it, modify it
  278. * then return the modified version
  279. * @returns {object} the modified object
  280. * @example
  281. * <pre>
  282. * gridOptions.importerObjectCallback = function ( grid, newObject ) {
  283. * switch newObject.status {
  284. * case 'Active':
  285. * newObject.status = 1;
  286. * break;
  287. * case 'Inactive':
  288. * newObject.status = 2;
  289. * break;
  290. * }
  291. * return newObject;
  292. * };
  293. * </pre>
  294. */
  295. gridOptions.importerObjectCallback = gridOptions.importerObjectCallback || function( grid, newObject ) { return newObject; };
  296. },
  297. /**
  298. * @ngdoc function
  299. * @name addToMenu
  300. * @methodOf ui.grid.importer.service:uiGridImporterService
  301. * @description Adds import menu item to the grid menu,
  302. * allowing the user to request import of a file
  303. * @param {Grid} grid the grid into which data should be imported
  304. */
  305. addToMenu: function ( grid ) {
  306. grid.api.core.addToGridMenu( grid, [
  307. {
  308. title: i18nService.getSafeText('gridMenu.importerTitle'),
  309. order: 150
  310. },
  311. {
  312. templateUrl: 'ui-grid/importerMenuItemContainer',
  313. action: function ($event) {
  314. this.grid.api.importer.importAFile( grid );
  315. },
  316. order: 151
  317. }
  318. ]);
  319. },
  320. /**
  321. * @ngdoc function
  322. * @name importThisFile
  323. * @methodOf ui.grid.importer.service:uiGridImporterService
  324. * @description Imports the provided file into the grid using the file object
  325. * provided. Bypasses the grid menu
  326. * @param {Grid} grid the grid we're importing into
  327. * @param {File} fileObject the file we want to import, as returned from the File
  328. * javascript object
  329. */
  330. importThisFile: function ( grid, fileObject ) {
  331. if (!fileObject){
  332. gridUtil.logError( 'No file object provided to importThisFile, should be impossible, aborting');
  333. return;
  334. }
  335. var reader = new FileReader();
  336. switch ( fileObject.type ){
  337. case 'application/json':
  338. reader.onload = service.importJsonClosure( grid );
  339. break;
  340. default:
  341. reader.onload = service.importCsvClosure( grid );
  342. break;
  343. }
  344. reader.readAsText( fileObject );
  345. },
  346. /**
  347. * @ngdoc function
  348. * @name importJson
  349. * @methodOf ui.grid.importer.service:uiGridImporterService
  350. * @description Creates a function that imports a json file into the grid.
  351. * The json data is imported into new objects of type `gridOptions.importerNewObject`,
  352. * and if the rowEdit feature is enabled the rows are marked as dirty
  353. * @param {Grid} grid the grid we want to import into
  354. * @param {FileObject} importFile the file that we want to import, as
  355. * a FileObject
  356. */
  357. importJsonClosure: function( grid ) {
  358. return function( importFile ){
  359. var newObjects = [];
  360. var newObject;
  361. var importArray = service.parseJson( grid, importFile );
  362. if (importArray === null){
  363. return;
  364. }
  365. importArray.forEach( function( value, index ) {
  366. newObject = service.newObject( grid );
  367. angular.extend( newObject, value );
  368. newObject = grid.options.importerObjectCallback( grid, newObject );
  369. newObjects.push( newObject );
  370. });
  371. service.addObjects( grid, newObjects );
  372. };
  373. },
  374. /**
  375. * @ngdoc function
  376. * @name parseJson
  377. * @methodOf ui.grid.importer.service:uiGridImporterService
  378. * @description Parses a json file, returns the parsed data.
  379. * Displays an error if file doesn't parse
  380. * @param {Grid} grid the grid that we want to import into
  381. * @param {FileObject} importFile the file that we want to import, as
  382. * a FileObject
  383. * @returns {array} array of objects from the imported json
  384. */
  385. parseJson: function( grid, importFile ){
  386. var loadedObjects;
  387. try {
  388. loadedObjects = JSON.parse( importFile.target.result );
  389. } catch (e) {
  390. service.alertError( grid, 'importer.invalidJson', 'File could not be processed, is it valid json? Content was: ', importFile.target.result );
  391. return;
  392. }
  393. if ( !Array.isArray( loadedObjects ) ){
  394. service.alertError( grid, 'importer.jsonNotarray', 'Import failed, file is not an array, file was: ', importFile.target.result );
  395. return [];
  396. } else {
  397. return loadedObjects;
  398. }
  399. },
  400. /**
  401. * @ngdoc function
  402. * @name importCsvClosure
  403. * @methodOf ui.grid.importer.service:uiGridImporterService
  404. * @description Creates a function that imports a csv file into the grid
  405. * (allowing it to be used in the reader.onload event)
  406. * @param {Grid} grid the grid that we want to import into
  407. * @param {FileObject} importFile the file that we want to import, as
  408. * a file object
  409. */
  410. importCsvClosure: function( grid ) {
  411. return function( importFile ){
  412. var importArray = service.parseCsv( importFile );
  413. if ( !importArray || importArray.length < 1 ){
  414. service.alertError( grid, 'importer.invalidCsv', 'File could not be processed, is it valid csv? Content was: ', importFile.target.result );
  415. return;
  416. }
  417. var newObjects = service.createCsvObjects( grid, importArray );
  418. if ( !newObjects || newObjects.length === 0 ){
  419. service.alertError( grid, 'importer.noObjects', 'Objects were not able to be derived, content was: ', importFile.target.result );
  420. return;
  421. }
  422. service.addObjects( grid, newObjects );
  423. };
  424. },
  425. /**
  426. * @ngdoc function
  427. * @name parseCsv
  428. * @methodOf ui.grid.importer.service:uiGridImporterService
  429. * @description Parses a csv file into an array of arrays, with the first
  430. * array being the headers, and the remaining arrays being the data.
  431. * The logic for this comes from https://github.com/thetalecrafter/excel.js/blob/master/src/csv.js,
  432. * which is noted as being under the MIT license. The code is modified to pass the jscs yoda condition
  433. * checker
  434. * @param {FileObject} importFile the file that we want to import, as a
  435. * file object
  436. */
  437. parseCsv: function( importFile ) {
  438. var csv = importFile.target.result;
  439. // use the CSV-JS library to parse
  440. return CSV.parse(csv);
  441. },
  442. /**
  443. * @ngdoc function
  444. * @name createCsvObjects
  445. * @methodOf ui.grid.importer.service:uiGridImporterService
  446. * @description Converts an array of arrays (representing the csv file)
  447. * into a set of objects. Uses the provided `gridOptions.importerNewObject`
  448. * to create the objects, and maps the header row into the individual columns
  449. * using either `gridOptions.importerProcessHeaders`, or by using a native method
  450. * of matching to either the displayName, column name or column field of
  451. * the columns in the column defs. The resulting objects will have attributes
  452. * that are named based on the column.field or column.name, in that order.
  453. * @param {Grid} grid the grid that we want to import into
  454. * @param {Array} importArray the data that we want to import, as an array
  455. */
  456. createCsvObjects: function( grid, importArray ){
  457. // pull off header row and turn into headers
  458. var headerMapping = grid.options.importerProcessHeaders( grid, importArray.shift() );
  459. if ( !headerMapping || headerMapping.length === 0 ){
  460. service.alertError( grid, 'importer.noHeaders', 'Column names could not be derived, content was: ', importArray );
  461. return [];
  462. }
  463. var newObjects = [];
  464. var newObject;
  465. importArray.forEach( function( row, index ) {
  466. newObject = service.newObject( grid );
  467. if ( row !== null ){
  468. row.forEach( function( field, index ){
  469. if ( headerMapping[index] !== null ){
  470. newObject[ headerMapping[index] ] = field;
  471. }
  472. });
  473. }
  474. newObject = grid.options.importerObjectCallback( grid, newObject );
  475. newObjects.push( newObject );
  476. });
  477. return newObjects;
  478. },
  479. /**
  480. * @ngdoc function
  481. * @name processHeaders
  482. * @methodOf ui.grid.importer.service:uiGridImporterService
  483. * @description Determines the columns that the header row from
  484. * a csv (or other) file represents.
  485. * @param {Grid} grid the grid we're importing into
  486. * @param {array} headerRow the header row that we wish to match against
  487. * the column definitions
  488. * @returns {array} an array of the attribute names that should be used
  489. * for that column, based on matching the headers or creating the headers
  490. *
  491. */
  492. processHeaders: function( grid, headerRow ) {
  493. var headers = [];
  494. if ( !grid.options.columnDefs || grid.options.columnDefs.length === 0 ){
  495. // we are going to create new columnDefs for all these columns, so just remove
  496. // spaces from the names to create fields
  497. headerRow.forEach( function( value, index ) {
  498. headers.push( value.replace( /[^0-9a-zA-Z\-_]/g, '_' ) );
  499. });
  500. return headers;
  501. } else {
  502. var lookupHash = service.flattenColumnDefs( grid, grid.options.columnDefs );
  503. headerRow.forEach( function( value, index ) {
  504. if ( lookupHash[value] ) {
  505. headers.push( lookupHash[value] );
  506. } else if ( lookupHash[ value.toLowerCase() ] ) {
  507. headers.push( lookupHash[ value.toLowerCase() ] );
  508. } else {
  509. headers.push( null );
  510. }
  511. });
  512. return headers;
  513. }
  514. },
  515. /**
  516. * @name flattenColumnDefs
  517. * @methodOf ui.grid.importer.service:uiGridImporterService
  518. * @description Runs through the column defs and creates a hash of
  519. * the displayName, name and field, and of each of those values forced to lower case,
  520. * with each pointing to the field or name
  521. * (whichever is present). Used to lookup column headers and decide what
  522. * attribute name to give to the resulting field.
  523. * @param {Grid} grid the grid we're importing into
  524. * @param {array} columnDefs the columnDefs that we should flatten
  525. * @returns {hash} the flattened version of the column def information, allowing
  526. * us to look up a value by `flattenedHash[ headerValue ]`
  527. */
  528. flattenColumnDefs: function( grid, columnDefs ){
  529. var flattenedHash = {};
  530. columnDefs.forEach( function( columnDef, index) {
  531. if ( columnDef.name ){
  532. flattenedHash[ columnDef.name ] = columnDef.field || columnDef.name;
  533. flattenedHash[ columnDef.name.toLowerCase() ] = columnDef.field || columnDef.name;
  534. }
  535. if ( columnDef.field ){
  536. flattenedHash[ columnDef.field ] = columnDef.field || columnDef.name;
  537. flattenedHash[ columnDef.field.toLowerCase() ] = columnDef.field || columnDef.name;
  538. }
  539. if ( columnDef.displayName ){
  540. flattenedHash[ columnDef.displayName ] = columnDef.field || columnDef.name;
  541. flattenedHash[ columnDef.displayName.toLowerCase() ] = columnDef.field || columnDef.name;
  542. }
  543. if ( columnDef.displayName && grid.options.importerHeaderFilter ){
  544. flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName) ] = columnDef.field || columnDef.name;
  545. flattenedHash[ grid.options.importerHeaderFilter(columnDef.displayName).toLowerCase() ] = columnDef.field || columnDef.name;
  546. }
  547. });
  548. return flattenedHash;
  549. },
  550. /**
  551. * @ngdoc function
  552. * @name addObjects
  553. * @methodOf ui.grid.importer.service:uiGridImporterService
  554. * @description Inserts our new objects into the grid data, and
  555. * sets the rows to dirty if the rowEdit feature is being used
  556. *
  557. * Does this by registering a watch on dataChanges, which essentially
  558. * is waiting on the result of the grid data watch, and downstream processing.
  559. *
  560. * When the callback is called, it deregisters itself - we don't want to run
  561. * again next time data is added.
  562. *
  563. * If we never get called, we deregister on destroy.
  564. *
  565. * @param {Grid} grid the grid we're importing into
  566. * @param {array} newObjects the objects we want to insert into the grid data
  567. * @returns {object} the new object
  568. */
  569. addObjects: function( grid, newObjects, $scope ){
  570. if ( grid.api.rowEdit ){
  571. var dataChangeDereg = grid.registerDataChangeCallback( function() {
  572. grid.api.rowEdit.setRowsDirty( newObjects );
  573. dataChangeDereg();
  574. }, [uiGridConstants.dataChange.ROW] );
  575. grid.importer.$scope.$on( '$destroy', dataChangeDereg );
  576. }
  577. grid.importer.$scope.$apply( grid.options.importerDataAddCallback( grid, newObjects ) );
  578. },
  579. /**
  580. * @ngdoc function
  581. * @name newObject
  582. * @methodOf ui.grid.importer.service:uiGridImporterService
  583. * @description Makes a new object based on `gridOptions.importerNewObject`,
  584. * or based on an empty object if not present
  585. * @param {Grid} grid the grid we're importing into
  586. * @returns {object} the new object
  587. */
  588. newObject: function( grid ){
  589. if ( typeof(grid.options) !== "undefined" && typeof(grid.options.importerNewObject) !== "undefined" ){
  590. return new grid.options.importerNewObject();
  591. } else {
  592. return {};
  593. }
  594. },
  595. /**
  596. * @ngdoc function
  597. * @name alertError
  598. * @methodOf ui.grid.importer.service:uiGridImporterService
  599. * @description Provides an internationalised user alert for the failure,
  600. * and logs a console message including diagnostic content.
  601. * Optionally, if the the `gridOptions.importerErrorCallback` routine
  602. * is defined, then calls that instead, allowing user specified error routines
  603. * @param {Grid} grid the grid we're importing into
  604. * @param {array} headerRow the header row that we wish to match against
  605. * the column definitions
  606. */
  607. alertError: function( grid, alertI18nToken, consoleMessage, context ){
  608. if ( grid.options.importerErrorCallback ){
  609. grid.options.importerErrorCallback( grid, alertI18nToken, consoleMessage, context );
  610. } else {
  611. $window.alert(i18nService.getSafeText( alertI18nToken ));
  612. gridUtil.logError(consoleMessage + context );
  613. }
  614. }
  615. };
  616. return service;
  617. }
  618. ]);
  619. /**
  620. * @ngdoc directive
  621. * @name ui.grid.importer.directive:uiGridImporter
  622. * @element div
  623. * @restrict A
  624. *
  625. * @description Adds importer features to grid
  626. *
  627. */
  628. module.directive('uiGridImporter', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
  629. function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
  630. return {
  631. replace: true,
  632. priority: 0,
  633. require: '^uiGrid',
  634. scope: false,
  635. link: function ($scope, $elm, $attrs, uiGridCtrl) {
  636. uiGridImporterService.initializeGrid($scope, uiGridCtrl.grid);
  637. }
  638. };
  639. }
  640. ]);
  641. /**
  642. * @ngdoc directive
  643. * @name ui.grid.importer.directive:uiGridImporterMenuItem
  644. * @element div
  645. * @restrict A
  646. *
  647. * @description Handles the processing from the importer menu item - once a file is
  648. * selected
  649. *
  650. */
  651. module.directive('uiGridImporterMenuItem', ['uiGridImporterConstants', 'uiGridImporterService', 'gridUtil', '$compile',
  652. function (uiGridImporterConstants, uiGridImporterService, gridUtil, $compile) {
  653. return {
  654. replace: true,
  655. priority: 0,
  656. require: '?^uiGrid',
  657. scope: false,
  658. templateUrl: 'ui-grid/importerMenuItem',
  659. link: function ($scope, $elm, $attrs, uiGridCtrl) {
  660. var grid;
  661. function handleFileSelect(event) {
  662. var target = event.srcElement || event.target;
  663. if (target && target.files && target.files.length === 1) {
  664. var fileObject = target.files[0];
  665. // Define grid if the uiGrid controller is present
  666. if (typeof(uiGridCtrl) !== 'undefined' && uiGridCtrl) {
  667. grid = uiGridCtrl.grid;
  668. uiGridImporterService.importThisFile( grid, fileObject );
  669. target.form.reset();
  670. } else {
  671. gridUtil.logError('Could not import file because UI Grid was not found.');
  672. }
  673. }
  674. }
  675. var fileChooser = $elm[0].querySelectorAll('.ui-grid-importer-file-chooser');
  676. if ( fileChooser.length !== 1 ){
  677. gridUtil.logError('Found > 1 or < 1 file choosers within the menu item, error, cannot continue');
  678. } else {
  679. fileChooser[0].addEventListener('change', handleFileSelect, false);
  680. }
  681. }
  682. };
  683. }
  684. ]);
  685. })();