JQuery datatable column data update works too slow - javascript

Working on generating table using datatable.
I have textbox below the table, when I add any value to that textbox then that value should be updated to specific column of 1st row then each row should be increment by 1 for that column(new updated value).
I have code for that, that works fine for me. But it takes too much time for that. I have 159 records in table and when I update column then it takes about to 8-9 seconds, this is very long duration. Till execution complete I am not able to do anything.
JS code:
updateNo: function(dataTableId, noColIndex, numToAdd) {
var dataTable = $(dataTableId).dataTable();
var numberOfRows = dataTable.api().rows().data().length;
var index;
for (index = 0; index < numberOfRows; index++) {
var cell = dataTable.api().cell(index, noColIndex);
var currentNo = cell.data();
var newNo = parseInt(currentNo) + numToAdd;
cell.data(newNo).draw();
}
}
I have tried to calculate method execution time and found that last line of method: cell.data(newNo).draw(); takes more time to execute.
I am not so much proficient in JavaScript or Jquery so I don't know the reason. If someone knows the reason and fix for this issue then please let me know.
I want to decrease execution time for this.

You don't have to redraw every cell, just redraw the entire table once after executing your code

Related

Paste the static value in the column besides if the particular cell is empty in google sheets

I might not be able to explain better, but I will try my best. I have two columns say A and B, in column A there are formulas so values in them get changed depending on some other conditions, Now what I want in column B is to paste/setvalue the value for the first time whenever a value appears in column A, so that when there are any further changes in column A, it wouldn't affect the value that is pasted in column B. Although I have tried my best to write the script, it does paste the value but it pastes in all the column and does not care if any cell in column A is empty.
I have gone through a lot of research but could not find an answer. Although OnEdit can work but as the column from which the value is to be got has formulas in it and OnEdit doesn't work on formulas. So once the script is corrected, we can trigger it to time driven.
I just need the help to make this function work correctly, I will be highly thankful for any help. thank you.
function pastevalue(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheet1');
var lastrow = ss.getRange("A2:B").getValues().filter(String).length;
var range = ss.getRange(2,1,lastrow);
var pasterange = ss.getRange(2,2,lastrow);
var values = range.getValues().filter(String);
var pastevalues = pasterange.getValues();
for (i=0; i<values.length; i++){
if(pastevalues[i] == ""){
var value = pasterange.setValue(values[i])
}
}
}
I presume that your goal is to grab the numerical value of a formula immediately after you enter it, so that if the displayed value in the cell of the formula changes in the future, you still possess the original value that the formula yielded. The following script accomplishes that:
function onEvent(e){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
if (e.range.getColumn() == 1 && typeof e.oldValue == 'undefined'){
sheet.getRange(e.range.getRow(), 2).setValue(e.range.getValue());
}
}
Note that it is an event trigger, meaning it runs every time the spreadsheet is, well, edited. As the parameter of the function we grab the event that triggered the script (you can read how they are structured here), and then we check for two conditions that both have to be true to copy the value into the B column:
First we check that the column of the cell modified is the A (1st) column.
Then we check that the cell was blank before modification. This will mean that the value will only be copied when a formula is written in a blank cell.

Javascript append some calculation results into table rows one by one

I'm working on a simple electron / node.js app, which takes input information locally, do some calculation and present calculation results in a table
Input:
10s of rows of features info
ID | length | depth |
Calculation: takes about seconds for each feature calculation.
Output:
Some amount of row from input, but with a results column
ID | length | depth | Results
I tried to append the results to tables for presenting, the code looks like this
<table id = 'results-table'>
<th>ID</th><th>length</th><th>depth</th><th>Results</th>
</table>
function getCrackTableValues(){
document.body.style.cursor = 'wait';
var table = document.getElementById('input-table'); //get info from input table
for (var r = 1, n = table.rows.length; r < n; r++) { //skip table head tart from second row
const crackID = table.rows[r].cells[0].innerHTML; //input
var a_m = Number(table.rows[r].cells[1].innerHTML); // input
var c_m = Number(table.rows[r].cells[2].innerHTML); //input
var result = foo(a_m, c_m); //foo just for example, takes seconds for calculation
var newRow = document.getElementById('results-table').insertRow(); //output table
newRow.innerHTML = '<td>'+ crackID+
'</td><td>' + `${a_m.toFixed(1)}` +
'</td><td>' + `${c_m.toFixed(1)}` +
'</td><td>' + `${result.toFixed(1)}` + //append results to output table
'</td>';
}
document.body.style.cursor = 'default';
}
The code works ok, but with couple issues.
Q1: I was hoping once a single calculation is done, it will show results on the output table, and move to next entry's calculation. So the user could see current results, while the calculation of the rest rows are going on.
Currently it seems the output table won't show up until all the calculations are done.
Are there any ways I could use to make the results table grows/shows up one by one, as calculation of each row goes on?
Q2: I was trying to disable the cursor while the calculation goes on document.body.style.cursor = 'wait';. and enable the cursor back on after all calculations are done.
But it seems this line executed after calculation, it would just disabled the cursor and flash back on.
Are there any potential issue with my current implementation? My node.js is v12.16.3, on a old 32bit windows 7.
The cause of both issues is the same: the UI won't get chance to update until it manages to escape your very-long-running loop.
You need to change foo() to become an async function. You've not shown any details, so I will assume it is pure CPU calculation and has no file or network access points.
I think I'd first pull out the loop contents into another function. And then I've put the loop termination condition at the top of that new function:
function processOneRow(r){
const table = document.getElementById('input-table');
if(r >= table.rows.length){ //All done
document.body.style.cursor = 'default';
return;
}
const crackID = table.rows[r].cells[0].innerHTML;
const a_m = Number(table.rows[r].cells[1].innerHTML);
const c_m = Number(table.rows[r].cells[2].innerHTML);
const result = foo(a_m, c_m);
const newRow = document.getElementById('results-table').insertRow();
newRow.innerHTML = '<td>'+ ...;
setTimeout(processOneRow, 0, r+1)
}
And then you can start it going by calling it for the first row:
function getCrackTableValues(){
document.body.style.cursor = 'wait';
setTimeout(processOneRow, 0, 1)
}
The use of setTimeout() with a 0ms delay, gives the UI thread time to update each time, before it will call processOneRow() on the next row of the input table.
Aside: Putting the code to restore the cursor inside processOneRow() is a bit of a code smell. If this code was going in a library, I would probably use before()/after() hooks. (You could then also make sure the after() hook gets called if there is an exception thrown.)
The other way to approach this would be to use worker threads and move the foo(a_m, c_m) calculation there. That would then naturally be async. Beyond the extra complexity, the downside of that is if foo() uses data, it needs to be kept with it in that worker thread, which gets complex if the same data is needed in the main thread. But, otherwise, it is a better solution for long running processes.

For loop keeps breaking out after 1 instance - Apps Script

I have looked everywhere I can think of for anything that can provide an answer to this. First time posting a question here - I can usually find my answers. I have a for loop that is pulling information from a range of data that is formatted in one cell like this: 09/01/2016 - Status changed to active.
The loop is supposed to first see how many values are in that column then go one by one and split the data into a simple array, post it into two columns on a separate sheet, then move onto the next one. The problem is that it stops after the first entry.
var numEntries = dataSheet.getRange(1,i+1,1000).getValues();
var lastEntry = numEntries.filter(String).length;
if (lastEntry == 7) {
// no change data to date
sheet.getRange(18,3).setValue("No changes yet");
} else {
var changeData = dataSheet.getRange(8,i+1,lastEntry-7).getValues();
for (var y = 0; y < changeData.length; y++) {
var changeHistory = changeData[y][y].split(" - ");
sheet.getRange(nextRow+1,2).setValue(changeHistory[0]);
sheet.getRange(nextRow+1,3).setValue(changeHistory[1]);
nextRow++;
Logger.log(nextRow);
Logger.log(changeData.length);
Logger.log(y);
}
}
I know that it is executing properly because it is properly setting the "No changes yet" value when there are no entries. Variable nextRow starts at a value of 17, and the log properly shows changeData.length with the number of entries and y being equal to 0. But then it stops. It doesn't follow the loop that y is still less than changeData.length. Any help is very much appreciated!
[edit] - I also want to point out that it does properly split and populate the first value into the two cells I want it to, so the whole for statement does work, it just doesn't loop. [edit]
[16-09-29 15:37:48:514 CDT] 18.0 [16-09-29 15:37:48:515 CDT]
11.0 [16-09-29 15:37:48:515 CDT] 0.0
changeData is an n*1 Array.
You are increasing y and and you are also trying to get the y-th column from changeData.
After the first iteration this is undefined because there's only one column.
undefined does not have a split method throwing an exception and terminating the script. (You may not see this exception, these kinds of exceptions aren't always shown to the user for some reason)
Try
var changeHistory = changeData[y][0].split(" - ");
instead.

jQuery calculation updating one row at a time

So, I'm trying to create a small table for working out the potential winnings of betting on a rubber duck race when each duck has certain odds.
I sort of have this working but have hit a stumbling block...
When the page loads all of the maths is done correctly based on the default value of £10. What I then want to do is allow people to change the amount of money they would like to bet per duck and the potential winnings for that duck only updates automatically.
This is what I have so far:
function calculate_odds(row) {
var winnings = 0;
// Set winnings to 0
var odds = $(row).find('#theodds').attr('data-duckodds'),
// Find the value of the data attribute for a specific td
betting_amount = $('[name="betting-amount"]').val(),
// Find the value entered into an input field
winnings = (parseFloat(odds) / 1 + 1) * betting_amount;
// Work out the winnings based on the odds given.
// Divide first number by 1 as all odds are something to 1 for now, then +1
// Multiply that number by the bet
// For example Bet 30 on 3/1 odds
// 3 / 1 = 3 + 1 = 4 * 30 = 120
$(row).find('.js-winnings').html(winnings.toFixed(2));
// Show the winnings amount in the final td in each row
}
$(document).ready(function() {
$('.lineup tbody tr').each(function() {
// Run the function calculate_odds() initially based on the default value;
calculate_odds();
$(this).find('[name="betting-amount"]').on('keyup', function() {
// Now loop through each row and change the winnings amount if the betting amount is changed
calculate_odds($(this).closest('tr'));
}).trigger('keyup');
})
});
From what I understand (my jQuery is not great), within this line: $(this).find('[name="betting-amount"]').on('keyup', function() { all I should need to do is select the specific row I want to update. Which should be simple right?
Instead what this does is takes the updated value from the first row and then applies as that as you change the later rows.
Can anyone point our where I'm going wrong? You can see the calculator here: http://www.kb-client-area.co.uk/ducks/races/race-1/
Thanks in advance :)
The specific problem you're encountering is where you're setting betting_amount:
betting_amount = $('[name="betting-amount"]').val()
You're looking globally in the document, and so finding the first instance.
Switching it to this makes it work:
betting_amount = $(row).find('[name="betting-amount"]').val()
As an aside: it would be better to use a class instead of an ID for #theodds, as IDs are supposed to be unique per document :)
I think perhaps your 'this' isn't referring to what you think it is in this line: calculate_odds($(this).closest('tr'));
Could you try something along the lines of:
$(this).find('[name="betting-amount"]').on('keyup', function(e) {
// Now loop through each row and change the winnings amount if the betting amount is changed
calculate_odds($(e.target).closest('tr'));
}).trigger('keyup');
})
As I said earlier, element IDs must be unique in a given document. You have the id theodds repeated as many times as the number of rows in your table which makes your HTML invalid! Remove those IDs and you could just work around the data-* that you already have.
function calculate_odds(row) {
row = $(row);
var winnings = 0,
//find the data-* from within the context of the keyup - the row
odds = row.find('[data-duckodds]').attr('data-duckodds'),
//find the entered amount from within the context of the keyup - the row
betting_amount = row.find('[name="betting-amount"]').val(),
//Your math
winnings = (parseFloat(odds) / 1 + 1) * betting_amount;
row.find('.js-winnings').html(winnings.toFixed(2));
}
$(document).ready(function() {
//You don't need an each loop here as the keyup will be triggered on every amount box on load as well.
$('.lineup').on("keyup", "[name='betting-amount']", function() {
calculate_odds($(this).closest('tr'));
})
.find("[name='betting-amount']").keyup();
});
Take a look at this fiddle for a demo.

Index or size is negative or greater than allowed amount (non-negative indices)

While using Firefox, I keep getting the error described in the subject line for this block of code:
for(var i = 0; i < tables.length; i++)
{
var j = rows.length - 1;
while(j--)
{
if(hideDP && tables[i].innerHTML.indexOf(">D<") != -1)
{
if(!platTag && !soulSilverTag && pearlTag)
{
tables[i].deleteRow(j);//ERROR IS ON THIS LINE
}
}
}//end while loop (rows)
}//end for loop (tables)
I suspect that this error is because I'm somewhat new to making reverse loops, but I specifically made a reverse loop in this instance because it made deleting rows from a table easier. Note also that j is something like 24 and i is 0, so they're non-negative. Could someone shed some light on this for me?
EDIT : The full code can be found here.
Strictly working off of the currently posted code, here are the issues I see:
The posted code looks incomplete. Where is rows being initialized? This could cause the stated error.
Given while(j--);   The var j = rows.length - 1; line is incorrect. That is, unless you know that the last row will never need deleting. But if that is the case, then comment the code to make it clear.
For example, if there were 4 rows, the current code initializes j to 3, but because of the location of the -- operator, the inside of the loop sees: 2, 1, 0.   For the code as shown, use var j = rows.length; or add a comment to show that the logic is deliberate.
The 2 if() statements do not depend on j at all! (At least as the code is posted here.) If this is true, then move the conditionals outside of the j loop.
Consider posting the full, unedited, code. Or linking to it on a site like Pastebin.
Update for full script, now that it's been linked to:
Scanning the complete code, it looks like tables[i].deleteRow(j); can be called multiple times for the same row.
The easy solution, that should be done anyway, is to add a continue statement after each row delete.
For extra credit, reanalyze and simplify the flag and if logic too. :)
Update for target page, now that it's been linked to:
Examining the target page, the tables being looped by this script contain nested tables.
That throws off the row count in this line:
var rows = tables[i].getElementsByTagName("tr");
Sometimes making it seem like table[i] has more rows than it really directly owns.
Solution, use the built in rows array; so the line becomes:
var rows = tables[i].rows;
~~~~
While examining the script relative to the target page, a few other issues seemed apparent:
It's not best to loop through all tables. Target just the ones you need. So this:
tables = document.getElementsByTagName("table");
Should be changed to:
var tables = document.querySelectorAll ("div.KonaBody > table.roundy");
...which will select just the 4 payload tables, and not their subtables or the other tables scattered about.
By fine-tuning the initial table selection, the following, problamatic, test is not needed:
if(tables[i].getAttribute("style").indexOf("border: 3px solid") != -1)
Missing var in front of the majorSections initialization.
That error will also be generated if j is >= to the amount of rows in the table, but I'm not seeing the exact problem.

Categories

Resources