I have a table with the odd and even rows with a different CSS style tr:nth-child(2n){...}, and when I filter them with a textbox and jQuery, I hide() all the rows except the ones that match my criteria.
The problem is that now the rows remain with the current style (as I assume they keep the position despite they can't be seen), so the new odd and even rows doesnt match the CSS pattern.
How could I fix it?
Try to follow this example:
jQuery('tr:visible').filter(':odd').css({'background-color': 'red'});
jQuery('tr:visible').filter(':even').css({'background-color': 'yellow'});
Check here:
http://jsfiddle.net/KSL7j/1/
Hope it helps
Update
You can check this other example with odd and row CSS classes.
As CAbbott suggested in this fiddle: http://jsfiddle.net/KSL7j/21/
nth-child checks for the nth-child, not for the nth visible child or th nth whatever-styled child (hide() just adds display:none and nothing more...) and will never do.
I see two possible solutions:
1.add classes even/odd after filtering, just asking for the visible ones and then use your css on those classes
untested code:
var rows = $(tr[#display=block]);
rows.each(function(){
var index = rows.index(this);
if(index%2==0){
$(this).addClass('even');
}
else{
$(this).addClass('odd');
}
}
2.really remove the rows, not just hiding them
when you use hide() it is just set the display to none.
the structure of the dom is not modify so the nth-child do not work as you expected
you need to remove the even tr to get the effect you want.
if you want reset the rows. you can hold them in a variable and restore them back
var rows = $("tr");
var even = rows.filter(":even");
$("#trigger").click(function () {
even.hide();
even.remove();
});
http://jsfiddle.net/R2gBt/
Related
I'd like to select last div which id starts with "level":
var div = $('div[id^="level"]:last');
But as well I'd like to select the last and visible one. How could I perform that? Following doesn't work:
$('div[id^="level"]:last:visible');
I tried couple different combinations but none worked.
Try switching your :last and :visible that was you first filter all the elements by their visibility, and then filter for the last one.
$('div[id^="level"]:visible:last');
Maybe something like this?
var div = $('div[id^="level"]:last').filter(":visible");
I have a layout where I need each child div in two columns to have a minimum height equivalent to the height of the window. To do this, I use:
$('.element').css("min-height",$(window).height());
This works for my purposes, however I wish to apply this to a number of elements, as aforementioned.
I used an array to attempt to achieve this:
var length = [$('.first'), $('.second'), $('.third'), $('.fourth'), $('.one'), $('.two'), $('.three'), $('.four')];
length.css("min-height",$(window).height());
As I am only new at javascript, I am unsure if it is even possible to select elements in this manner. Any help would be appreciated.
Here is a jsfiddle.
Instead of supplying multiple selectors, you could as well add a new class to all elements that need to be modified.
For example, add class="adjust-min-height" and then use
$('.adjust-min-height').css("min-height", $(window).height());
edit:
If you want to use an array similar to what you asked for in your question, you could do this:
var elements = ['.first', '.second', '#maybe-an-id', '.third'];
var selector = elements.join(', ');
$(selector).css('min-height', $(window).height());
You can of course put the .join(', ') after the array, I just split it up for clarity.
When supplying multiple selectors, separate them by a comma:
$('.first, .second, .third, .fourth, .one, .two, .three, .four').css("min-height", $(window).height());
However the above code completely misses the point of classes; you should put a single class on all the above elements and use one selector only - exactly as your first example does.
I have table which is being dynamically created.
I would like to try not to have any more attributes in the table (like an ID field).
It is a multilevel table where all the TableRows should be expandable and collapse on click in any of the TD in each row.
$('.fylke_click').click(function () {
$(this).parent().nextUntil('.fylke').slideToggle(0);
$('.sted').hide();
});
$('.kom_click').click(function () {
$(this).parent().nextUntil('.kommune').slideToggle(0);
});
See this simplified fiddle:
http://jsfiddle.net/T2Lwn/
So it's basically 3 levels and it is a lot of problems here.
One obvious one is when you are on the second level, which is called "kommune" and if you click on the last TR it removes the "fylke" underneath. As you can see if you click on "MIDTRE GAULDAL"
This is probably because I use .Parent() and I need some sort of if check if I am on the last row?
Is it also other problems with this code? Can I specify the click method class="fylke_click" and class="kom_click" on a more general level?
For example for all <tr class="fylke"> each TD class will have class="fylke_click" and same for kommunne?
If I understand your issue correctly this may help:
Demo Fiddle:
Since you said you're going to be dynamically creating this content, I would recommend delegating off of the main table instead of making a click handler for each row. Also, since all of the stuff you want to show / hide are siblings and not nested, things get a bit tricky. You'll need to be specific with your .nextUntil() by passing a filter, and I found a :not() on the filter was necessary.
Again, since these are all siblings, it's not as easy as hiding the children of the header row, so I set up an "open" class to check if the header was open or not, and hid / showed stuff depending on if it was already open.
JS:
$('.kommune').hide();
$('.sted').hide();
$('.table').on('click', 'tr', function(){
$this = $(this);
if( $this.hasClass('fylke') ){
if ( $this.hasClass('open') ) {
$this.toggleClass('open').nextUntil('.fylke', 'tr').hide();
}
else {
$this.toggleClass('open').nextUntil('.fylke', 'tr:not(.sted)').toggle();
}
}
else if ( $this.hasClass('kommune') ){
$this.nextUntil('.kommune', 'tr:not(.fylke)').toggle();
}
});
In your source code you can define tfoot before tbody but in the browser tfoot will still be displayed last:
<table>
<thead><tr><th>i get displayed first</th></tr></thead>
<tfoot><tr><td>i get displayed last</td></tr></tfoot>
<tbody><tr><td>i get displayed second</td></tr></tbody>
</table>
Now, I want to grab the tr elements of this table in their visual order, not the order they have in the html. So this of course does not do the trick:
var rows = $('table tr');
jQuery goes through the table and adds the tr elements in the order they appear in the source code.
I thought I could make separate blocks and concatenate them to get the right order:
var header = $('table>thead>tr');
var body = $('table>tbody>tr');
var footer = $('table>tfoot>tr');
var rows = $().add(header).add(body).add(footer);
Strangely enough the order is still the same as if I did $('table tr')! How can this be?
I've also illustrated the problem in a jsFiddle: http://jsfiddle.net/nerdess/sKewX/2/
If you want to have the elements in the exact order you want, you need to build the result manually. I've modified your code in the fiddle: http://jsfiddle.net/lechlukasz/sKewX/3/
var header = $('table>thead>tr');
var body = $('table>tbody>tr');
var footer = $('table>tfoot>tr');
var apppend = function(arr, items) {
for (var i=0;i<items.lenght;i++)
arr.push(items[i])
}
var rows = []
append(rows, header)
append(rows, body)
append(rows, footer)
console.log(rows);
Element selectors look at the DOM, so they will only return the elements in the order they appear in the DOM.
If you want them in the VISUAL order you'll have to determine the positioning of each item yourself.
See: Determining an element's absolute on-document position
From documentation for add() method:
Do not assume that this method appends the elements to the existing
collection in the order they are passed to the .add() method. When all
elements are members of the same document, the resulting collection
from .add() will be sorted in document order; that is, in order of
each element's appearance in the document. If the collection consists
of elements from different documents or ones not in any document, the
sort order is undefined. To create a jQuery object with elements in a
well-defined order, use the $(array_of_DOM_elements) signature.
So yes, it will appear the same as $('table tr');
Because $('table tr') will only look for code (it has nothing to do with the console).
Now because you add the body to var rows before you add the footer, it is logical that the display will be different from the code.
It's the same as publishing a book and then telling the readers to read page 3 before page 2:
Now the readers ('the console') know the correct order, but the book still retains a wrong order of page numbers.
So to make life easy: try to keep code and display as parallel as possible. Hence try to keep the same order in both to avoid unnecessary complexity.
Here's an example using the insertion sort algorithm (http://en.wikipedia.org/wiki/Insertion_sort). By design, add() collects the elements in the DOM order.
The idea is to sort the elements based on how they'd be seen visually (using their offset).
JsFiddle: http://jsfiddle.net/Pv4tj/
http://jsfiddle.net/NzbRQ/2/
I allow the user to add multiple rows of fields, but I do not want to include a delete link on the very first row of fields, so they can't delete all the fields.
Also, how do I limit it to only 3 rows of fields?
Try this fiddle: Fiddle
For the first part of hiding the delete on the first row, I called the following on page load:
$(".removeoutcome").hide();
Then to make sure they can't add more than 3 or delete the last one, I've added length checks in your click methods, see:
$('.addoutcome').live('click', function() {
if ($(".outcomegroup").length < 3) {
$('#template').clone().removeAttr('id').insertAfter($(this).closest('.outcomegroup')).find('.minus').show();
renumber();
}
});
$('.removeoutcome').live('click', function() {
if ($(".outcomegroup").length > 1) {
$(this).closest('.outcomegroup').remove();
renumber()
}
});
Also, on a side note, live is deprecated now, so if you're using jQuery 1.7, change these methods to on or if you're pre-1.7, use delegate.
You can just hide the del for first element and limit it to add only 3 more set using the following code
var count = 3;
$('.minus').first().hide();
$('.addoutcome').live('click', function() {
count--;
if(count < 0 )return;
$('#template').clone().removeAttr('id').insertAfter($(this).closest('.outcomegroup')).find('.minus').show();
});
here is the working fiddle http://jsfiddle.net/joycse06/uW9NQ/
Updated: http://jsfiddle.net/NzbRQ/5/
First off, ditch .live. I added the section to give a more specific selector than body, but there's probably something better that you can use in your original DOM.
Just don't remove the last row with some simple logic. Your logic for showing the future "del" link was actually already there! You don't even really need the last-row-removal logic at all since just not displaying "del" is enough, but I was just being thorough.
I don't know why anyone haven't paid close attention to this line:
.find('.minus').show();
where he definitely was un-hiding the del element. In short, the only thing you need to do is add the proper CSS rule:
.minus { display: none; }
and that's it, the first element won't show a del link and the others will.
The limit to three elements simply.
$("[parent element]").on('click', '.addoutcome', function() {
if($('.addoutcome').length > 2) return;
...
});
A better selector [parent selector] is needed and depends totally in your layout. Basically, it is the element that wraps all these elements, the parent element of all of them.