I'm using Slickgrid to display data on a html site. The user can choose a table and the columns.
The code works well, but one table contains around 30 columns and around 500000 rows. Now the script takes too long and I get a firefox javascript timeout.
I know, that i can use setTimeout(), but i don't know how to use in this function.
What can i do, to avoid the javascript timeout?
function addRow(){
for (var i=0;i<arrayRow.length;i++){
var row ='{"id": "' + i + '", ';
for (var j=0;j>arrayColumn.length;j++){
row = row + '"' + arrayColumn[j] + '" : "' + array[j]+[i] + '",'
}
row = row.substr(0,row.length-1);
row = row + '}';
data[i]=JSON.parse(row);
}
if (i==arrayRow.length){
dataView.setItems(data);
}
}
Edit1: I've updated my code, but now I get the error "too much recursion".
i=0;
function addRow(){
if (i<arrayRow.length){
var row ='{"id": "' + i + '", ';
for (var j=0;j>arrayColumn.length;j++){
row = row + '"' + arrayColumn[j] + '" : "' + array[j]+[i] + '",'
}
row = row.substr(0,row.length-1);
row = row + '}';
data[i]=JSON.parse(row);
i++;
if(i%100000==0){
setTimeout(addRow,0);
} else {
addRow();
}
}
if (i==arrayRow.length){
dataView.setItems(data);
}
}
The timeout for script execution measure the time that took the execution of one method.
You need to separete "for" loop into several loops. For example you can make a method that add 100000 rows and call it with settimeout 5 times
Maybe it should be something like that:
var iFirstRow = 0;
funtion AddRows( _iFirstRow, _nRowsToAdd )
{
..implementation of adding nRows
iFirstRow = iFirstRow + nRowsToAdd;
if ( There is rows to add )
{
Call AddRows via timeout
}
else
{
..its ready
}
}
Related
I was given a task to make small change in schedule appointment calendar, the goal of this task is to display number of appointments per day(number of events can be displayed above of under day, see screenshot below). This app uses Full Calendar v1.5.4. I was looking at full calendar documentation but I didn't find anything useful there, this app already utilizes allDayText so it can not be applied there.
Do you know how can I create a new row below or above a day header and add there information about number of events that are happening that day?
Edit:
I've came up with the this code, added it in buildSkeleton method. Added 7 to i so column has unique value.
"<tr>" +
"<th class='fc-agenda-axis " + headerClass + "'> </th>";
for (i = 0; i < colCnt; i++) {
s += "<th class='fc- fc-col" + i+7 + ' ' + headerClass + "'/>";
}
s += "<th class='fc-agenda-gutter " + headerClass + "'> </th>" +
"</tr>" +
Which gives me a row that I need but for some reason it changes size of the first and last column.
Once styling will be fixed I'll have to find a place where I can insert a number of events.
Function below gives desired behavior, it updates number of events whenever view is changed.
Although I'm not able to adjust size of the first and last columns in header to the previous state, as you can see at the second screenshot they are way wider. I checked css file attached to the fullCalendar but didn't find anything there, it seems to be updated in fullCalendar.js file.
function SetCount(events) {
var startDate = calendar.getView().start;
var endDate = calendar.getView().end;
var e = events.filter(e => e.isBlockAppointment === false && startDate <= e.start && e.start <= endDate);
var hist = {};
dates = [];
e.map(function(a) { dates.push(a.start.getDay()) });
dates.map(function (a) { if (a in hist) hist[a]++; else hist[a] = 1; });
var colCnt = getColCnt();
if (colCnt === 1) {
$('.Index0').text(Object.keys(hist).length === 0 ? 0 : hist[Object.keys(hist)[0]]);
} else {
for (var i = 0; i < colCnt; i++) {
$('.Index' + i).text(i in hist ? hist[i]: 0);
}
}
}
Before:
After:
I tried add rowspan="2" to these rows and removed them from the second row but it doesn't work. How can I change a size of these 2 columns?
"<th class='fc-agenda-axis " + headerClass + "'> </th>";
"<th class='fc-agenda-gutter " + headerClass + "'> </th>"
I am seeking help trying to add a new table in my third function called ingredients. I am not very familiar with javascript so I tried to duplicate code from newDosage which is similar to what I need to do. Unfortunately, right now all I see is 0, 1, or 2 and not the actual text from the ingredient table. If anyone can help me correctly call the table, it would be greatly appreciated. Thank you.
Below is my code. The first function pulls the database, the second function uses the results and the third function is where I have tried to add the ingredient table.
function listTreatmentDb(tx) {
var category = getUrlVars().category;
var mainsymptom = getUrlVars().mainsymptom;
var addsymptom = getUrlVars().addsymptom;
tx.executeSql('SELECT * FROM `Main Database` WHERE Category="' + category +
'" AND Main_Symptom="' + mainsymptom + '" AND Add_Symptom="' + addsymptom + '"',[],txSuccessListTreatment);
}
function txSuccessListTreatment(tx,results) {
var tubeDest = "#products";
var len = results.rows.length;
var treat;
for (var i=0; i < len; i = i + 1) {
treat = results.rows.item(i);
$("#warning").append("<li class='treatment'>" + treat.Tips + "</li>");
$("#warning-text").text(treat.Tips);
$('#warning').listview('refresh');
//console.log("Specialty Product #1: " + treat.Specialty1);
if(treat.Specialty1){
$("#products").append(formatProductDisplay('specialty1', treat.Specialty1, treat.PurposeSpecialty1, treat.DosageSpecialty1, '1'));
}
if(treat.Specialty2){
$("#products").append(formatProductDisplay('specialty2', treat.Specialty2, treat.PurposeSpecialty2, treat.DosageSpecialty2, '0'));
}
}
}
function formatProductDisplay(type, productName, productPurpose, productDosage, Ingredients, aster){
var newDosage = productDosage.replace(/"\n"/g, "");
if(aster=='1'){ productHTML += "*" }
productHTML+= "</div>" +
"</div>" +
"<div class='productdose'><div class='label'>dosage:</div>" + newDosage + "</div>" +
"<div class='productdose'><div class='label'>ingredients:</div>" + Ingredients +
"</div></li>"
return productHTML;
}
You are missing an argument when you call formatProductDisplay(). You forgot to pass in treat.Ingredient.
Change:
$("#products").append(formatProductDisplay('specialty1', treat.Specialty1, treat.PurposeSpecialty1, treat.DosageSpecialty1, '1'));
To:
$("#products").append(formatProductDisplay('specialty1', treat.Specialty1, treat.PurposeSpecialty1, treat.DosageSpecialty1, treat.Ingredients, '1'));
Also do the same thing to the similar 'Specialty2' line right below it.
I have a method called refreshHistory() that basically reads locally stored list of json (using https://github.com/marcuswestin/store.js/) and populates a list in the order they were stored at.
Everytime a user action happens, this method is called. But as the list gets bigger and bigger, it slows down the browser to a crawl.
function refreshHistory() {
var records = typeof store.get('history') == "undefined" ? 0 : store.get('history').history;
;
if (records == 0) {
$('#content #historyView').html('<i>history show up here in order.</i>');
} else {
var xhistory = '<div id="history">';
for (var i = 0; i < records.length; i++) {
var xaction = records[i]
xhistory += '<div id="action">' + (i + 1) + '. ' + '<b>' + xaction.action + "</b> " + xaction.caption + '<span class="delaction" id=' + i + ' data-stamp="' + xaction.msg + '" style="color:red;cursor:pointer;">' + '[remove]' + '</span></div>'
}
xhistory += "</div>"
$('#qtip-0-content #historyView').html(xhistory);
}
}
Rendering everything on every event is a simple strategy, which is good, but it does run into the performance problems you are describing. It's hard to give specific advice, but you could either:
Implement a more detailed rendering logic, where only new items are rendered and added to the DOM.
Use ReactJs or Virtual DOM libraries, which allow your code to use the render everything pattern, but make the actual updates to the DOM faster by doing the minimum needed.
The only way to really make this efficient is to implement it in a different way.
I've been using knockout.js personally and am very happy with it. Basically you write a template and the library handles the DOM node changes, only updating the parts needed. You will need to learn how to think slightly differently, but there are some great tutorials available.
That said, one simple trick you can try is move the selectors outside the function so they are only ran once instead of each time you call the function.
For sanity I would also keep records variable the same type whether or not the .get('history') returns undefined.
var contentHistoryView = $('#content #historyView');
var qtipHistoryView = $('#qtip-0-content #historyView');
function refreshHistory() {
var records = typeof store.get('history') == "undefined" ? [] : store.get('history').history;
if (records.length) {
contentHistoryView.html('<i>history show up here in order.</i>');
} else {
var xhistory = '<div id="history">';
for (var i = 0; i < records.length; i++) {
var xaction = records[i]
xhistory += '<div id="action">' + (i + 1) + '. ' + '<b>' + xaction.action + "</b> " + xaction.caption + '<span class="delaction" id=' + i + ' data-stamp="' + xaction.msg + '" style="color:red;cursor:pointer;">' + '[remove]' + '</span></div>'
}
xhistory += "</div>"
qtipHistoryView.html(xhistory);
}
}
I doubt this will have a huge impact though, as I suspect most of the execution time is spent in the loop.
I have a Javascript function that prints various information from a json file and displays it in a table of contents fashion. It parses the information and prints it into a "ui-grid-b" div because i want them in rows of 3. I had a problem with the javascript printing repeatedly every time the page was opened so I added in a function to clear the div every time it prints. However, when I open a new seperate page with a "ui-grid-b" div in it it clears that and prints the table of contents again. Here's the js code and I hope you can help:
<script type="text/javascript">
var grid= new Array();
grid[0]= "a";
grid[1]= "b";
grid[2]= "c";
var j=0;
var color= new Array();
color[0]= '#00c6c4;';
color[1]= '#6fc41b;';
color[2]= '#ffbd0c;';
color[3]= '#ff84f1;';
color[4]= '#1fbbff;';
color[5]= '#ff1700;';
color[6]= '#976833;';
var k=0;
$(document).on("pageinit", "#Page1", function(){
var imp= "Json/empirical.json";
$.getJSON(imp, function(data) {
j=0;
k=0;
var toc= '';
$.each(data.tcontent, function(index, item) {
if (j > 2) { j = 0; }
if (k > 6) { k = 0; }
toc += "<div class='ui-block- ' " + grid[j] + " '>" + item.url + '<div class="grid" style="background-color: ' + color[k] + ' ">' + "<p class='gridtext'>" + item.Name + "</p>" + "</div>" + "</a>" + "</div>"
j++;
k++;
});
$(".ui-grid-b").empty().append(toc);
});
});
</script>
Assign your toc grid a unique ID:
<div id="theTOC" class="ui-grid-b"></div>
Then in your code instead of:
$(".ui-grid-b").empty().append(toc);
do
$("#theTOC").empty().append(toc);
Make sure this id is unique accross all pages. Also make sure your pages have unique IDs (i.e. only one page called "Page1").
I am trying to pull each element 'one by one' from two separate HTML lists and print each element after the other. If that doesn't make sense, here is some pseudo-code to better explain what I am trying to accomplish.
$('#tracktitle').append("<li class='titlelist'><a href='" + track.permalink_url + "' target='_blank'>" + track.title +"</a><br></li>")
$('#trackimage').append("<li class='imagelist'><a href='" + track.permalink_url + "' target='_blank'><img src='" + track.artwork_url + "' /></a></li>");
for(var i =0;i<7;i++){
// print 1st tracktitle
// print 1st image
// print 2nd tracktitle
// 2nd image ... etc
}
any help would be greatly appreciated
If you have to use for loop do this
for (var i = 0; i < 7; i++) {
$('#tracktitle').find('li:eq(' + i + ')'); // gives you the li tracktitle element as per index
$('#trackimage').find('li:eq(' + i + ')'); // gives you the li trackimage element as per index
}
To get the text and image use
$('#tracktitle').find('li:eq(' + i + ')').find('a').text();
$('#trackimage').find('li:eq(' + i + ')').find('a').html()
You can also use jquery.each if you want to navigate for elements
$('#tracktitle').find('li.titlelist').each(function () {
$(this) // gives you li element
});
Check http://jsfiddle.net/raunakkathuria/FVTUN/3/