We have a JQuery datatable with excel export, but cant solve a problem with numbers.
Numbers displays in the datatable in hungarian format: 5 588,9906 (whitespace is the thousand separator, comma is the decimal point).
Now we need to display the datas as numbers in excel, but thats not working every time. In excel settings, the thousand separator is whitespace, the decimal point is comma.
Datatable:
datatable format
Result in Excel (lower one is ok, upper one is a string):
excel error
The code:
var buttonCommon = {
exportOptions: {
format: {
body: function ( data, row, column, node ) {
return column === 6 || column === 8 || column === 9 || column === 10 || column === 11 || column === 12 || column === 13
? data.replace(',', '.').replace(' ', ',') : data;
}
}
}
};
var table = $('#talaltszamlak').DataTable({
dom: 'Blfrtip',
buttons: [
$.extend( true, {}, buttonCommon, {
extend: 'excelHtml5'
} ),
],
pageLength: 50,
"order": [[ 3, "asc" ]],
language: {
url: '//cdn.datatables.net/plug-ins/1.10.22/i18n/Hungarian.json'
},
});
Thank You!
Here is an example where you provide your own custom Excel number format.
In this case, the Excel format string is:
#,##0.0##
So, we will get up to 3 decimal places (and a minimum of 1 decimal place).
The test data:
<div style="margin: 20px;">
<table id="example" class="display dataTable cell-border" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr><td>Tiger Nixon</td><td>123,45</td></tr>
<tr><td>Garrett Winters</td><td>4 567,892</td></tr>
<tr><td>Ashton Cox</td><td>1 233 445,1</td></tr>
</tbody>
</table>
</div>
The DataTable with custom code:
$(document).ready(function() {
var table = $('#example').DataTable( {
dom: 'Brftip',
buttons: [
{
extend: 'excelHtml5',
text: 'Excel',
exportOptions: {
format: {
body: function ( data, row, column, node ) {
return reformatNumber(data, row, column, node);
}
}
},
customize: function( xlsx ) {
addCustomNumberFormat(xlsx, '#,##0.0##');
formatTargetColumn(xlsx, 'B'); // Excel column B
}
}
]
} );
} );
function reformatNumber(data, row, column, node) {
// replace spaces with nothing; replace commas with points.
if (column === 1 ) {
var newData = data.replace(',', '.').replaceAll(' ', '');
return newData;
} else {
return data;
}
}
function addCustomNumberFormat(xlsx, numberFormat) {
// this adds a new custom number format to the Excel "styles" document:
var numFmtsElement = xlsx.xl['styles.xml'].getElementsByTagName('numFmts')[0];
// assume 6 custom number formats already exist, and next available ID is 176:
var numFmtElement = '<numFmt numFmtId="176" formatCode="' + numberFormat + '"/>';
$( numFmtsElement ).append( numFmtElement );
$( numFmtsElement ).attr("count", "7"); // increment the count
// now add a new "cellXfs" cell formatter, which uses our new number format (numFmt 176):
var celXfsElement = xlsx.xl['styles.xml'].getElementsByTagName('cellXfs');
var cellStyle = '<xf numFmtId="176" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"'
+ ' applyFont="1" applyFill="1" applyBorder="1"/>';
// this will be the 8th "xf" element - and will therefore have an index of "7", when we use it later:
$( celXfsElement ).append( cellStyle );
$( celXfsElement ).attr("count", "69"); // increment the count
}
function formatTargetColumn(xlsx, col) {
var sheet = xlsx.xl.worksheets['sheet1.xml'];
// select all the cells whose addresses start with the letter prvoided
// in 'col', and add a style (s) attribute for style number 68:
$( 'row c[r^="' + col + '"]', sheet ).attr( 's', '68' );
}
The code adds a new number format record to the Excel styles XML sheet; it then uses that record to create a new cell format record. Finally, it locates every cell in column B of the Excel spreadsheet and applies the cell formatter.
The end result is that a value which is displayed in the DataTable like this:
1 233 445,1
Will be displayed in Excel like this:
1,233,445.1
You can use whatever Excel number format string you want, instead of #,##0.0##.
Related
I have a HTML table with QRcode as one of its column values; I use QRcode.min js library to convert the string to QRcode;
json = $.parseJSON(JSON.stringify(res.d));
// console.log('data ' , json);
$.each(json, function (i, item) {
// console.log(item.medicine);console.log(item.Medicine);
if (item.QrImg1 == null) {
td1 = $('<td>').text(' ');
} else {
td1 = $('<td>').qrcode({ width: 100, height: 100, text: item.QrImg1 })
}
if (item.QrImg2 == null) {
td2 = $('<td>').text(' ');
} else {
td2 = $('<td>').qrcode({ width: 100, height: 100, text: item.QrImg2 })
}
var $tr = $('<tr>').append(
$('<td style="width:30%">').text(item.Medicine),
$('<td>').text(item.BatchCode),
td1,
td2
).appendTo('#meds');
}
This is a pharmacy app, where in all the medicines along with their batch code(as QRCode) is displayed. They will have to do quick filter search on the medicine name so pagination wont help.
The issue is that I have around 6000+ row so while loading it takes time specially on a tablet. Is there some way I can get this loaded faster.
if you get the data one time from the server and you do search on client side from table then jquery.DataTables will help you filter rows https://datatables.net/
it has many options customize the view of table & functionality like sort / search / group
<html>
<head>
<link rel="stylesheet" type="text/css" href="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css">
</head>
<body>
<table id="example">
<thead>
<tr><th class="site_name">Name</th><th>Url </th><th>Type</th><th>Last modified</th></tr>
</thead>
<tbody>
</tbody>
</table>
<script type="text/javascript" charset="utf8" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.2.min.js"></script>
<script type="text/javascript" charset="utf8" src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script>
<script>
$("#example").dataTable({
"aaData":[
["Sitepoint","http://sitepoint.com","Blog","2013-10-15 10:30:00"],
["Flippa","http://flippa.com","Marketplace","null"],
["99designs","http://99designs.com","Marketplace","null"],
["Learnable","http://learnable.com","Online courses","null"],
["Rubysource","http://rubysource.com","Blog","2013-01-10 12:00:00"]
],
"aoColumnDefs":[{
"sTitle":"Site name"
, "aTargets": [ "site_name" ]
},{
"aTargets": [ 1 ]
, "bSortable": false
, "mRender": function ( url, type, full ) {
return '' + url + '';
}
},{
"aTargets":[ 3 ]
, "sType": "date"
, "mRender": function(date, type, full) {
return (full[2] == "Blog")
? new Date(date).toDateString()
: "N/A" ;
}
}]
});
</script>
</body>
</html>
I have a dynamically generated CSV file from another vendor that I am puling in and need to show in a table on my site. The problem is I need to be able to manipulate the data from the CSV so it can show the corrected values in the html table. In the end I need the HTML table to just display the Products, not the Mixed Sets.
I am using jquery and the papaparse library to get the data and parse it in a table in html. My codepen is here:
https://codepen.io/BIGREDBOOTS/pen/YQojww
The javascript pulls the initial csv values and display in a table, but I can't figure out how to to add together the values. If there is a better way of going about this, like converting the CSV to some other form of data like JSON, That is fine too.
My CSV looks like this:
product_title,product_sku,net_quantity
Product 1,PRD1,10
Product 2,PRD2,20
Product 3,PRD3,30
Mixed Set 1,MIX1,100
Mixed Set 2,MIX2,50
Mixed Set 3,MIX3,75
The Javascript I am using is:
function arrayToTable(tableData) {
var table = $('<table></table>');
$(tableData).each(function (i, rowData) {
var row = $('<tr class="rownum-' + [i] + '"></tr>');
$(rowData).each(function (j, cellData) {
row.append($('<td class="' + [i] + '">'+cellData+'</td>'));
});
table.append(row);
});
return table;
}
$.ajax({
type: "GET",
url: "https://cdn.shopify.com/s/files/1/0453/8489/t/26/assets/sample.csv",
success: function (data) {
$('body').append(arrayToTable(Papa.parse(data).data));
}
});
My rules for the mixed set:
Mixed Set 1 should add 100 to Product 1 and Product 2.
Mixed Set 2 should add 50 to Product 2 and Product 3.
Mixed Set 3 should add 75 to Product 1, Product 2 and Product 3.
I'd like to end up with Just the products output, and the correct numbers added to the formula.
The end result would be a table with Product 1 = 185, Product 2 = 245, and Product 3 = 155.
While it would be even better if the top THEAD elements were in a "th", It's fine if that is too complicated.
<table>
<tbody>
<tr class="rownum-0">
<td class="0">product_title</td>
<td class="0">product_sku</td>
<td class="0">net_quantity</td>
</tr>
<tr class="rownum-1">
<td class="1">Product 1</td>
<td class="1">PRD1</td>
<td class="1">185</td>
</tr>
<tr class="rownum-2">
<td class="2">Product 2</td>
<td class="2">PRD2</td>
<td class="2">245</td>
</tr>
<tr class="rownum-3">
<td class="3">Product 3</td>
<td class="3">PRD3</td>
<td class="3">155</td>
</tr>
</tbody>
</table>
Without knowing the size of the dataset you're working with, I suggest you first iterate through all the CSV dataset in order to populate a list of products with the correct values, and then iterate again on that to populate your HTML table:
function datasetToMap(data) {
var ret = {};
//Initialize a map with all the product rows
$(data).each(function(index, row) {
if(row[0].startsWith("Product")) {
ret[row[1]] = row; //Using the SKU as the key to the map
}
});
//Apply your mixed sets rules to the elements in the ret array
$(data).each(function(index, row) {
if(row[1] === "MIX1") {
ret["PRD1"][2] += 100;
ret["PRD2"][2] += 100;
}
//Do the same for Mixed sets 2 and 3
});
return ret;
}
function appendMapToTable(map) {
var $table = $('#my-table');
Object.keys(map).forEach(function(key, i) {
var rowData = map[key];
var row = $('<tr class="rownum-' + [i] + '"></tr>');
$(rowData).each(function (j, cellData) {
row.append($('<td class="' + [j] + '">'+cellData+'</td>'));
});
$table.append(row);
});
}
$.ajax({
type: "GET",
url: "https://cdn.shopify.com/s/files/1/0453/8489/t/26/assets/sample.csv",
success: function (data) {
appendMapToTable(datasetToMap(Papa.parse(data).data));
}
});
Note that this expects a table with id my-table to be already present in your HTML: you could manually parse the first row of your CSV data to add the table headings.
Also note that if your CSV dataset is very big this is definitely not an optimal solution, since it requires iterating through all its lines twice and then iterating again through all the list built with computed values.
I want to make excel like cell system but dynamically, Where i have to select every cell individually.
My desired output:
If i have 2 and 10, the output will be like that(above image). 2 means 2 row and 10 means 10 columns. the 2 and 10 is from database then javascript/angularjs should make the table according to those values. The second thing is that i have to select every individual cell using javascript. For example, i want to select B7 and if i click on that cell, an alert box will be shown with the selected cell number.
In real i want to store some values regarding that cell. How can i make every cell clickable? Any suggestion? I prefer angularjs.
Edit:
Acually i want to make Yard graphical view. Staff will select cell and input goods weight(in bootstrap modal). Then save. Next time if a cell/slot has weight before, it will be in different color(red-means the cell/slot is already filled with goods) and if he click on that cell , all details will be shown regarding to that cell like weight. Database table will store yard_id,cell_id,weiight. How can make query to get details from database to have my cell filled with color and show details if the cell has details before?
Edit 2:
You make an object in factory to set value in cell :
database[createKey({
row: 'A',
column: 1
})] = 12;
Here row A and column 1 is red colored by default. But in real app, i will have data for some cells like:
[{"row":"A","column":1,"weight":100},
{"row":"A","column":2,"weight":200}
].
Then how can i set those value on specific cells and have different bg color?
I want to use this method( loadData() ) to set color(like the one you set-red color) in the cell those have value stored in database when page load for the first time :
function loadData() {
fakeHttp.get('api/weights').then(function (result) {
$scope.weights = result.data;
console.log(result.data)
});
};
I will pass json data in result.data parameter(given above).
...in real app, i will have data for some cells like:... how can i set those value on specific cells and have different bg color?
You can keep loadData the same and change $scope.getWeight to accommodate the format of the data. This takes a dependency on lodash's find, since that makes things more concise. If you don't want to do that you can replace _.find with your own find method that does the same thing - I'll leave that as an exercise for you :)
http://plnkr.co/edit/b0q4qTyNjQp7J2IB7ayf?p=preview
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.0.1/lodash.js"></script>
JavaScript
$scope.getWeight = function (row, column) {
if ($scope.weights) {
// See if there's a record with the row and column.
var record = _.find($scope.weights, {
row: row,
column: column
});
// Was a record found with the row and column?
if (record) {
// If so return its weight.
return record.weight;
}
}
};
Staff will select cell and input goods weight(in bootstrap modal). Then save. Next time if a cell/slot has weight before, it will be in different color(red-means the cell/slot is already filled with goods) and if he click on that cell , all details will be shown regarding to that cell like weight...How can make query to get details from database to have my cell filled with color and show details if the cell has details before?
I didn't completely understand, but here's roughly what you could do for the parts I did understand. This assumes you have 3 endpoints - GET api/weights to get the weights; GET api/weight to get the weight for a single cell and POST api/weight to update a weight. You'll need to replace fakeHttp with $http and the actual url's. I don't know what Yard or Yard_id is.
http://plnkr.co/edit/aAiYbChTqmAwgky0WOJ3?p=preview
// TODO: Replace fakeHttp with $http
var module = angular.module('myApp', ['ui.bootstrap']);
module.controller('MainCtrl', function ($scope, $uibModal, fakeHttp) {
$scope.rows = [
'A',
'B'
];
$scope.columns = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
];
$scope.select = function (row, column) {
var modalInstance = $uibModal.open({
templateUrl: 'myModal.html',
controller: 'ModalInstanceCtrl',
resolve: {
row: function () {
return row;
},
column: function () {
return column;
}
}
});
modalInstance.result.then(loadData);
};
$scope.getWeight = function (row, column) {
if ($scope.weights) {
var key = createKey({
row: row,
column: column
});
return $scope.weights[key];
}
};
loadData();
function loadData() {
fakeHttp.get('api/weights').then(function (result) {
$scope.weights = result.data;
});
};
function createKey(data) {
var key = {
row: data.row,
column: data.column
};
return JSON.stringify(key);
}
});
module.controller('ModalInstanceCtrl', function ($scope, row, column, fakeHttp, $uibModalInstance) {
$scope.row = row;
$scope.column = column;
fakeHttp.get('api/weight', {
row: row,
column: column
}).then(function (result) {
$scope.weight = result.data;
});
$scope.save = function () {
fakeHttp.post('api/weight', {
row: row,
column: column,
weight: $scope.weight
}).then(function () {
$uibModalInstance.close();
});
};
});
module.factory('fakeHttp', function ($q) {
var fakeHttp = {};
var database = {};
database[createKey({
row: 'A',
column: 1
})] = 12;
fakeHttp.get = function (url, data) {
if (url === 'api/weight') {
var key = createKey(data);
return $q.when({ data:
database[key]
});
} else if (url === 'api/weights') {
return $q.when({ data:
database
});
} else {
alert('invalid url: ' + url);
}
};
fakeHttp.post = function (url, data) {
if (url === 'api/weight') {
var key = createKey(data);
database[key] = data.weight;
return $q.when({});
} else {
alert('invalid url: ' + url);
}
};
return fakeHttp;
function createKey(data) {
var key = {
row: data.row,
column: data.column
};
return JSON.stringify(key);
}
});
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<link data-require="bootstrap#3.3.7" data-semver="3.3.7" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<script data-require="angular.js#1.6.2" data-semver="1.6.2" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.js"></script>
<script data-require="angular.js#1.6.2" data-semver="1.6.2" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular-route.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.3.3/ui-bootstrap-tpls.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="MainCtrl">
<table border="1" cellspacing="0">
<tbody>
<tr ng-repeat="row in rows">
<td ng-repeat="column in columns" style="width: 100px; cursor: pointer"
ng-style="{ background: getWeight(row, column) ? 'red' : '' }"
ng-click="select(row, column)">
{{row}}{{column}}
</td>
</tr>
</tbody>
</table>
</body>
</html>
myModal.html
<div class="modal-body">
Please enter weight for {{ row }}{{ column }}
<input type="text" class="form-control"
ng-model="weight" />
<button class="btn btn-primary"
ng-click="save()">Save</button>
</div>
How can i make every cell clickable?
Here's how to make every cell clickable in AngularJS.
http://plnkr.co/edit/XKa5WwjyYTugDZ744iWB?p=preview
Your question was very unclear. I couldn't tell what you wanted, exactly.
JavaScript:
module.controller('MainCtrl', function($scope) {
$scope.rows = [
'A',
'B'
];
$scope.columns = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
];
$scope.select = function(row, column) {
if ($scope.selectedRow === row && $scope.selectedColumn === column) {
$scope.selectedRow = undefined;
$scope.selectedColumn = undefined;
} else {
$scope.selectedRow = row;
$scope.selectedColumn = column;
}
};
});
HTML:
<body ng-controller="MainCtrl">
<table border="1" cellspacing="0">
<tbody>
<tr ng-repeat="row in rows">
<td ng-repeat="column in columns" style="width: 100px; cursor: pointer"
ng-click="select(row, column)"
ng-style="{ background: row == selectedRow && column == selectedColumn ? 'yellow' : 'none' }">
{{row}}{{column}}
</td>
</tr>
</tbody>
</table>
<br>
Selected (row, column):
<br>
({{selectedRow || 'undefined'}}, {{selectedColumn || 'undefined'}})
</body>
I'm trying to search in the columns 'Part Number' and 'Internal Reference' with one searchbar and with another searchbar in the column named 'Description':
By the moment I'm trying with this in the html:
...
<th class="code">Part Number</th>
<th class="keyword">Description</th>
<th class="code">Internal Reference</th>
...
And this in the .js:
$('#keyword-search').keyup(function() {
var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
oTable.columns('.keyword').search('^' + val, true, false).draw();
});
$('#code-search').keyup(function() {
var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
oTable.columns('.code').search('^' + val, true, false).draw();
});
I want to be able to search in the 'Part Number' or in the 'Reference' column but not in both at the same time, just to show the columns where the expression exists in the first or in the second column.
I need this to be solved, I tried different ways and I don't find the solution.
EDIT 1: I want a final result like this:
But that search is not working, there is no final filtered result, there is a collision between the two columns because it's searching 'NUM1' in the column 'Part Number' and in the column 'Internal Reference' at the same time. I mean that the code it's doing an AND search instead of an OR search, that is what I want.
Something along the lines of this should work:
$('#keyword-search').keyup(function() {
var searchText = $(this).val().toLowerCase();
$.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {
//Assuming part number and internal reference are 1st and 3rd columns
if((~data[0].toLowerCase().indexOf(searchText)) || (~data[2].toLowerCase().indexOf(searchText))) {
return true;
}
return false;
}
Check this and this
I am performing some ASP.NET gridview conversions using the datatables.net plug-in. The answer to why I am doing this is more involved and can be debated. However, I need some help with one of the issues I am running into.
Using Javascript to convert the gridview on the page was actually quite simple and works well. The major issue is that I want to have a fixed 'total' row (footer) within the body of the datatable so that it remains responsive just like the rest of the table.
I have attempted to add a footer using the code-behind, and I can populate that footer with total data, but it is not responsive with the rest of the table. I am assuming because the <tfoot> is outside of the <tbody>.
Using javascript, I have successfully added a new datatable row and I can output the data to the console, but I am unable to populate the added row with the object data.
Javascript:
var sum;
$(document).ready(function () {
var table = $('#cphPage_gvTaxColl').DataTable();
//convert string to int
var intVal = function (i) {
var j = $("<span/>");
var txt = j.html(i).text();
// alert('txt :' + txt);
var myVal = typeof txt === 'string' ?
parseFloat(txt.replace(/[^\d.-]/g, '')) :
typeof txt === 'number' ?
i : 0;
return myVal || 0;
};
//format integer as currency
var formatSum = function (myVal) {
return accounting.formatMoney(myVal, {
symbol: "$",
precision: 2,
thousand: ",",
decimal: ".",
format: {
pos: "%s %v",
neg: "%s (%v)",
zero: "%s 0.00"
}
});
};
//add total row and determine index
table.row.add(['GRAND TOTAL']).draw();
var total_row = (table.row().count() + 1);
var total_col = (table.row(total_row).column().count + 1);
//alert
console.log('total row: ' + total_row);
//loop columns
table.columns('.sum').every(function () {
sum = this
.data()
.reduce(function (a, b) {
console.log('adding ' + intVal(a) + ' and ' + intVal(b));
return intVal(a) + intVal(b);
});
//alert
console.log('sum: ' + sum);
console.log('column row 2 val: ' + this.data().row([2]));
$(this.cell.node( total_row )).html(
formatSum(sum)
);
});
});
How do I present the object data within the datarow?
I am also receiving the following error message, and I am not certain which parameter is missing ( the 2nd and 3rd columns are null ):
Error message
I have included a screenshot with the console data, and if you need it I can provide the .aspx markup:
Page + cosole log output
I'm still learning the ins-and-outs of this stuff. Any guidance you can provide is greatly appreciated.
Thanks in advance!
Here is my solution:
The html-table for datatables should have <tfoot>
Something like this:
<table id='table'>
<tbody>
<tr><td></td></tr>
</tbody>
<tfoot>
<tr><td></td></tr>
</tfoot>
</table>
Define footerCallback field
Datatables initialization:
$('#table').dataTable({
...
"footerCallback": _footerDrawn
...
});
footerCallback:
I use server-side data, so my source of data for footer is just another field of of ajax-response:
_footerDrawn: function( row, data, start, end, display ) {
var table = $('#table').dataTables();
var json = table.api().ajax.json();
// assign values to each cell of the footer from json.total array
$.each( table.api().columns().indexes(), function( index ) {
$( table.api().column( index ).footer() ).html( json.total[index] );
});
}
}
json.total contains array of string to print in footer row