Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,25 @@ bower install ng-table-export

## Example

* [ngTable export to CSV](http://bazalt-cms.com/ng-table/example/15)
* [ngTable export to CSV](http://bazalt-cms.com/ng-table/example/15)

### This version fixes ng-table-export for Internet Explorer 9++ (maybe even 8)
### Additional Features (compared to original ng-table-export)

* **Add possibility to specify encoding of the generated csv file.**
For example:
```html
<a class="btn btn-primary" ng-mousedown="csv.generate($event)" ng-href="{{ csv.link() }}" download="test.csv">Export to CSV</a>
<table ng-href ... export-csv="csv" ng-export-encoding="latin1">
```
Alternatively (it's just a matter of taste):
```html
<a class="btn btn-primary" ng-mousedown="csv.generate($event, 'latin1')" ng-href="{{ csv.link() }}" download="test.csv">Export to CSV</a>
<table ng-href ... export-csv="csv">
```
If you omit `ng-export-encoding`, you will get the default (`UTF-8`). Right now, only UTF-8 and latin1 (i.e. ISO-8859-1 is supported).

* In case you provide a short view in a table cell (e.g. using manual truncation of a string when it is too long) but still want
the original contents to be exported, then you can do so by setting the attribute **data-fulltext** on the `<td>` or `<th>` element.
If this attribute is present, its content is exported instead of the text() contents.

2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ng-table-export",
"version": "0.1.0",
"version": "0.2.0",
"main": [
"ng-table-export.js"
],
Expand Down
3 changes: 2 additions & 1 deletion ng-table-export.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ng-table-export.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

151 changes: 137 additions & 14 deletions ng-table-export.src.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,171 @@
angular.module('ngTableExport', [])

.config(['$compileProvider', function($compileProvider) {
// allow data links
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|data):/);
}])

.directive('exportCsv', ['$parse', function ($parse) {
return {
restrict: 'A',
scope: false,
link: function(scope, element, attrs) {
var data = '';

/********************************************************************************************
* Public stuff:
*
* csv will be exposed within the PARENT scope.
* This will make it available to siblings of the <table> tag.
*/
var csv = {
stringify: function(str) {
return '"' +
str.replace(/^\s\s*/, '').replace(/\s*\s$/, '') // trim spaces
.replace(/"/g,'""') + // replace quotes with double quotes
stringify: function (str) {
return '"' + str.replace(/^\s\s*/, '').replace(/\s*\s$/, '') // trim spaces
.replace(/"/g, '""') + // replace quotes with double quotes
'"';
},
generate: function() {
extractData: function () {
data = '';
var rows = element.find('tr');
angular.forEach(rows, function(row, i) {
var tr = angular.element(row),
tds = tr.find('th'),
rowData = '';
angular.forEach(rows, function (row, i) {
var tr = angular.element(row), tds = tr.find('th'), rowData = '';
if (tr.hasClass('ng-table-filters')) {
return;
}
if (tds.length == 0) {
tds = tr.find('td');
}
if (i != 1) {
angular.forEach(tds, function(td, i) {
rowData += csv.stringify(angular.element(td).text()) + ';';
angular.forEach(tds, function (td, i) {
if (td.hasAttribute('data-fulltext')) {
rowData += csv.stringify(td.getAttribute('data-fulltext')) + ';';
} else {
rowData += csv.stringify(angular.element(td).text()) + ';';
}
});
rowData = rowData.slice(0, rowData.length - 1); //remove last semicolon
}
data += rowData + "\n";
});
},
link: function() {
return 'data:text/csv;charset=UTF-8,' + encodeURIComponent(data);
/**
* @param $event Handing over the $event is necessary to properly cancel event propagation in IE
* @param encoding If you supply this parameter, it will override the csv-export-encoding attribute
* you could alternatively have supplied together with csv-export on the table element.
* This alternative helps you in reducing code-changes in case you have the download-button
* put into a template which you re-use everywhere where you're using ng-table
*/
generate: function ($event, encoding) {
encodingOverwrite = encoding;

/** all browsers need to have the data prepared ...*/
csv.extractData();

/* ... but only IE will start the download here, that's why we pass $event so the normal behaviour
of following the href can be preventDefaulted. All other browsers will have the download triggered
through this normal behaviour of visiting the href ... that's where the link() function takes over */
csv.generateIE($event);
},
generateIE: function ($event) {
if (window.navigator.msSaveOrOpenBlob) {
var encoding = _getRequestedEncoding(),
blobObject,
filename;

/**
* The following logic depends on the "data" string to be UTF-8. This should usually be the case.
*/
if (encoding === 'UTF-8') {
blobObject = _getUtf8Blob();

} else if (encoding === 'ISO-8859-1') {
blobObject = _transformUtf8ToLatin1AndGetBlob();

} else {
_logErrorEncodingNotSupported();
}

/** we need $event also to collect the filename from the "download" attribute */
if ($event && $event.preventDefault) {

filename = $event.target.attributes['download'].value;
window.navigator.msSaveOrOpenBlob(blobObject, filename);
$event.preventDefault(); // href must not be followed

} else {
console.warn('ng table export: you should pass over the $event in your expression for proper IE support, ' +
'e.g. via ng-click="csv.generate($event)" --- otherwise the href will be followed');
}
}
},
link: function () {
var encoding = _getRequestedEncoding();
if (encoding === 'UTF-8') {
return 'data:text/csv;charset=UTF-8,' + encodeURIComponent(data);

} else if (encoding === 'ISO-8859-1') {
return 'data:text/csv;charset=ISO-8859-1,' + escape(data);

} else {
_logErrorEncodingNotSupported();
}
}
};
$parse(attrs.exportCsv).assign(scope.$parent, csv);


/********************************************************************************************
* Private stuff here
*/
var data = '',
encodingOverwrite = '';

function _logErrorEncodingNotSupported() {
console.error("ng table export: invalid encoding requested. only 'UTF-8' and 'ISO-8859-1' are supported");
}

/**
* Returns the requested encoding.
*
* To change the encoding from the default value (UTF-8) to latin1,
* do it like so: <table ... ng-table ... export-csv="..." export-csv-encoding="latin1">
*
* Actually at the moment, it does not matter what you insert into export-csv-encoding. It will always be
* interpreted as latin1 (i.e. ISO-8859-1) as long as the value does not match to "utf".
*/
function _getRequestedEncoding() {
var enc = encodingOverwrite ? encodingOverwrite : attrs.exportCsvEncoding;
if (!enc) {
return 'UTF-8';
} else {
if (enc.match(/utf/)) {
return 'UTF-8';
} else {
return 'ISO-8859-1';
}
}
}

function _transformUtf8ToLatin1AndGetBlob() {
var utf8Text = data,
buffer = new ArrayBuffer(utf8Text.length),
uint8Array = new Uint8Array(buffer);

for (var i = 0; i < uint8Array.length; i++) {
var charCode = utf8Text[i].charCodeAt(0);
if (charCode > 256) { // latin1 goes only from charCode 1 to 256
// that's why we set it to a predefined latin1 char which is easily recognizable as "this char has no representation in latin1"
// we "use" the paragraph sign at position %B6 (or 182 in decimal notation): ¶
charCode = 182; // ¶
}
uint8Array[i] = charCode; // will be transformed to correct latin1 binary representation
}
var blobObject = new Blob([uint8Array]);
return blobObject;
}

function _getUtf8Blob() {
return new Blob([data]);
}
}
};
}]);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ng-table-export",
"version": "0.1.0",
"version": "0.2.0",
"author": "Vitalii Savchuk <esvit666@gmail.com>",
"license": "BSD",
"repository": {
Expand Down
Loading