I'm currently using Tabulator.js to get a table generated for my project.
In my project I receive information from firebase and I load it to my table which is designed by TABULATOR.js ( http://tabulator.info ).
I know how to calculat normal value in my table. But I would like to calculate time. For example in row 1 I get 00:45 (45min) and row 2 I get 1:10 the result row should give me 1:55.
I not really familiar with web codding that's why I request your help.
My code :
var table = new Tabulator("#editor", {
downloadConfig:{
columnGroups:false,
rowGroups:false,
},
height:360,
data: arrayFlight,
pagination:"local",
resizableColumns: false,
paginationSize:12,
columnVertAlign:"center",
columnHoriAlign:"center",
columns:[ //I show you only the requested column
{
title:"SINGLE PILOT FLIGHT TIME",
columns:[
{title:"SE", field:"seTime", align:"center", formatter:"datetime", formatterParams:{inputFormat:"hh:mm:ss", outputFormat:"hh:mm:ss", invalidPlaceholder:"-"}, sorter:false, headerSort:false, width:95, bottomCalc:"sum", bottomCalcParams:{precision:2}},
{title:"ME", field:"meTime", align:"center", formatter:"datetime", formatterParams:{inputFormat:"hh:mm:ss", outputFormat:"hh:mm:ss", invalidPlaceholder:"-"}, sorter:false, headerSort:false, width:95},
],
},
],
thanks for your help.
You would need to use a custom column calculation for this, something like this:
//define custom calculation function
var timeSum = function(values, data, calcParams){
//values - array of column values
//data - all table data
//calcParams - params passed from the column definition object
var time = 0;
values.forEach(function(value){
if(value){
//split time value into minutes and sum
var values = value.split(":");
time += parseInt(values[0]) * 60;
time += parseInt(values[1]);
}
});
//format sum as hour:minute
return Math.floor(time/60) + ":" + time%60;
};
Then you can assign it in your column definition:
{title:"SE", field:"seTime", bottomCalc:timeSum}
Related
http://live.datatables.net/dalogaci/1/edit
I have an amount of money to be dispersed and am using DataTables to display a list of people and allow entry of an amount next to each person (their share of the disbursement). I want to provide a running total of the amount entered into the table so I can warn when the total to be dispersed has been reached or passed.
Kind regards,
Glyn
You can use the following approach.
In my case, I display the running total in a <div>, rather than an input box, as the value is only for display purposes:
<div id="showsum">Grand Total: $0.00</div>
The end result:
The script for this - which I have tried to explain with comments in the code:
<script type="text/javascript">
// define the table variable here so the doSum()
// function will have access to it, when needed:
var table;
// reads each value from the final column in the table, checks
// if the value is a number (as opposed to blank), and then
// keeps a running total. Ensure we round fractions of pennies
// as needed.
//
// When handling money, use a big number library - see this:
// https://stackoverflow.com/questions/1458633/how-to-deal-with-floating-point-number-precision-in-javascript
//
function doSum() {
//var foop = table.columns(5).nodes().to$();
var sum = 0.0;
// this gets each node (cell) in the final column:
table.columns(5).nodes().to$()[0].forEach(function (item) {
// see if the display value is a number (i.e. not blank):
var amt = parseFloat($('input', item ).val());
if (!isNaN(amt)) {
sum += amt;
}
});
// round and display to 2 decimal places:
sum = (Math.round((sum + Number.EPSILON) * 100) / 100).toFixed(2);
$('#showsum').text("Grand Total: $" + sum);
}
$(document).ready(function() {
table = $('#example').DataTable( {
"columnDefs": [ {
"targets": 5,
"data": function ( row, type, val, meta ) {
// note the use of onchange="doSum()" in the following:
return '<input type="number" min="0" max="99999.99" step=".01" placeholder="0.00" onchange="doSum()">';
}
} ]
} );
} );
</script>
For a change to be added to the grand total, you have to hit "enter", or click outside of the input field, if you type the value in manually.
Because you are dealing with money, the code should really be using a "big number" format to eliminate the risk of inaccuracies in fractions of pennies (due to limitations in floating point arithmetic). For example see here.
Final note: I see this question was down-voted. I think that may have been because you only link to your demo code, instead of showing the relevant parts in the question itself. The link to the demo is useful - but showing code in the question itself is generally a "must-do", I think.
Good day,
I am trying to get data into a table, with the tour_id and every single media_id (the station_id i am getting from somewhere else), the ordernumber is what is giving me a headache:
I am trying to get every station one number for every media i am posting.
For example:
station 1 has 2 medias
and station 2 has 3
then the odernumbers should be like this: 0, 0, 1, 1, 1
I am using the following Code at this moment:
for(var i = 0; i < this.currentStations.length; i++){
this.http.get("http://localhost:3000/mediasforstation/" + this.currentStations[i].id).subscribe((res) => {
medias = res;
for (var j = 0; j < medias.length; j++){
this.http.post("http://localhost:3000/posttourstations",
{"tour_id": id, "media_id": medias[j].id, "ordernumber": i}).subscribe(function(res) {
console.log(res);
}.bind(this));
}
});
}
Everything but the ordernumber works, however, the ordernumber always takes the number of stations involved, in our example above it would be 2.
How do I fix this?
Thank you very much for your help.
As I understand, you need to keep the index value. The type of variable i is var which is function scoped. Within outer loop, you are calling an API that returns some response, meanwhile the value of i is updated and for next index/counter, the API call has been sent. When you get response from API calls, you get the value of i where the outer loop has been called of.
In other words, you need to understand the difference between var and let. Your problem can be solved by replacing
for(var i=0;...)
with
for(let i=0;...)
Here's providing you the sample code.
//block scoped - retains value of i
for (let i=0;i<10;i++){
this.http.get('https://jsonplaceholder.typicode.com/users').subscribe(res=>{
for(var j=0;j<5;j++){
console.log(`i=>${i}`)
}
})
}
//function scoped - gets updated value of i
for (var i=0;i<10;i++){
http.get('https://jsonplaceholder.typicode.com/users').subscribe(res=>{
for(var j=0;j<5;j++){
console.log(`i=>${i}`)
}
})
}
I have a CSV file with following format:
<pre id="csv" style="display:none">
DATES,WHOLESALE,ECOMMERCE,RETAIL,LOANS,BONDISSUER
01/10/2018 00:00,25,16,13,1,0
01/10/2018 01:00,24,5,9,3,2
01/10/2018 02:00,28,6,17,0,6
The data range is 01/10/2018 00:00 - 31/10/2018 00:00
Interval is every hour.
I am using highstock stacked column with 5 categories: WHOLESALE,ECOMMERCE,RETAIL,LOANS,BONDISSUER.
My problem is, that the highstock navigator displays the data incorrectly. I think I have to customise property in range selector or navigator, but I can't find any documentation online. I tried inputDateParser, but it didn't work. Here is the jsfiddle
inputDateParser: function (value) {
value = value.split(/[:\.]/);
return Date.UTC(
1970,
0,
1,
parseInt(value[0], 10),
parseInt(value[1], 10),
parseInt(value[2], 10),
parseInt(value[3], 10)
);
}
How do I get the data range to be correct: month of October 2018 according to the dates in CSV?
I should not see a whole year in the navigator, when I only have data for October.
Thanks much appreciated
You would need to format the dates correctly, it can be done using the beforeParse callback function, like this:
data: {
csv: document.getElementById('csv').innerHTML,
beforeParse: function(e) {
let csv = e.split('\n'); //split by newline
let processedTable = []
processedTable.push(csv[0].split(','))
for (let i = 1; i < csv.length; i++) {
let row = csv[i].split(',');
if (row.length != 6) //skip empty rows or rows with more/less columns
continue;
let date = row[0].split(' ')[0].split('/')
let time = row[0].split(' ')[1].split(':')
processedTable.push(
[(new Date(date[2], date[1] - 1, date[0], time[0], time[1], 0)).getTime(), //get the timestamp for the date
parseInt(row[1]),
parseInt(row[2]),
parseInt(row[3]),
parseInt(row[4]),
parseInt(row[5])
].join(',')
)
}
return processedTable.join('\n') //join the array into a string again
},
},
Every row is parsed, by splitting it apart, the date is found, and milliseconds since 1970 is returned by getTime(). Then we join the cells into strings, and lastly the rows into a long string. The reason we convert this back into a string, is because highcharts is going to read it in from a string.
Working JSFiddle example: https://jsfiddle.net/ewolden/spmtgv3a/
API on beforeParse: https://api.highcharts.com/highcharts/data.beforeParse
I'm looking for way to generate data by JSON schema faker js with IDs incremented from 0.
When I'm trying to use autoIncrement parameter in schema, I get valid values, but this auto increment is started from random number.
Is that possible to do that with this package?
I didn't find an official solution to the problem, but here is a workaround.
json-schema-faker's source code for generating auto-incremented integers (node_modules\json-schema-faker\lib\index.js) explains why it starts from a random integer:
// safe auto-increment values
container.define('autoIncrement', function (value, schema) {
if (!this.offset) {
var min = schema.minimum || 1;
var max = min + env.MAX_NUMBER;
this.offset = random$1.number(min, max);
}
if (value === true) {
return this.offset++;
}
return schema;
});
It is the if (!this.offset) branch that sets up the initial value. To achieve our goal, we can modify the code inside the branch like this:
if (!this.offset) {
var min = schema.minimum || 1;
// var max = min + env.MAX_NUMBER;
// this.offset = random$1.number(min, max);
this.offset = min;
}
When minimum is specified in the schema, its value will be used as the starting point. Otherwise, 1 is used instead.
It is also noteworthy that, if you specify minimum with an extremely large number, the auto-incrementation will no longer be "safe".
For anyone searching for a more current answer, you can now set an 'initialOffset' value within the schema which acts as a start value
import fl.events.*;
const PointsStart:int=0;
var Points:int=PointsStart;
youChose.text=String(Points)+" points";
comboBox.prompt='Contestants'
comboBox.addItem({label:"John Smith",Points:10});
comboBox.addItem({label:"Chris Tucker",Points:12});
comboBox.addItem({label:"Paul Allen",Points:14});
comboBox.addEventListener(Event.CHANGE, listevalg);
function listevalg (evt:Event)
{
Points=comboBox.selectedItem.Points;
youChose.text=String(Value)+" points";
}
I'd like to have a textbox that says what the current standings are. Say I choose Chris Tucker in the combo box, I want the textbox to say something like 'He's in second place'
First you need to know which rank each person is in. To do that you can copy the list of people and sort it by Points, then register their rank as their position in that list.
import fl.events.*;
const PointsStart:int=0;
var Points:int=PointsStart;
youChose.text=String(Points)+" points";
comboBox.prompt='Contestants'
var people:Array = [{label:"John Smith",Points:10},
{label:"Chris Tucker",Points:12},
{label:"Paul Allen",Points:14}];
// Copy of "people", sorted by Points, descending.
var sortedPeople:Array = people.concat().sortOn("Points", Array.DESCENDING | Array.NUMERIC);
for each (var person:Object in people) {
// Register this person's ranking as its position in the sorted array + 1
// (because indexes start at 0)
person.Rank = sortedPeople.indexOf(person) + 1;
comboBox.addItem(person);
}
comboBox.addEventListener(Event.CHANGE, listevalg);
function listevalg (evt:Event)
{
Points=comboBox.selectedItem.Points;
// The ranking is now available as "item.Rank".
youChose.text=String(Points)+" points, rank "+String(comboBox.selectedItem.Rank);
}
If you don't actually need to keep the current order in the combobox, you don't even need to make a copy of the array before sorting.