TableExport icon indicating copy to clipboard operation
TableExport copied to clipboard

Error: Failed to execute 'setItem' on 'Storage': Setting the value of 'te-ec8b88f-xlsx' exceeded the quota.

Open jorgeandresserrano opened this issue 6 years ago • 7 comments

I'm running an Angular 4 application and when I switch in and out (several times, like more than 10) into the component that uses the library, I get the following message and blocks the whole app execution.

Error: Failed to execute 'setItem' on 'Storage': Setting the value of 'te-ec8b88f-xlsx' exceeded the quota. at LocalStorage.setItem (tableexport.js:797) at TableExport.xlsx (tableexport.js:345) at tableexport.js:126

line 797: return this.store.setItem(key, value); link to code line 345: _store.getInstance().setItem(hashKey, dataObject, true); link to code line 126: context.setExportData(self.exporters[key].call(self, context)); link to code

jorgeandresserrano avatar Jul 12 '17 02:07 jorgeandresserrano

@jorgeandresserrano - This was an error in object storage and hashCode that should be fixed in v5.0.0-rc.10 where I switched from LocalStorage to SessionStorage and drastically reduced the size of the objects in storage. I also just fixed master so that it points to this latest version.

If the problem persists, try giving the <table> elements an id property. The hashKey that I am using is computed based on the table id attribute combined with the export type (e.g. xlsx) and falls back to the internal _uuid function to assure uniqueness which may be causing the problem for larger tables after multiple rerenders.

Lastly, if neither of those fix the issue then I may need to either create a utility to clear out unused export blobs from session storage or use an indexeddb.

clarketm avatar Jul 12 '17 03:07 clarketm

@clarketm hi. Having similar problem with my use case... I have table generated in my react component with dynamic ID that can change even with data change in the table. Would it be possible to allow something like data-export-id to be used in your hash creating instead of id (if this attribute is set, use it, or fallback to id and your default fallbacks...). I need dynamic ID on the table to bind some non-react JS code on the table. But in worst case, I can switch to using class name as my unique referrer instead of ID, but using ID seems more logical and is faster.

soukupl avatar Jul 14 '17 09:07 soukupl

@soukupl – check out the latest commit a2158d2. I am preparing this for v5.0.0-rc.11.

The reference key value will default to the value of the id property if defined, otherwise, it will be generated.

<table id="my-table" tableexport-key="my-table">
...
</table>

The attribute name can be customized via the following prototype property:

// Attribute applied to each table element
TableExport.prototype.tableKey = 'tableexport-key' // default

clarketm avatar Jul 16 '17 01:07 clarketm

@clarketm seems to work for me now :) I also did tweak my code to better support your plugin. :) Anyway, my integration is now working, so big thank you :)

soukupl avatar Jul 18 '17 08:07 soukupl

@soukupl – I am always open to suggestions for improvement if it aids in utility. If you don't mind me asking, what was your tweak?

clarketm avatar Aug 10 '17 03:08 clarketm

@clarketm I change my code to work in a different way...

  1. I render the table and export button, but not initialize your lib
  2. If user clicks my export button -> 2a. I will add "working" overlay to block the UI 2b. I will initialize your code to prepare the table 2c. I will manually start CSV or XLS export via your API 2d. I will remove my "working" overlay to unblock the UI 2e. I will unload your code.

I have few hooks that can be injected so I can modify table before I initialize your code (didn't use it, but I will have to for my specific table). This way, I can control what I'm displaying and what I'm exporting in single table.

The think is, that my code is changing the table almost all the time as all data in the table are async and may even react to push notifications in one case. So your code needs to refresh it's prepared data and it was slow for big tables... I can change the table like 2 times in one second in extreme case... So this init/deinit on demand is actually faster.

exportTable__do(exportMode) {
      console.log("[ElmTable] Export to: ", exportMode);

      var exportHelper = TableExport(document.getElementById(this.state.tableHtmlId), {
         formats: [exportMode],
         exportButtons: false,
         filename: "table-export"
      });

      var exportData = exportHelper.getExportData();
      console.log(exportData);

      var exportDataKey = Object.keys(exportData)[0];
      exportData = exportData[exportDataKey][exportMode];

      exportHelper.export2file(
         exportData.data,
         exportData.mimeType,
         exportData.filename,
         exportData.fileExtension
      );

      exportHelper.reset();
      exportHelper.remove();

      setTimeout(() => {
         this.setState({ isLoading: false });
      }, 250);
   }

This is just the main part of the export code, but there are some other things going on async to this. The whole table is rendered from the object stored in react's state and the export is in fact executed when specific change to the state happens.

*) and yes, console.log is stripped in production build :D

soukupl avatar Aug 10 '17 08:08 soukupl

sessionStorage.clear();

this.tableExport = new TableExport();

makenskiy avatar Oct 19 '18 06:10 makenskiy