Getting the 'co-ordinates' of a <TD> cell using jQuery - javascript

I'm building somewhat of a different website, below is my HTML markup and my question. Please don't be put off by this wall of text, I'm sure it's really not a difficult problem for someone who know's their stuff but it takes some explaining.
<div id="0" class="cell" style="top: 0px; left: 0px;">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr id="0">
<td id="0"> </td>
<td id="1"> </td>
<td id="2"> </td>
<td id="3"> </td>
<td id="4"> </td>
<td id="5"> </td>
<td id="6"> </td>
<td id="7"> </td>
<td id="8"> </td>
<td id="9"> </td>
<td id="10"> </td>
<td id="11"> </td>
<td id="12"> </td>
<td id="13"> </td>
<td id="14"> </td>
<td id="15"> </td>
</tr>
<tr id="1">
<td id="0"> </td>
<td id="1"> </td>
<td id="2"> </td>
<td id="3"> </td>
<td id="4"> </td>
<td id="5"> </td>
<td id="6"> </td>
<td id="7"> </td>
<td id="8"> </td>
<td id="9"> </td>
<td id="10"> </td>
<td id="11"> </td>
<td id="12"> </td>
<td id="13"> </td>
<td id="14"> </td>
<td id="15"> </td>
</tr>
</tbody>
</table>
</div>
This markup is repeated in a tiling sort of pastern in order to fill the entire page. A similar DIV might be:
<div id="1" class="cell" style="top: 144px; left: 0px;">
<!-- The rest of the table code here... -->
</div>
If you can't see it already, I'm creating a load of cells across the entire page sorted into DIVs. Now, when a user clicks into a cell (one of the <td>'s), I want to get it's co-ordinates represented by: 0, 1, 5.
In this example, 0, 1, 5 is the DIV with id of 0, the TR element inside that DIV with the ID of 1, and lastly the cell inside that TR element with an ID of 5. I wanted to write a javascript function to get these co-ordinates, but I am at a complete loss on what parameters to pass, and little idea how I can get out the co-ordinates.
From as far as I can think once I can pass a click event(?) to the function I can look at the <td>'s parent elements and get their IDs?
If anyone can provide a solution to this problem or provide any input, it'd be greatly appreciated.

Since it is not valid to begin an ID with a number, I'll offer a different solution.
Since your IDs are basically index numbers, you can use jQuery's .index() method to get what you need.
Test it here: http://jsfiddle.net/hBarW/
$('td').click(function(){
var $th = $(this);
var td_idx = $th.index();
var tr_idx = $th.closest('tr').index();
var div_idx = $(this).closest('div').index();
alert(td_idx + ' ' + tr_idx + ' ' + div_idx);
});

Use the closest jQuery function, which returns the parent element that you specify.
Like this:
$("td").click(function () {
var parentDIVId = $(this).closest("div").attr("id");
var parentTRId = $(this).closest("tr").attr("id");
var myId = $(this).attr("id");
}

try
$('td').click(function(){
var td = this.id;
var tr = $(this).closest('tr').attr('id');
var div = $(this).closest('div').attr('id');
});
you can test it here.
more on .closest() here

the easy thing would be
$('td').click(function(){
$this = $(this);
alert( $this.closest('div').attr('id') + ',' + $this.closest('tr').attr('id') + ',' + $this.attr('id'));
});
But you have some issues..
you cannot have numbers as IDs
IDs should be unique inside the DOM ...

Related

Get tr element with document.querySelector

I trying to get a tr element using the document.querySelector sentence, but I get :
TypeError: tempNode.querySelector(...) is null
My selector in Javascript is: document.querySelector("#row-model")
This is working with other element (with a div to be exact) but with it, I tried others selectors (using the datatype, the tr, etc, but always I get the same error)...Then in the browser console I checked the existence of the element, the HTML of the element is as follows:
<table>
<tbody>
<tr class="" id="row-model" data-id="myid" data-type="rowtemplate">
<td class="category">
</td>
<td class="title showTipTip">
<a data-cats="" href="#profile" id="title" aria-controls="profile" role="tab" data-toggle="tab" title="" data-id="" class="spotlink" address="true"></a>
</td>
<td class="comments">
<a class="spotlink" href="#comments" title="" id="commentValue"> commentValue
</a>
</td>
<td class="genre">
catdesc
</td>
<td class="poster">
poster
</td>
<td class="date" id="since"></td>
<td class="filesize" id="filesize">
</td>
<td class="nzb">
NZB
</td>
<td class="multinzb">
<input onclick="multinzb()" name="messageid[]" value="" type="checkbox">
</td>
</tr>
</tbody>
</table>
EDITED:
The JS code inside the function is:
$('#catalog').each(function(){
var tempNode = document.querySelector("#row-model").cloneNode(true); //I clone the element and then append it to another table
tempNode.querySelector("a #category").textContent = "test";
$('#spotsTable tr:last').after(tempNode);
});
Also, I have the table inside a div with hidden class (bootstrap), maybe it can affect it?

Scroll to element in modal div

I'm using JQuery load() to place a page into a modal div set to overflow-y:auto; At the top of the loaded page inside the modal div, I want to click on an element (actually a table cell...) that will scroll the page down to a specific div:
<div id='haematopoietic_section' class='cap_h2'>Haematopoietic</div>
The code in the loaded page contains:
$('#haematopoietic').click(function(){
$(document).scrollTop($('#haematopoietic_section').offset().top);
});
The above code isn't doing anything. I can throw an alert in the click event, but it won't scroll. Any ideas?
See example at https://jsfiddle.net/z7m4c38d/3/ Note that this fiddle does not use JQuery load, but instead has code fixed inside the div...problem remains...
use the below code, in your click event
var container = $('body'),
scrollTo = $('#haematopoietic_section');
container.scrollTop(
scrollTo.offset().top - container.offset().top + container.scrollTop()
);
Since the div is contained in <div id = 'cap_module_holder'> .... </div>
so your container variable should be:
var container = $('#cap_module_holder');
i have added an extra div in middle to increase height so that you can see the scroll effect.
<div id='module_container'>
<div id='cap_module_holder'>
<p class='cap_h1'>Bone Tumours</p>
<p>Introduction</p>
<p>
<br>In the first three decades of life, benign tumours are the most frequent. In the elderly, a bone tumour is likely to be malignant, either primary or a metastasis.</p>
<p class='cap_h2'>Primary tumours involving bone</p>
<p>These are all derived from tissue of mesodermal origin.</p>
<table width="auto" border="0" align="center" cellspacing="3">
<tr>
<td width="208" valign="top">
<p align="center"><strong>Histological classification</strong>
</p>
</td>
<td width="208" valign="top">
<p align="center"><strong>Benign</strong>
</p>
</td>
<td width="208" valign="top">
<p align="center"><strong>Malignant</strong>
</p>
</td>
</tr>
<tr>
<td id='haematopoietic' class='cap_t2' width="208" valign="top">
<p>Haematopoietic</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Haemangioma</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Myeloma
<br>Malignant  lymphoma</p>
</td>
</tr>
<tr>
<td class='cap_t2' width="208" valign="top">
<p>Chondrogenic</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Osteochondroma
<br>Chondroma
<br>Chondromyxoid fibroma</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Chondrosarcoma
<br>Dedifferentiated -Chondroblastoma</p>
</td>
</tr>
<tr>
<td class='cap_t2' width="208" valign="top">
<p>Osteogenic</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p> Osteoma                           Osteoid osteoma
<br>Osteoblastoma</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Osteosarcoma</p>
</td>
</tr>
<tr>
<td class='cap_t2' width="208" valign="top">
<p>Fibrogenic</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Fibrous cortical defect
<br>Non-ossifying fibroma</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Fibrosarcoma</p>
</td>
</tr>
<tr>
<td class='cap_t2' width="208" valign="top">
<p>Neuroectodermal</p>
</td>
<td width="208" valign="top">
<p> </p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Ewing’s sarcoma</p>
</td>
</tr>
<tr>
<td class='cap_t2' width="208" valign="top">
<p>Notochordial</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Benign notochordal cell tumour      </p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Chordoma</p>
</td>
</tr>
<tr>
<td class='cap_t2' width="208" valign="top">
<p>Odontogenic</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Giant cell tumour</p>
</td>
<td class='cap_t3' width="208" valign="top">
<p>Ameloblastoma
<br>
</p>
</td>
</tr>
<tr>
<td class='cap_t2' valign="top">Unknown origin</td>
<td class='cap_t3' valign="top">Unicameral cyst
<br>Aneurysmal bone cyst</td>
<td valign="top"> </td>
</tr>
</table>
<div style = "height:500px;" >ok </div>
<div id='haematopoietic_section' class='cap_h2'>Haematopoietic</div>
</div>
</div>
A more recent solution using only JavaScript:
var element = document.getElementById("scroll-here")
element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })
See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Late to the party here, but I am posting this in the hopes that it helps someone else who is beating their heads against the wall about scrolling inside modals.
In my case I had multiple modals that could be opened (but just one at a time), and within each modal was a form that needed to be validated on submission. I wanted it to scroll to the first invalid form input on submission.
The key thing here is that you want to scroll the contents inside the modal, not the page behind the modal, nor the position of the modal itself against the background page. So to do this you need to do the following:
1) Structure your modals correctly. Put an id into the div that has the class='modal fade' and then make sure the 'modal-body' has its own id, in this case 'newExpenseForm18'. (note I use a 'key' attribute to tell me which modal is open).
<div class="modal fade uploadExpense in" key="18" id="uploadExpense18" role="dialog" >
<div class="modal-dialog text-left">
<div class="modal-content" id="modalcontent18">
<div class="modal-header">
</div>
<div class="modal-body" id="newExpenseForm18">
..... etc followed by (at some point)
<div id = 'myExpense18'>
..... etc
2) Now you need to get three ids: the whole modal ( in this case "uploadExpense18"), the container div ( in this case "theform18"), and the target div to which you want to scroll, in this case "myExpense18". You can get these thus:
var modalId = $('.modal:visible').attr('id');
var key = $('.modal:visible').attr('key');
var bodyId = 'newExpenseForm'+key;
var targetId = 'myExpense'+key;
3) Now you find out the distance you need to scroll. To do this, find the offset of the target div, relative to the top of the page, and also the offset of the modal-body, relative to the top of the page
var position = $('#'+targetId).offset().top;
var position2 = $('#'+bodyId).offset().top;
4) subtract one from the other to get the offset of the target relative to the container div.
var distance = position-position2;
5) and, finally, scroll the body of the modal inside the modal div, so that the target is now at the place where the top of the container used to be:
$('#'+modalId).animate({ scrollTop: distance }, "slow");
Hope that helps someone!

How to back to a root HTML tag with jQuery or Javascript

I would like to use the td.ms-vb-title in order to get the text 2,004, 2,005, 2,006 in the class ms-vb2 attribute.
I tried to use prev() but it didn't work...
HTML:
<tbody>
<tr iid="92,1,0" class="ms-itmhover" setedgeborder="true">
<td class="ms-vb-itmcbx ms-vb-firstCell">
<input type="checkbox" class="s4-itm-cbx"></td>
<td class="ms-vb2"></td>
<td height="100%" class="ms-vb-title" onmouseover="OnChildItem(this)" id="msomenuid2"></td>
<td class="ms-vb2">
<div align="right">2,004</div>
</td>
<td class="ms-vb2">
<div align="right">1,000</div>
</td>
<td class="ms-vb2">
<div align="right">400</div>
</td>
<td class="ms-vb2 ms-vb-lastCell">
<div align="right">600</div>
</td>
</tr>
<tr iid="92,2,0" class="ms-alternating ms-itmhover" setedgeborder="true">
<td class="ms-vb-itmcbx ms-vb-firstCell">
<input type="checkbox" class="s4-itm-cbx"></td>
<td class="ms-vb2"></td>
<td height="100%" class="ms-vb-title" onmouseover="OnChildItem(this)"></td>
<td class="ms-vb2">
<div align="right">2,005</div>
</td>
<td class="ms-vb2">
<div align="right">1,170</div>
</td>
<td class="ms-vb2">
<div align="right">460</div>
</td>
<td class="ms-vb2 ms-vb-lastCell">
<div align="right">1,200</div>
</td>
</tr>
<tr iid="92,3,0" class="ms-itmhover" setedgeborder="true">
<td class="ms-vb-itmcbx ms-vb-firstCell">
<input type="checkbox" class="s4-itm-cbx"></td>
<td class="ms-vb2"></td>
<td height="100%" class="ms-vb-title" onmouseover="OnChildItem(this)"></td>
<td class="ms-vb2">
<div align="right">2,006</div>
</td>
<td class="ms-vb2">
<div align="right">660</div>
</td>
<td class="ms-vb2">
<div align="right">1,120</div>
</td>
<td class="ms-vb2 ms-vb-lastCell">
<div align="right">780</div>
</td>
</tr>
</tbody>
Javascript:
var arrayList = $("td.ms-vb-title:contains('')");
var a = $(arrayList).prev().eq(0).find("ms-vb2");
alert(arrayList.length);
alert(a.length);
$.each(arrayList, function (i, e) {
areaname[i] = $(e).text();
});
You should use .closest()
For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree
Change your code to
var a = $(arrayList).closest('tr').find(".ms-vb2");

Using checkboxes to update a total row based on images

I am working on code which updates a total row based on when a checkbox is checked based on whether or not an image in that row is the correct image.
Here is the HTML:
<table border="1">
<tr> <!-- Table Header -->
<td>
Checkbox
</td>
<td>
Items
</td>
<td>
Area 1
</td>
<td>
Area 2
</td>
<td>
Area 3
</td>
</tr>
<tr id="checkRow"> <!-- Row 1 -->
<td>
<form>
<input type="checkbox" name="Row1" value="Row1" onchange="onCheck(this);">
</form>
</td>
<td>
Item 1
</td>
<td class="imageBox">
<img id="image1" src="yes.png" alt="Needed">
</td>
<td class="imageBox">
<img id="image2" src="yes.png" alt="Needed">
</td>
<td class="imageBox">
<img id="image3" src="no.png" alt="Needed">
</td>
</tr>
<tr> <!-- Row 2 -->
<td>
<form>
<input type="checkbox" name="Row2" value="Row2" onchange="onCheck(this);">
</form>
</td>
<td>
Item 2
</td>
<td class="imageBox">
<img src="yes.png" alt="Needed">
</td>
<td class="imageBox">
<img src="yes.png" alt="Needed">
</td>
<td class="imageBox">
<img src="no.png" alt="Needed">
</td>
</tr>
<tr> <!-- Row 3 -->
<td>
<form>
<input type="checkbox" name="Row3" value="Row3" onchange="onCheck(this);">
</form>
</td>
<td>
Item 3
</td>
<td class="imageBox">
<img src="yes.png" alt="Needed">
</td>
<td class="imageBox">
<img src="yes.png" alt="Needed">
</td>
<td class="imageBox">
<img src="yes.png" alt="Needed">
</td>
</tr>
<tr> <!-- Row 4 -->
<td>
<form>
<input type="checkbox" name="Row4" value="Row4" onchange="onCheck(this);">
</form>
</td>
<td>
Item 4
</td>
<td class="imageBox">
<img src="yes.png" alt="Needed">
</td>
<td class="imageBox">
<img src="yes.png" alt="Needed">
</td>
<td class="imageBox">
<img src="no.png" alt="Needed">
</td>
</tr>
<tr id="outputRow"> <!-- Table Bottom -->
<td>
<!--Empty-->
</td>
<td>
Summation
</td>
<td id="total1">
0
</td >
<td id="total2">
0
</td>
<td id= "total3">
0
</td>
</tr>
</table>
Here is the Javascript (using jQuery)
//Numbers in the total row (Summation)
var total1=0;
var total2=0;
var total3=0;
function onCheck(cb)
{
var $box = $(cb);
var imageBoxes = $box.parents('td.imageBox');
if(cb.checked===true)
{
//Checks the image in the row. If it is yes.png, it adds 1 to to the total
//for that column and displays that total variable in the total row.
/*if(document.getElementById('image1').src.toString().indexOf('yes')>0){
total1++;
document.getElementById('total1').innerHTML=total1;
} */
if(imageBoxes[0].children().attr('src').toString().indexOf('yes')>0){
total1++;
document.getElementById('total1').innerHTML=total1;
}
/*else
{
document.getElementById('total1').innerHTML=no;
} */
if(document.getElementById('image2').src.toString().indexOf('yes')>0){
total2++;
document.getElementById('total2').innerHTML=total2;
}
/* else
{
document.getElementById('total2').innerHTML=no;
} */
if(document.getElementById('image3').src.toString().indexOf('yes')>0){
total3++;
document.getElementById('total3').innerHTML=total3;
}
/*else
{
document.getElementById('total3').innerHTML=no;
} */
}
//If the checkbox is unchecked, this checks for
//if the image in each box in that row is
//yes.png. If it is, then 1 is subtracted from the
//column's total and the new total is shown.
else
{
if(document.getElementById('image1').src.toString().indexOf('yes')>0){
total1--;
document.getElementById('total1').innerHTML=total1;
}
if(document.getElementById('image2').src.toString().indexOf('yes')>0){
total2--;
document.getElementById('total2').innerHTML=total2;
}
if(document.getElementById('image3').src.toString().indexOf('yes')>0){
total3--;
document.getElementById('total3').innerHTML=total3;
}
}
}
I built this in Fiddle, so all the Script imports are not shown.
EDIT: Here is the link to the Fiddle: hhttp://jsfiddle.net/GGxpX/62/
EDIT: It was pointed out that my Id's were repeating. I fixed this in the new fiddle, but this did not fix the problem.
EDIT3: Fixed more problems including using a td element as its image child. The link points to the updated Fiddle now.
EDIT4: Updated Fiddle again.
If I understand what you want, I think you are making this more complicated than it needs to be. (Correct me if I'm wrong.) I would have the handler for the checkboxes re-calculate the totals each time.
The JavaScript could be this short:
function onCheck() {
var totals = [0, 0, 0];
$('tr.checkRow').each(function () {
var $row = $(this);
if ($row.children('td:first').find('input:checkbox').prop('checked')) {
$(this).find('td.imageBox').each(function (index) {
var $imageBox = $(this);
if ($imageBox.children('img:first').attr('src').indexOf('yes') >= 0) {
++(totals[index]);
}
});
}
});
$('#total1').text(totals[0]);
$('#total2').text(totals[1]);
$('#total3').text(totals[2]);
}
Notice how the onCheck() function doesn't even take a parameter. That's because it doesn't matter what checkbox was changed, or if it was checked or unchecked.
This loops through each row, and if its checkbox is checked, it loops through each image box.
In order for the code above to work, you must put the class "checkRow" on the proper <tr> elements. (You previously had it as an "id" on those elements.)
jsfiddle
There were several things I saw wrong with your code. Here's a few:
"id" attributes must be unique.
When checking the result of calling .indexOf() use >= 0, not > 0.
imageBoxes[0] returns a DOM element, not a jQuery object.
There is no need for the calls to toString() because the src attribute is a string.
You could also attach your event handlers with jQuery, rather than use "onchange" attributes, but I left it your way in the jsfiddle.

JavaScript multiple incrementing variable solution

I have a variable ver i = 1.
I have a table as follows;
<table>
<tr class="testrow">
<td class="prev"> </td>
<td class="data"> </td>
<td class="next"> </td>
</tr>
<tr class="testrow">
<td class="prev"> </td>
<td class="data"> </td>
<td class="next"> </td>
</tr>
<tr class="testrow">
<td class="prev"> </td>
<td class="data"> </td>
<td class="next"> </td>
</tr>
<tr class="testrow">
<td class="prev"> </td>
<td class="data"> </td>
<td class="next"> </td>
</tr class="testrow">
<tr>
<td class="prev"> </td>
<td class="data"> </td>
<td class="next"> </td>
</tr>
</table>
The table may have more rows. I want a variable to increase value by 1 when I click next and decrease by 1 for prev. This can be done easily. But I want some variable which is row dependent. When I clicknext in first row, the variable value should be 2, but it should not change when I click either next or prev in any other row. Also this should be the case in all other rows. The minimum value of variable should be 1.
It will be helpful if someone provide me a fiddle with the variable displayed in the middle cell of each row. Note that in this demo, it should not be something to ++ or -- the text or data in the middle cell.
Here is my fiddle.
I'd use jQuery.data() to store the variable in each row, changing it when the user clicks prev/next:
$(function() {
$(".testrow").each(function() {
var $row = $(this);
// set the initial value
$row.data("currentIndex", 1);
$row.find(".prev").click(function() {
$row.data("currentIndex", $row.data("currentIndex") - 1);
alert("currentIndex: "+$row.data("currentIndex"));
});
$row.find(".next").click(function() {
$row.data("currentIndex", $row.data("currentIndex") + 1);
alert("currentIndex: "+$row.data("currentIndex"));
});
});
});
jsFiddle: http://jsfiddle.net/5TPCK/12/
$('table tr .next').click(function() {
alert($(this).closest('tr').index());
});
http://jsfiddle.net/ThiefMaster/5TPCK/2/
Btw, </tr class="testrow"> is horribly wrong - it should only be </tr>.
Couldn't you keep an array of these counters (this would work if the number of rows is known beforehand and static)? Otherwise you could attach the counter to each <tr> element using the jquery data() function.
See: http://api.jquery.com/jQuery.data/

Categories