I have html page with many rows (is about 40000)
<html><body>
<table id="t1">
<tr id="r1" name="1"><td>row 1</td></tr>
<tr id="r2" name="1"><td>row 2</td></tr>
....
<tr id="r50000" name="3"><td>row 30000</td></tr>
</table></body></html>
I need a fast way to hide/show set of rows (10 000 or 20 000) with the specified name. Platform requirements: IE8-9 and Mozila Firefox. I tray many methods: using tbody, block tags, hiding rows, and stop at one: loop trow the rows and hide/show it:
curLevel=root.getAttribute("Name");
var nextElement=curElement.nextElementSibling;
while(nextElement!=null)
{
curElement=nextElement;
nextElement=curElement.nextElementSibling;
if(curElement.tagName=="TR")
{
i++;
childLevel=curElement.getAttribute("Name");
if(childLevel<=curLevel)
break;
curElement.style.display = blockStyle;
}
}
But this method is very slow!! Takes is about 2 minutes...
Loop goes fast, the slowest part is curElement.style.display = blockStyle; it repaints document every time.
Could I change display style for selection rows and then show changes?
P.S. without jQuery
Probably the fastest way is to use a CSS rule, either by adding and removing a rule, or modifying one. Since the rows you wish to hide have a common name, you can use the equivalent of the following to hide the rows with a name of "1":
tr[name="1"]{
display: none;
}
and remove the rule to show them. The following shows how to do that.
// Object to hold functions for adding and removeing style rules
var myStyles = (function() {
// Use the first style sheet for convenience
var sheet = document.styleSheets[0];
// Delete a rule from sheet based on the selector
function deleteRule(selector) {
// Get rules
var rules = sheet.rules || sheet.cssRules; // Cover W3C and IE models
// Search for rule and delete if found
for (var i=0, iLen=rules.length; i<iLen; i++) {
if (selector == rules[i].selectorText) {
sheet.deleteRule(i);
}
}
}
// Add a rule to sheet given a selector and CSS text
function addRule(selector, text) {
// First delete the rule if it exists
deleteRule(selector);
// Then add it
sheet.insertRule(selector + text);
}
// Return object with methods
return {
'addRule': addRule,
'deleteRule': deleteRule
};
}());
// Convenience functions to hide and show rows
function hideRows(){
myStyles.addRule('tr[name="1"]','{display: none}');
}
function showRows(){
myStyles.deleteRule('tr[name="1"]');
}
Alternative behaviours for the addRule function if a rule with the selector already exists are:
do nothing, or
add the new CSS text to the existing rule
Some play HTML:
<table>
<tr name="1"><td>name is 1
<tr name="1"><td>name is 1
<tr name="1"><td>name is 1
<tr name="1"><td>name is 1
<tr name="2"><td>name is 2
<tr name="2"><td>name is 2
<tr name="2"><td>name is 2
<tr name="2"><td>name is 2
</table>
<button onclick="hideRows()">Hide rows named 1</button>
<button onclick="showRows()">Show rows named 1</button>
Clicking on the first button hides all rows with a name of "1" by adding a CSS rule, clicking the other button shows them by removing the rule.
Of course you can make it much more sophisticated, the above just shows the method.
a table with 40000 rows is not the best for a webpage....
like pradipgarala say you should do it from server side.
or at list use "divs" to separate multiple tables with less rows..
<div id="table_1_1000">
<table>
...rows from 1 to 1000
</table>
</div>
like this you can show-hide only the divs you need... and the loop would be faster...
but still not the best solution....
My first idea would be to do something like this:
var start = 20000; // hide 10k rows
var end = 30001; // rows from 20k to 30k
while(end!=start) {
end--;
var x = 'r' + end;
document.getElementById(x).style.display = "none";
}
Basically, I would use IDs instead going trough DOM Nodes, if possible. It's "cheaper".
Since performance is an issue, you should note that is faster to decrement than to increment.
Note: Since I don't have enough rep, I can't comment on pradipgaralas answer so I'll note it here... Can you do something like IF "request is to hide/show over 10k(or whatever number your benchmark show you) rows" SEND REQUEST TO SERVER ELSE DO YOUR THING ON CLIENT SIDE?
Related
I'm writing a python app which is displaying an HTML table of pupil capabilities. I want to add the ability to filter the view depending on those capabilities - including multiple filters at the same time, hence wanting to do this in javascript (managing this via database lookups was becoming unwieldy).
I have a table which has a grid of capabilities (true/false), and to each 'false' I have added a class, such as 'pupil_web', and I have written a javascript function which will hide the on that row, triggered by a button at the top of each column.
But what I want is for the function to hide the entire row if it contains a td of that class, and I can't work out how to do it. I'm a fairly basic Python programmer, and this is my first project of any reasonable size; so far it's going well, but having spent a couple of hours trying to get this working (and getting as far as hiding the TD, not the enclosing row), I'd appreciate some help or a pointer in the right direction - I can't work out how to make the function look inside the row's content, only to look at each individual TD.
Here's the Javascript (note that at the moment I'm using Jinja2 to create multiple functions, each one for each capability, where the name of the function and the capability DIV content are linked - again I'm sure I'm not doing that in the best manner (creating a function for each column), but at the moment I'd rather get it working in the present form and then hopefully optimise in the future).
function toggle_{{ capability }}() {
var table, td, i;
table = document.getElementById("myTable");
td = table.getElementsByClassName("div_{{ capability }}");
// Loop through all table rows, and hide those who don't match the search query
for (i = 0; i < td.length; i++) {
if (td[i].style.display === "none") {
td[i].style.display = "";
} else {
td[i].style.display = "none";
}
}
}
Here's a simple version of the HTML table (the real one has about 20 columns, with a class tag present for the column entry that would lead to a row being hidden).
<tr>
<td>
Pupil 1
</td>
<td>
<img class="pupil_web" src="static/cross.png" width="25">
</td>
<td>
<img src="static/tick.png" width="25">
</td>
</tr>
<tr>
<td>
Pupil 2
</td>
<td>
<img src="/static/tick.png" width="25">
</td>
<td>
<img class="pupil_email" src="static/cross.png" width="25">
</td>
</tr>
Any pointers in the right direction would be greatly appreciated - I've not been at this long (I'm about 4 months in to a 2-year self-study plan), but I'm trying to learn rather than just give up and/or paste code in without understanding it.
Try this:
function toggle_{{ capability }}() {
var table, td, i;
table = document.getElementById("myTable");
td = table.getElementsByClassName("div_{{ capability }}");
// Loop through all table rows, and hide those who don't match the search query
if (td.parent().style.display === "none") {
td.parent().style.display = "";
} else {
td.parent().style.display = "none";
}
}
}
I have a table with some items and those items can be selected by adding a tick. Check the image attached:
What I need to achieve is to hide the row which does not contain any ticks to be not visible. This is because in my app I have to generate lists of the items contains only ticks in another view. So when I will press the generate button that row will be hidden.
I just want to say if that row does not contain any 'glyphicon-ok' need to be deleted/hidden when I will generate the view with the list of those items.
I tried something like this:
SveCrf.prototype.hideRowWhereNoTicksForm = function () {
var tr = document.getElementsByTagName('tr');
for (var i = 0; i < tr.length; i++) {
switch (tr.item(i).getElementsByTagName('td').item(0).className) {
case "glyphicon-ok":
tr.item(i).style.display = "none";
break;
}
}
}
This doesn't do anything.
I would like to see an example of being able to resolve this issue.
Correct me if I'm wrong but you don't seem to have provided HTML you want to act upon but just a screenshot and a link to some RoR code in the comments that generates the HTML. Also you don't show how you try to execute SveCrf.prototype.hideRowWhereNoTicksForm, and furthermore I'm not really sure at all what you are trying to do with switch/case (I also don't understand what item is supposed to be; this is where providing us with actual HTML might have helped).
In addition, as I've alluded to in some comments of mine, you are really trying to do two things. I don't know if you've seen this Stackoverflow page yet about creating "a Minimal, Complete, and Verifiable example" but I think reviewing that will help improve your StackOverflow experience moving forward (and also for me it validated my suggestion of "divide and conquer").
All of which I think made it hard for you to get the help you desired. In any case below I'm providing some sample HTML with a table containing four rows total, two with a cell that contains the class foo, and two that don't. Beneath that is my non-jQuery code selecting the rows with no cells containing the class foo, and then hiding them; furthermore there is a demo of the same functionality using jQuery at https://repl.it/#dexygen/HideRowsWithNoCellsWithClass
<table border="1">
<tr><td class='foo'>foo</td><td></td><td></td></tr>
<tr><td></td><td>bar</td><td></td></tr>
<tr><td></td><td></td><td>baz</td></tr>
<tr><td class="foo">foo</td><td>bar</td><td>baz</td></tr>
</table>
/*
We cannot call `filter` directly on an HTMLCollection such as returned by
"document.getElementsByTagName('tr')" as it is not a bona fide array, so we use
"[].filter.call()", and we return only those rows that *fail* the test
"row.querySelector('td.foo')", then we loop over these with `forEach` and hide them
*/
[].filter.call(document.getElementsByTagName('tr'), function(row) {
return !row.querySelector('td.foo');
}).forEach(function(row) {row.style.display = 'none'});
I have a treeview-table like this: http://jsfiddle.net/NPGUx/6/ and I'm using:
$('.toggle').trigger('click');
to hide all elements onload, the problem is that I have too many rows (like 1000-1500) so that cause that the message "Script is running slowly, do you want to stop it?" appears like three times.
How can I make a better solution to hide all elements?
How about this:-
Change your classes from collapse to expand as you render the records and use this query at the end, to hide all but the 0th level, or hide all the other level tr's while rendering itself.
Script
$('tr[data-depth]').not('[data-depth=0]').hide(); // Or just render all tr's but this
//with display:none css property.
Change your filter to avoid filtering from all tr's to this:-
var rootDepth = $(this).closest('tr').data('depth');
var findChildren = function (tr) {
var depth = tr.data('depth');
return tr.nextUntil('[data-depth=' + rootDepth + ']').filter(function(){
return $(this).data('depth') > depth;
});
Html
<tr data-depth="0" class="expand level0"> <!--Instead of collapse-->
<td><span class="toggle expand"></span>Item 1</td> <!--Instead of collapse-->
Demo
I got whole table, which has cells with particular ID's, example: "2012-01-01_841241" etc etc. Date, then some number.
I want to filter my table, so I send some request and get for example three numbers which should be only shown.
I want to hide all cells without these numbers in their IDs - is it any other way than iterating over all of them and check if their ID matches my ID string? (It looks costly).
So, i'm trying to avoid it (especially, when I will have a table of someNumbers :) ):
$('td').each(function(){
if($(this).attr("id") != someNumber) $(this).hide();
})
Thanks!
Well here is a way you can do it (jsFiddle here):
Essentially you can hide everything then make the ones you want visible:
$("#myTable td").hide();
showCells("2012-01-01_841242", "2012-01-01_841247");
function showCells() {
for (var i = 0; i < arguments.length; i++)
{
$("#" + arguments[i]).show();
}
}
The problem however with doing this on a table is that you can end up with an uneven number of <td> tags inside your various <tr> tags so you may want to find a different way to lay them out.
Did you consider something like this:
You can alway hide all tds and than show only these which you want to show
var id = getCurrentIdNotToHide();
$('td#'+id).show();
But I'm not sure if this is better solution
Use this code:
$('td:not([id="' + someNumber + '"])').hide();
I have the following jquery code to loop over 525 (I know, alot!) checkboxes:
var elements = $("#profile-list table tr input[type=checkbox].email-checkout:not(:checked)");
$.each(elements, function(i) {
$(elements[i]).attr('checked', 'checked');
});
UPDATE The html looks like this:
<table>
<tr>
<th>Name</th>
<th>Title</th>
<th>E-mail</th>
<th>Telephone</th>
<th id="email_check"><img src="check_black.png"/></th>
</tr>
<?php foreach ($this->profiles as $profile): ?>
<tr>
<?php echo $this->presentProfile($profile, 'list') ?>
</tr>
<?php endforeach; ?>
This basically loops over all profiles in the database and creates a table row for each profile, where the last table data includes a checkbox, which one can select to send email to. If the user clicks the table header with the id of "email_check" then the javascript code should kick in, and that's where Chrome fails.
I attach the event with the following code:
$("#email_check img").live('click', function() {
//my code
}
When I run this code in Firefox (mac), it goes smoothly but when I run it in Chrome (mac) it takes forever and ends up giving me the window where chrome offers me the option of killing the window, so basically it never completes this loop.
I've been trying to optimize this selector as much as I can, and since jquery 1.3, I understand that they switched from left to right to right to left selector, which basically means that I should try to make my right most selector as specific as I can. Can it be any more specific than I currently have?
Or is it the loop that just takes so long? I have tried switching from $.each to just a regular for() without a positive result.
Any tips or ideas how I can fix this?
Ingiber
I really don't think this is a selector issue at all.
Your selector is a valid selector for querySelectorAll, which means it will be extremely fast.
I tested the exact selector in Chrome on Mac against a table with 250 rows, and the result was instantaneous.
I'd guess that there's something else going on.
Try removing the table tr part of the selector. It isn't adding anything.
Try this:
// console.time("test");
var elements = $("#profile-list input[type=checkbox].email-checkout").get();
var len = elements.length;
for (var i = 0; i < len; i += 1) {
elements[i].checked = true;
}
// console.timeEnd("test");
(So, first we select all check-boxes that are of the class "email-checkout" and are inside the #profile-list element. Then we just set their checked property to true. I assume, this is as fast as it can be.)
You could always give each check box a select/deselect event that will add/remove a class from the checkbox, then use the class as the selector.
You can use a .each() on the set to use the elements directly, like this:
$("#profile-list table tr input[type=checkbox].email-checkout").each(function() {
this.checked = true;
});
Also note the removal of :not(:checked) above...if you're going to check them all, that selector is more expensive that actually checking them anyway. More importantly is that this.checked = true; is tremendously cheaper than $(elements[i]).attr('checked', 'checked'); which happens every time.
Did you profile this? What is taking too long, getting the elements or looping over them? The only way to really speed up code is to profile and fix the slow parts.
FWIW, I would try
var elements = $("#profile-list").find("input[type=checkbox].email-checkout").get();
...
and see what happens.
Add an onlclick on the checkbox
$("#profile-list input[type=checkbox].email-checkout").click(function() {
var obj = $(this);
obj.hasClass("checked") ? obj.removeClass("checked") : obj.addClass("checked");
});
s = $("input[type=checkbox].email-checkout.checked");