jQuery - check if selected row is last visible row in table - javascript

previously i checked whether a row is last row in a table like this in a condition:
$row.is(':last-child')
which works fine.
Now, i have a requirement where some of the rows in the table are hidden - now i have to check whether a specific row is the last visible row in the table.
I tried with this:
$row.is(':visible:last-child')
but not that successfull. Does someone have a clue?

This doesn't work because the last-child is display: none;.
One approach is to iterate the childs to find the index of the last visible child (see fiddle) :
var $rows = $('td');
var $rowsReverse = $($rows.get().reverse());
var $lastVisibleIndex = -1;
$rowsReverse.each(function(index) {
if ($lastVisibleIndex == -1 && $(this).is(':visible')) {
$lastVisibleIndex = $rowsReverse.length - index - 1;
}
});
$rows.each(function(index) {
var $row = $(this);
if (index == $lastVisibleIndex) {
$row.addClass('red');
}
});​

Thanx everybody for the quick feedback. I could solve it with the following:
$row.parent().find('tr:visible').last().attr('data-id') is $row.attr('data-id')
(it's in a loop)
#falsarella your answer i guess works fine - is a bit complicated, but it works apparently.

You could try
$(element).is(":visible").last();
or
$(element:visible).last();
If that doesn't work, let me know.

Related

Append div inside of td and set the value?

I have multiple tables that I need to populate. I use jQuery to loop through table cells. If table cell has data-text attribute I need to append div element. Div element will allow cell to have scroll bar vertical. This way table won't expend if text is too long.
Here is example of my code:
$('#'+tabID+' table tr td').each(function(){
elementID = $(this).prop('id').toUpperCase();
value = $.trim(decodeURIComponent(obj.DATA[elementID]['value']));
if($(this).attr('data-text')) {
$(this).append('<div class="hm_textScroll">'+value+'</div>');
} else {
$(this).text(value).css({'color':'blue','font-weight':'bold'});
}
});
Code above will append div element and set the value but the problem is that if I move to a different table and come back again one more div will append. That creates duplicate. I'm not sure what is the best way to prevent that? Or if there is a better way to work around this. If anyone have suggestions please let me know.
Thanks in advance.
Here you go with a solution
$('#' + tabID + ' table tr').each(function(){
$(this).find('td').each(function(){
elementID = $(this).prop('id').toUpperCase();
value = $.trim(decodeURIComponent(obj.DATA[elementID]['value']));
if(typeof $(this).attr('data-text') != 'undefined') {
if($(this).find('div.hm_textScroll').length > 0){
$(this).find('div.hm_textScroll').text(value);
} else {
$(this).append(`<div class="hm_textScroll">${value}</div>`);
}
} else {
$(this).text(value).css({'color':'blue','font-weight':'bold'});
}
});
});
First loop through each tr then loop through each td.
For check the data-attribute, use typeof $(this).attr('data-text') != 'undefined
In the if statement (true condition) I've used backtick ES6 for appending div container.
Hope this will help you.
If I understand you correctly, you would have to additionally check whether a <div class="hm_textScroll"></div> already exists in the <td>.
One possible solution using vanilla javascript would be this:
const tableElement = document.querySelectorAll('#'+tabID+'table tr td');
tableElement.forEach(td => {
if (td.hasAttribute("data-text")) {
if (!td.querySelector(".hm_textScroll")) {
td.innerHTML='<divclass="hm_textScroll">'+value+'</div>'
}
}
});

change rows depending on the ordernumber in database

I'm creating for my education-project a pizza-ordering website. With the help of the stackoverflow-community I've achieved already a lot - so thank you! But now I'm stuck and can't find any working solution to my problem.
Question
How can I change the row color alternating (white / grey / white / grey ...) depending on the ordernumber in the database(mysqli)? The ordernumber can be in more than one row, so I can not simple change the color row by row.
I've tried with jquery, but this works only if the ordering numbers remain always in the list (even/odd) ... if an order is cancelled, then it doesn't works anymore (see image with missing ordernumber 7)
Here is the code in jquery:
$(document).ready(function() {
var check = 0;
for(var i =0; i<= $("tr").length;i++){
$("tr").each(function(){
if(parseInt($(this).find("#bestnr").text())==check){
if(check%2 == 0){
$(this).css("background-color","white");
}else{
$(this).css("background-color","#DCDCDC");
}
}
});
check +=1;
}
});
Any ideas? Thanks for your help!
Since you're working with JQuery, something like this ought to do the trick - explanations in code comments.
$(document).ready(function() {
// define the initial "previous order id" as 0 assuming
// there will never be an order with id 0
var previousOrderId = 0;
var previousBgColour = '#dcdcdc';
var thisBgColour;
// loop the table rows
$("tr").each(function() {
// determine "this" row id (assuming bestnr is short for bestelnummer)
// and that the text in that table cell *is* the order number
// I've changed this to a class as an id HAS to be unique
// you'll need to update your code to accommodate
var thisOrderId = parseInt($(this).find(".bestnr").text());
// define the background colour based on whether the order id has changed
// if it has change it
if(thisOrderId != previousOrderId) {
thisBgColour = previousBgColour == '#dcdcdc' ? '#ffffff' : '#dcdcdc';
previousBgColour = thisBgColour;
}
else {
thisBgColour = previousBgColour;
}
$(this).css({'background-color' : thisBgColour});
//update the previousOrderId to this id
previousOrderId = thisOrderId;
});
});
You're basically storing the previous order id and comparing it to the current order id - if the order id hasn't changed it'll use the previous background colour, if it has it'll flipflop it to the alternate colour.
If it is just alternating colors, you can use CSS directly and not worry about anything else:
tr:nth-child(odd) {
background-color:white;
}
tr:nth-child(even) {
background-color:#DCDCDC;
}
If this is somehow dependent on logic from the backend, we can look at adding a class in jQuery and adding colors to this class via CSS

Wrap every child divisible by 5 and previous 4 in a div

I've been working on this JSFiddle to practice my understanding of jquery, but now I'm stuck.
How do you wrap a child element in a div to follow this pattern: child elements 1-5, then child elements 6-10, then child elements 11-15, and so on?
I'm working on a tally counter, so I want every 5 tallies to cluster together. That way, I can more easily select the last child and apply a class to make it rotate, in order to "cross out" the previous 4 tallies.
edit: (To clarify: I've been looking into selecting by index and by nth-child/nth-of-type, but those methods can only really grab the fifth element, or maybe even multiples of five? It doesn't grab the previous divs, too.)
edit 2: (So, you can actually use those selectors! I figured I was getting something wrong. It's always something simple.)
$(".button").click(function() {
var $button = $(this);
var oldValue = $button.parent().find("input").val();
if ($button.text() == "+") {
var newVal = parseFloat(oldValue) + 1;
} else {
// Don't allow decrementing below zero
if (oldValue > 0) {
var newVal = parseFloat(oldValue) - 1;
} else {
newVal = 0;
}
}
$("#counternumber").val(newVal);
});
$("#plus").click(function() {
var tally = "<div class='tally'>I</div>";
$("#dummy").append(tally)
});
$(function(){
$('#scratchpad.tally:nth-of-type(5)').wrap('tallyfamily');
});
JSFiddle.
Here is a general solution to wrap elements in groups of 5:
$(".holder > div:nth-child(5n-4)")
.addClass("first-of-group")
.each(function(){
$(this).nextUntil(".first-of-group")
.addBack()
.wrapAll("<div class='wrapper'>");
})
.removeClass("first-of-group");
http://jsfiddle.net/nJJM8/1/
Basically, :nth-child(5n-4) gets the first element in each group of 5. Then a class is temporarily added to keep track of these. nextUntil is used to find all elements up until the next element with that class. And finally wrapAll is used to wrap the matched elements in a div.
EDIT: Even easier:
var $divs = $(".holder > div");
for (var i = 0; i < $divs.length; i += 5) {
$divs.slice(i, i + 5).wrapAll("<div class='wrapper'>");
}
http://jsfiddle.net/kMzeN/1/
You're almost there, but a couple of things to note. You will only call your "wrap" function once, as it's outside of the click event. If you are dynamically adding, then you'll want to call it each time.
Secondly, with the HTML in your fiddle, you will never get the 5th record because you are appending your selector is looking for the 5th element with ID "scratchpad" with the class of tally. You'd need to change your selector to something that looks for all tallies, like so:
$(".tally:nth-of-type(5)").css('color', 'red');
I've updated the fiddle you were working on, and my code highlights each 5th record, so you can see what's going on. You were close, but you'll also want to add to your "nth-of-type" selector the use of "n", this way it gets every 5th record, not just the 5th one. So the full function becomes this
$("#plus").click(function() {
var tally = "<div class='tally'>I</div>";
$("#dummy").append(tally);
$(".tally:nth-of-type(5n)").css('color', 'red');
});
Fiddle: http://jsfiddle.net/Hfz9L/16/
To rotate (or apply any other property) to each 5th element, you don't even need to wrap them. Just specify a css class using the nth-of-type(5n) and it will affect every 5th element.
#scratchpad .tally:nth-of-type(5n) {
display: inline-block;
transform:rotate(20deg);
-ms-transform:rotate(20deg); /* IE 9 */
-webkit-transform:rotate(20deg); /* Opera, Chrome, and Safari */
}
Here is your fiddle updated: http://jsfiddle.net/Hfz9L/20/
Check this Working Demo Fiddle
$("#plus").click(function() {
var tally = "<div class='tally'>I</div>";
$("#dummy").append(tally);
$('#scratchpad .tally:nth-of-type(5n+1)').prevUntil('span').wrapAll('<span style="margin-right:5px;color:red;text-decoration:line-through;"></span>');
});
$('#scratchpad .tally:nth-of-type(5n+1)').prevUntil('span').wrapAll('<span style="margin-right:5px;color:red;text-decoration:line-through;"></span>');
Some changes:
$('#scratchpad .tally:nth-of-type(5n+1)') and not $('#scratchpad.tally:nth-of-type(5)'). - .tally is the child of #scratchpad ; selector to be used :nth-of-type(5n+1)
Use .wrapAll() - to wrap the selected elements in a <span> or any other element.
.prevUntil() - get all the previous elements.
You can make a for loop and do this:
for(i=1;i<=noOfChildElements/5;i++)
{
$('.child:nth-child('+i+'), .child:nth-child('+(i+1)+'), .child:nth-child('+(i+2)+'), .child:nth-child('+(i+3)+'), .child:nth-child('+(i+4)+')').wrapAll("<div />");
}
Basically I'm going through the child elements in the for loop and at every turn of the loop I'm selecting the 5 next child elements and wrapping them in a div using the .wrapAll() function. Hope this helps.

performing sortable using JavaScript

i have a situation where i need to achieve this, in a table having n rows. if i click on a row in a table and then click on another row. the content in row of first click should go to content in row of second click and then each row should be shifted by on step backward or forward. this can be taken equivalent to JQUERY sortable.
Example:
|1|2|3|4| if i click on 1 and 4 then it should be |2|3|4|1|
how to record two clicks, and the contents of my rows are div elements containing many input elements. I thought of this idea and is this a good way to achieve sortable or is there a still better way, i want to do it using java script.
thanks in advance.
my script fucntion goes like this. I really should have thought for a little longer. i used flags here, i got two questions more, can i do that with out flags?, is there a better way?
<script>
var flag=0;
var id1;
var id2;
function Myfunction(id)
{
if(flag==0)
{
id1=id;
flag=1;
}
else
{
id2=id;
var x=document.getElementById(id1).innerHTML;
var num1=parseInt(id1);
var num2=parseInt(id2);
for(var i=num1;i<num2;i++)
{
var j=i.toString();
var k=(i+1).toString();
document.getElementById(j).innerHTML=document.getElementById(k).innerHTML;
}
document.getElementById(id2).innerHTML=x;
flag=0;
}
}
</script>
I made up a little http://jsfiddle.net/zxKeg/. Works with jQuery only, no additional plugins needed. Hope this will help you!
JS Code:
$(document).ready(function() {
var $table = $('table');
var $toCopy = null;
$table.on('click', 'tr', function() {
if($toCopy === null || $toCopy[0] == this) {
$toCopy = $(this);
}
else {
$toCopy.remove();
$(this).after($toCopy);
$toCopy = null;
}
});
});

JQuery: nextUntil() - weird problem

I'm building a page that features a hierarchical tree-type structure. I've posted a simplified version of it at JSFiddle
It mostly works as I'd like but for one thing - on clicking closed a Brand-level row I would like, as well as the town and shoe rows to contract (which they do), for the anchors on the Town rows to change their text to '+'.
I've attempted to do so with
$(this).parent().parent().nextUntil(".TRBrand", ".TownToggle").text("+");
but try as I might it won't play nicely.
Can anyone point me in the right direction ...?
Nested lists are better for tree like structures. You can see the js is easier to write with this markup:
http://jsfiddle.net/RANmK/1/
There were several problems with your version:
The last <a> (for Reebok) had the wrong class : TRTown instead of TownToggle
Your nextUntil(...) for TownToggle was only stopping when it sees .TRTown, which means it hides too much when it is the last Town in the list and continues to hide the next brand as well. It should also stop on .TRBrasnd. You can specify both selectors by seperating them with a comma.
a.toggleTown was not targetted correctly when updating the text value to +
If I understand your requirements correctly, the following should do what you want: http://jsfiddle.net/Sx4qg/69/
$('.BrandToggle').click(function() {
var t = $(this);
var txt = t.text();
var tr = t.closest("tr");
if (txt == "+") {
tr.nextUntil(".TRBrand", ".TRTown").show();
} else {
tr.nextUntil(".TRBrand", ".TRTown, .TRShoes").hide();
tr.nextUntil(".TRBrand", ".TRTown").find("a.TownToggle").text("+");
}
t.text(txt == "+" ? "-" : "+");
});
$(".TownToggle").click(function() {
var t = $(this);
var txt = t.text();
var tr = t.closest("tr");
if (txt == "+") {
tr.nextUntil(".TRBrand,.TRTown", ".TRShoes").show();
} else {
tr.nextUntil(".TRBrand,.TRTown", ".TRShoes").hide();
}
t.text(txt == "+" ? "-" : "+");
});
Try this:
$(this).parent().parent().nextUntil(".TRBrand").find('.TownToggle').text("+");
http://jsfiddle.net/sangdol/Sx4qg/64/
Hope this fiddle will help
$(this).parent().parent().nextUntil("tr:not(.TRTown, .TRBrand)", ".TownToggle").text("+");

Categories

Resources