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");
Related
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 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();
Example:
<table id ='table'>
<tr>
<td>1</td>
<td><select id='old' name='old'></select></td>
<td><select id='old2' name='old2'></select></td>
<td><div id='old3' name='old3'></div></td>
</tr>
</table>
How to change the value of id or name from select id ='old' to select id ='new' (for example) after deleting rows in javascript?
I have been trying all the methods like trying getElementById('old') = 'new' but not work, used replaceChild also not work (or maybe I put the wrong code, no idea).
Do you have other alternatives? (No JQuery, please).
Thanks.
You can use the setAttribute method to accomplish this
document.getElementById("old").setAttribute("id","new");
document.getElementById("new").setAttribute("name","new");
var sel = document.getElementById("old"); //Reference the element
sel.id = "new"; //set the id
try this :
document.getElementById("old").name = 'NewName';
alert(document.getElementById("old").name);
document.getElementById("old").id = 'Newid';
alert(document.getElementById("Newid").id);
its work for me.
I feel there is something inelegant going on here; if you told us more we'd be able to say the "right way" to do it. If you nevertheless have a very good reason to do what you're doing, merely call this snippet of code you have made all your changes. It will update all the elements in your rows to have the correct numbering.
var formElements = document.getElementById('table').getElementsByClassName('toUpdate');
for (var i=0; i<formElements.length; i++) {
var e = formElements[i];
e.id = 'new'+i;
}
There are quite a few variations on this if you didn't want to add a class="toUpdate ..." to each one. For example you were using regular form elements, you could iterate over the <form>'s elements. Or you could iterate through all the elements and pattern-match on the names or ids. Or if you are algorithmically generating this with javascript you could add each element to an array at the same time you add it to the DOM, for later use (like this update).
<td> <input type="button" name="buton" id="x2" value="2" onclick="swap(id)";/> </td>
This is the button in a table when it is clicked it's id is passed as parameter to function "swap" as below:
function swap(x)
{
document.write(x);
}
It is successful in getting the id but not the value;when i am trying in this way:
function swap(x)
{
document.write(x.value);
}
The output is shown as undefined. Can you tell me how to get the cell value using the cell id?
I believe that what you are looking for is document.getElementById(x).value;
Also if you want the button just pass this to the function like this:
<button onclick="foo(this)"/>
I guess use jQuery for the purpose,it allows to traverse in DOM very easily.
<table id="mytable">
<tr><th>Customer Id</th><th>Result</th></tr>
<tr><td>123</td><td></td></tr>
<tr><td>456</td><td></td></tr>
<tr><td>789</td><td></td></tr>
</table>
If you can, it might be worth using a class attribute on the TD containing the customer ID so you can write:
$('#mytable tr').each(function() {
var customerId = $(this).find(".customerIDCell").html();
}
Essentially this is the same as the other solutions (possibly because I copypasted), but has the advantage that you won't need to change the structure of your code if you move around the columns, or even put the customer ID into a < span >, provided you keep the class attribute with it.
By the way, I think you could do it in one selector:
$('#mytable .customerIDCell').each(function()
{
alert($(this).html());
});
If that makes things easier
Code will be more or less more reliable on cross bowser issue
z = document.getElementById(id); first, and then you should be able to use z.firstChild.textContent
You need to get the cell using var cell = document.getElementById(x). Then use cell.firstChild.nodeValue.
function swap(x)
{
var cell = document.getElementById(x);
document.write(cell.firstChild.nodeValue);
}
EDIT: Tested this on both FF3.5 and IE8 and it works.
If you are passing the id of the element you might want to use document.getElementById(x) to access it.
First off, I'm working on an app that's written such that some of your typical debugging tools can't be used (or at least I can't figure out how :).
JavaScript, html, etc are all "cooked" and encoded (I think; I'm a little fuzzy on how the process works) before being deployed, so I can't attach VS 2005 to ie, and firebug lite doesn't work well. Also, the interface is in frames (yuck), so some other tools don't work as well.
Firebug works great in Firefox, which isn't having this problem (nor is Safari), so I'm hoping someone might spot something "obviously" wrong with the way my code will play with IE. There's more information that can be given about its quirkiness, but let's start with this.
Basically, I have a function that "collapses" tables into their headers by making normal table rows not visible. I have "onclick='toggleDisplay("theTableElement", "theCollapseImageElement")'" in the <tr> tags, and tables start off with "class='closed'".
Single clicks collapse and expand tables in FF & Safari, but IE tables require multiple clicks (a seemingly arbitrary number between 1 and 5) to expand. Sometimes after initially getting "opened", the tables will expand and collapse with a single click for a little while, only to eventually revert to requiring multiple clicks. I can tell from what little I can see in Visual Studio that the function is actually being reached each time. Thanks in advance for any advice!
Here's the JS code:
bURL_RM_RID="some image prefix";
CLOSED_TBL="closed";
OPEN_TBL="open";
CLOSED_IMG= bURL_RM_RID+'166';
OPENED_IMG= bURL_RM_RID+'167';
//collapses/expands tbl (a table) and swaps out the image tblimg
function toggleDisplay(tbl, tblimg) {
var rowVisible;
var tblclass = tbl.getAttribute("class");
var tblRows = tbl.rows;
var img = tblimg;
//Are we expanding or collapsing the table?
if (tblclass == CLOSED_TBL) rowVisible = false;
else rowVisible = true;
for (i = 0; i < tblRows.length; i++) {
if (tblRows[i].className != "headerRow") {
tblRows[i].style.display = (rowVisible) ? "none" : "";
}
}
//set the collapse images to the correct state and swap the class name
rowVisible = !rowVisible;
if (rowVisible) {
img.setAttribute("src", CLOSED_IMG);
tbl.setAttribute("class",OPEN_TBL);
}
else {
img.setAttribute("src", OPENED_IMG);
tbl.setAttribute("class",CLOSED_TBL);
}
}
Have you tried changing this line
tblRows[i].style.display = (rowVisible) ? "none" : "";
to something like
tblRows[i].style.display = (rowVisible) ? "none" : "table-row";
or
tblRows[i].style.display = (rowVisible) ? "none" : "auto";
setAttribute is unreliable in IE. It treats attribute access and object property access as the same thing, so because the DOM property for the 'class' attribute is called 'className', you would have to use that instead on IE.
This bug is fixed in the new IE8 beta, but it is easier simply to use the DOM Level 1 HTML property directly:
img.src= CLOSED_IMAGE;
tbl.className= OPEN_TBL;
You can also do the table folding in the stylesheet, which will be faster and will save you the bother of having to loop over the table rows in script:
table.closed tr { display: none; }
You might want to place your onclick call on the actual <tr> tag rather than the individual <th> tags. This way you have less JS in your HTML which will make it more maintainable.
If you enable script debugging in IE (Tools->Internet Options->Advanced) and put a 'debugger;' statement in the code, IE will automatically bring up Visual Studio when it hits the debugger statement.
I have had issues with this in IE. If I remember correctly, I needed to put an initial value for the "display" style, directly on the HTML as it was initially generated. For example:
<table>
<tr style="display:none"> ... </tr>
<tr style="display:"> ... </tr>
</table>
Then I could use JavaScript to change the style, the way you're doing it.
I always use style.display = "block" and style.display = "none"