get values from adjacent table rows - javascript

i have a function to handle click of clickedcell. I want to exctract value of sibling cell with class "desired". how exactly to specify?
<tr>
<td class="desired">someValue</td>
<td><span "clickedcell"></span></td>
<td></td>
/tr>

$("span.clickedcell").click(function() {
var desired = $(this).closest(".desired").text();
...
});
or more simply:
$("span.clickedcell").click(function() {
var desired = $(this).parent().prev().text();
...
});
Also, the selector changes if you want to click anywhere in the cell:
$("td:has(span.clickedcell)").click(function() {
var desired = $(this).prev().text(); // OR
var desired2 = $(this).closest(".desired").text();
...
});
This can change depending on the nature of the relationship from clickedcell to desired. For example, the second example assumes desired is always the previous sibling. If there can be intervening siblings or it can be after then obviously the traversal needs to change to reflect that.

$(".clickedcell").click(function(){
$(this).closest("td").siblings(".desired").text();
});

Try YUI's DOM collection
YAHOO.util.Dom.getNextSibling(curTD);

Related

Is there way to parse tr returned by 'this'?

Each row of my table has a button at the end of the row, which has an addEventListener like this,
button.addEventListener ("click", function() {
deleteSummary(this);
});
function deleteSummary(oButton)
{
console.log(oButton.parentNode.parentNode.innerHTML)
}
the console.log shows like this,
<td>966</td><td>TypeA</td><td>1234</td><td>10,000</td><td>9,861</td><td>139</td><td>2021-01-02</td><td>3</td><td>7</td><td>8</td><td>7</td><td>89</td><td>9</td><td>8</td><td>7</td><td>1</td><td><button>delete</button></td>
But I have no idea how to parse(?) it.
I always found answers you use document.getElementById() when googling.
Thanks
You should not aim to parse HTML. You have access to the DOM, so stick with that. You already found the tr element successfully, and then you can for instance use its cells property to get access to all the td elements, and you could map that list of cells to their text content. That way you get a standard array with all the cell texts of that particular row.
let buttons = document.querySelectorAll("td>button");
for (let button of buttons) {
// Your code:
button.addEventListener ("click", function() {
deleteSummary(this);
});
}
function deleteSummary(oButton) {
let tr = oButton.parentNode.parentNode;
let data = Array.from(tr.cells, cell => cell.textContent);
data.pop(); // Optional: get rid of the column with the delete button
console.log(data);
}
<table>
<tr>
<td>966</td>
<td>TypeA</td>
<td>1234</td>
<td>10,000</td>
<td>2021-01-02</td>
<td><button>delete</button></td>
</tr>
<tr>
<td>123</td>
<td>TypeB</td>
<td>9988</td>
<td>29,999</td>
<td>2020-09-20</td>
<td><button>delete</button></td>
</tr>
</table>

Targeting Classes in Table Row

The code:
var table = document.getElementById('some-table');
var row = table.rows;
alert(row.length); // Returns number of rows
// Function to hide class on specific row when some action is performed
function someFunc(i) {
var elementToTarget = row[i].getElementsByClassName('some-class');
var otherElementToTarget = row[i].getElementsByClassName('some-other-class');
elementToTarget.style.display="none"; // Returns "elementToTarget.style
// is undefined"
otherElementToTarget.style.display="inline"; // Returns undefined
}
Basic table layout:
<table>
<tr>
<td>
<div class="some-class"></div>
<div class="some-other-class"></div>
</td>
</tr>
</table>
What I want to do: When a user triggers someFunc(), it hides some-class and displays some-other-class. But it only hides some-class for that particular row. Not all of the rows.
My Problem: It tells me that the elements in that row are undefined and I cannot perform any actions on them. It's very likely that I'm targetting those classes improperly.
Hopefully, I've been clear enough. If you need more clarification let me know.
Edit: There may not always be 'some-other-class' in the row. That's why I can't just target one of the divs. I need to know their row.
I'd refer you to the getElementsByClassName function's API. https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByName
Also, notice the name - Element*s*. It returns a list. And your function should treat it accordingly. so, e.g:
var elementToTarget = row[i].getElementsByClassName('some-class')[0];
var otherElementToTarget = row[i].getElementsByClassName('some-other-class')[0];
Check out this fiddle: http://jsfiddle.net/YD78S/

jQuery change all tr classes after specified one

I have a data table with alternating row background colors. I have an AJAX script to delete a row. I can't come up with a way to change the class of all the rows beneath the one that was deleted so that it alternates correctly again.
For example, considering the following:
`<tr id="1" class="row1">
<td>blah</td>
</tr>
<tr id="2" class="row2">
<td>blah</td>
</tr>
<tr id="3" class="row1">
<td>blah</td>
</tr>
<tr id="4" class="row2">
<td>blah</td>
</tr>`
Now, using my AJAX script, I remove id2, then id3 will move underneath id1 and they will have the same row color. I managed to make my script change the next tr class, but that doesn't really help because then it's just the same color as the one after that. I can't figure out how to iterate through all of the next tr's, and change their class accordingly.
What I have so far:
$('#news_' + id).fadeOut('slow');
var currtr = $('#news_' + id).attr('class');
var nexttr = $('#news_' + id).closest('tr').next('tr').attr('id');
$('#' + nexttr).removeClass($('#' + nexttr).attr('class'));
$('#' + nexttr).addClass(currtr);
You could just iterate over the visible<tr> elements, and remove the class from the even ones, and apply to the odd ones.
Something like this:
Example: http://jsfiddle.net/2CZdT/
$('tr:odd').addClass('odd');
$('td').click(function() {
$(this).parent().fadeOut(function() {
$(this).siblings('tr:visible').filter(':even').removeClass('odd')
.end().filter(':odd').addClass('odd');
});
});​
I have the click event on the <td>, so when one is clicked, it traverses up to the parent <tr> element, fades it out, the in the callback, it grabs all visible sibling <tr> elements, filters the even ones, removes the .odd class, then goes back and filters the odd ones, and adds the .odd class.
Note that this presumes there's a default class applied in your CSS, then you override the odd ones (or even ones) with the alternating class.
Easiest way is to go over the whole table again, e.g. add this after the fadeOut:
$('#id_of_your_table tr:even').addClass('even');
Edit: on second thought, that won't work since the row you faded still exists, but just isn't visible. You need to remove it from the DOM, or skip it when re-applying the zebra-effect. Example:
$('#news_' + id)
.fadeOut('slow')
.remove()
.closest('table')
.find('tr:even').addClass('even');
Or:
$('#news_' + id)
.fadeOut('slow')
.addClass('skip')
.closest('table')
.find('tr:not(.skip):even').addClass('even');
You can also target the table directly as in the first example, but you might as well move up from the faded row to the table its in.
You could use the next siblings selector to get all the rows following the one you are going to delete. Delete the desired row. Then, you should already have the following siblings, so just .each() them and change their class.
E.g.
var followingRows = $("#id2 ~ tr");
$("#id2").remove();
followingRows.each(function() {
if (this.is('.even')
this.removeClass('even').addClass('odd');
else
this.removeClass('odd').addClass('even');
});
Something close to that...
Let CSS do the work for you.
table tr:nth-child(2n+1) {
background-color: #eef;
}
no JavaScript required! =)
I would do something like this:
$('news_' + id).fadeOut('slow', function() {
$(this).remove();
});
var i = 1;
$('tr').removeClass().each(function() {
if (i == 1) {
$(this).addClass('row' + i);
i++;
} else {
$(this).addClass('row' + i);
i--;
}
});

How to do this in jQuery?

I have to attach the method copyToLeft on onClick event of all images which are inside the TD. TD is inside the table named mismatchList, so that the structure becomes like this mismatchList > tbody > tr > td > img
Although i have already done this, but that is using plain javascript. What i did was, i manually added copyToLeft(this); method on onClick event of all specified elements at the time of creation. [ This is the step which i want to omit and use jQuery to do this somehow ].
Also definition of copyToLeft goes like this:-
function copyToLeft(obj){
leftObj = getLeftTD (obj); // my method which returns the adjacent Left TD
rightObj = getRightTD (obj);
if ( leftObj.innerHTML != rightObj.innerHTML ) {
leftObj.innerHTML = rightObj.innerHTML;
leftObj.bgColor = '#1DD50F';
}else{
alert ( 'Both values are same' );
}
}
If required copyToLeft method's definition can also be changed. [ just in case you think, jQuery can be used to make this method better :) ]
Edit
Instead of asking another question i am just adding the new requirement :) [ let me know if i am supposed to create new one ]
i have to add copyToLeft method to all images as i specified, but alongwith that image src should be left_arrow.gif, and add copyToRight method if src is right_arrow.gif. Also, how can we get the adjacent left/right TD in jQuery, as i want to replpace my getLeftTD and getRightTD method as well?
If i've understood your question correctly, in jQuery, you'd bind the event as such:
$(document).ready(function() {
$('mismatchList > tbody > tr > td > img').click(copyToLeft);
});
In your copyToLeft function, you don't accept obj as an input parameter, instead this will be the image. $(this) will be a jQuery object, containing the image, should you require it...
You could do something like this to match the image src.
$('#mismatchList > tbody > tr > td > img[src='left_arrow.gif']').click(copyToLeft);
$('#mismatchList > tbody > tr > td > img[src='right_arrow.gif']').click(copyToRight);
It is worth noting that the part matching the image src does use the entire contents of src, so if you move the images to a different directory it will stop working. If you just want to match the end of source you can use $= instead of just =.
Here's a variation on TheVillageIdiots rewrite of your copy left function.
function copyToLeft() {
var cell = $(this).closest('td');
var leftObj = cell.prev();
var rightObj = cell.next();
if ( leftObj.html() != rightObj.html()) {
leftObj.html(rightObj.html());
leftObj.css('background-color','#1DD50F');
} else {
alert ( 'Both values are same' );
}
}
Part of me also thinks it would make sense to just have one copyToSibling function where you check $(this).attr('src') for whether it's left_arrow.gif or right_arrow.gif and act accordingly, rather than the two selectors I posted before.
try this code:
<table id="tbl">
<tbody>
<tr>
<td></td><td><img src="file:///...\delete.png" /></td>
</tr>
<tr>
<td></td><td><img src="file:///...\ok.png" /></td>
</tr>
</tbody>
</table>
<script type="text/javascript">
$(document).ready(function(){
$("table#tbl img").click(function(){
var td=$(this).parents("td");
var tr=$(td).parents("tr");
var left=$(td).prev("td");
$(left).html($(td).html());
});
});
</script>

jQuery to find all previous elements that match an expression

Using jQuery, how do you match elements that are prior to the current element in the DOM tree? Using prevAll() only matches previous siblings.
eg:
<table>
<tr>
<td class="findme">find this one</td>
</tr>
<tr>
<td>find the previous .findme</td>
</tr>
<tr>
<td class="findme">don't find this one</td>
</tr>
</table>
In my specific case, I'll be searching for the first .findme element prior to the link clicked.
Ok, here's what I've come up with - hopefully it'll be useful in many different situations. It's 2 extensions to jQuery that I call prevALL and nextALL. While the standard prevAll() matches previous siblings, prevALL() matches ALL previous elements all the way up the DOM tree, similarly for nextAll() and nextALL().
I'll try to explain it in the comments below:
// this is a small helper extension i stole from
// http://www.texotela.co.uk/code/jquery/reverse/
// it merely reverses the order of a jQuery set.
$.fn.reverse = function() {
return this.pushStack(this.get().reverse(), arguments);
};
// create two new functions: prevALL and nextALL. they're very similar, hence this style.
$.each( ['prev', 'next'], function(unusedIndex, name) {
$.fn[ name + 'ALL' ] = function(matchExpr) {
// get all the elements in the body, including the body.
var $all = $('body').find('*').andSelf();
// slice the $all object according to which way we're looking
$all = (name == 'prev')
? $all.slice(0, $all.index(this)).reverse()
: $all.slice($all.index(this) + 1)
;
// filter the matches if specified
if (matchExpr) $all = $all.filter(matchExpr);
return $all;
};
});
usage:
$('.myLinks').click(function() {
$(this)
.prevALL('.findme:first')
.html("You found me!")
;
// set previous nodes to blue
$(this).prevALL().css('backgroundColor', 'blue');
// set following nodes to red
$(this).nextALL().css('backgroundColor', 'red');
});
edit - function rewritten from scratch. I just thought of a much quicker and simpler way to do it. Take a look at the edit history to see my first iteration.
edit again - found an easier way to do it!
Presumably you are doing this inside an onclick handler so you have access to the element that was clicked. What I would do is do a prevAll to see if it is at the same level. If not, then I would do a parent().prevAll() to get the previous siblings of the parent element, then iterate through those backwards, checking their contents for the desired element. Continue going up the DOM tree until you find what you want or hit the root of the DOM. This a general algorithm.
If you know that it is inside a table, then you can simply get the row containing the element clicked and iterate backwards through the rows of the table from that row until you find one that contains the element desired.
I don't think there is a way to do it in one (chained) statement.
edit: this solution works for both your original problem, the problem you mention in your first comment, and the problem you detail in the comment after that.
$('.myLinks').click(function() {
var findMe = '';
$(this).parents().each(function() {
var a = $(this).find('.findme').is('.findme');
var b = $(this).find('.myLinks').is('.myLinks');
if (a && b) { // look for first parent that
// contains .findme and .myLinks
$(this).find('*').each(function() {
var name = $(this).attr('class');
if ( name == 'findme') {
findMe = $(this); // set element to last matching
// .findme
}
if ( name == 'myLinks') {
return false; // exit from the mess once we find
// .myLinks
}
});
return false;
}
});
alert(findMe.text() ); // alerts "find this one"
});
this works for your example in the OP as well as a modified example as explained in the comments:
<table>
<tr>
<td class="findme">don't find this one</td>
</tr>
<tr>
<td class="findme">find this one</td>
</tr>
<tr>
<td>find the previous .findme</td>
</tr>
<tr>
<td class="findme">don't find this one</td>
</tr>
</table>
as well as this test case which you added:
<table>
<tr>
<td class="findme">don't find this one</td>
</tr>
<tr>
<td class="findme">don't find this one</td>
</tr>
<tr>
<td class="findme">find this one</td>
</tr>
</table>
find the previous .findme
I usually number elements (1,2,3..) (rel="number"), so then i use this code to give class to all previous elements:
var num = $(this).attr("rel");
for (var i = 1; i<=num; i++)
{
$('.class[rel="'+i+'"]').addClass("newclass");
}
had the same problem, heres what i came up with. my function uses compareDocumentPosition. dont know how it compares to the other solutions in terms of performance though.
$.fn.findNext = function ( selector ) {
var found, self = this.get(0);
$( selector )
.each( function () {
if ( self.compareDocumentPosition( this ) === 4 ){
found = this;
return false;
}
})
return $(found);
}
of course one could change this quite easily to fetch ALL elements following the calling element.
$.fn.nextALL= function ( selector ) {
var found = [], self = this.get(0);
$( selector )
.each( function () {
if ( self.compareDocumentPosition( this ) === 4 )
found.push(this);
})
return $(found);
}
EDIT: streamlined version
$.fn.findNext = function( s ){
var m = this[0], f=function(n){return m.compareDocumentPosition(n)===4;};
return this.pushStack( $(s).get().filter(f) );
}

Categories

Resources