Iterating through table rows in nested divs - javascript

I have a page that contains a couple of layers of nested div tags. Within the the 8 or 9 of the divs are tables. How do I iterate through the divs and pick the specific divs that I want and then iterate through the cells in the table (one row) embedded in each of the divs? Here is a representative sample of the page that I want to iterate through.
<div id="TheHouseDiv" class="catbox_m">
<div class="Room1Div">
<table width="900" border="0">
<tbody>
<tr>
<td>I don't care about this value</td>
<td>I WANT THIS VALUE 1!</td>
<td>I WANT THIS VALUE TOO 2!</td>
<td>Another cell I don't want</td>
<td>THIS CELL I WANT ALSO</td>
<tr>
</tbody>
</table>
<table width="900" border="0">
<tbody>
<tr>
<td>Ignore this value in the second table</td>
<td>I WANT THIS VALUE</td>
<td>I WANT THIS VALUE TOO</td>
<td>Ignore this content</td>
<td>GET THIS CELL VALUE</td>
<tr>
</tbody>
</table>
</div>
<div class="Room2Div">
<table width="900" border="0">
<tbody>
<tr>
<td>I don't care about this value</td>
<td>I WANT THIS VALUE 1!</td>
<td>I WANT THIS VALUE TOO 2!</td>
<td>Another cell I don't want</td>
...
You get the idea. So there is one table within each div and multiple divs. There are actually between 8 and 10 divs. None of the tables or cells have IDs so I need to reference the positionally. However I don't want all of the cell nor all of the tables. I only want values from specific cells in each of the tables within each div although I want the same cells from every table. Would I iterate through this or just reference the specific cells I want and if so, how do I select them?

This gives you all the tds which you want. (if you don't understand the selector just post a comment and I will explain it.
$("div#TheHouseDiv > div > table td:not(:nth-child(1)):not(:nth-child(4))")
e.g. to loop over the hrefs of the <a> tags inside these tds
$("div#TheHouseDiv > div > table td:not(:nth-child(1)):not(:nth-child(4)) a")
.each(function(i, ele) {
alert(ele.href);
}
);
e.g. to loop over the text of the <a> tags inside these tds
$("div#TheHouseDiv > div > table td:not(:nth-child(1)):not(:nth-child(4)) a")
.each(function(i, ele) {
alert($(ele).text()); //or ele.innerHTML if no nasty is in the <a> tags
}
);

$('#TheHouseDiv div').eq(1).find('table').eq(2).find('tr').eq(3).find('td').eq(4).text()
A bit verbose, but I believe this retrieves the text of the 4th <td> inside the 3rd <tr> of the 2nd <table> from the first <div> contained in #TheHouseDiv.
You can also use the shortcut .find('tr:first') to match the first one.

Related

Show/Hide specific rows in table when link is clicked

I have a table which contains categories of info on each row and many rows may have the same category.
I have a menu of all the categories (a very simple vertical text menu in a div).
<div class="menu">
Category 1
Category 2
Category 3
</div>
<table border="1">
<tr id="cat1">
<td>some info</td>
</tr>
<tr id="cat2">
<td>blah blah</td>
</tr>
<tr id="cat1">
<td>more blah</td>
</tr>
</table>
When I click on a specific category link in that menu I want it to only show the rows that match that category in the table.
I'm new to Javascript, etc so still learning. I've searched on Google but can only find examples that seem to hide/show 1 row or something similar but not what I need it to do. I can't work out if it's possible to do what I described above. Any help will be much appreciated!
Issues in your code
You need to identify your table rows by category.
Using id to assign a category to multiple rows is wrong (Duplicate ID values is invalid HTML).
You can use class, but personally I prefer to attributes since that value is meant to use within JS and not styling.
The default behavior of anchors is to redirect, refresh (or move the scrollbar), to make it short this isn't the element you need to use. I will replace it with a button.
A solution
// Selecting all the filters (buttons)
document.querySelectorAll('[catFilter]').forEach((el)=>{
//console.log(el);
// Listenning to clicks on the filters
el.addEventListener('click', (ev)=>{
// Selecting all the table rows when the click happens
// This will happen everytime you click!
document.querySelectorAll('table tr').forEach((row)=>{
//console.log(row);
if(ev.target.value === "*"){
// Show all
row.classList.remove('hidden');
}else if(row.hasAttribute(ev.target.value)){
// Make sure that the filtered rows are shown
row.classList.remove('hidden');
}else{
// Hide everything else
row.classList.add('hidden');
}
})
})
})
.hidden {
display: none;
}
<button value="cat1" catFilter>cat1</button>
<button value="cat2" catFilter>cat2</button>
<button value="*" catFilter>All categories</button>
<table border="1">
<tr cat1>
<td>some info</td>
</tr>
<tr cat2>
<td>blah blah</td>
</tr>
<tr cat1>
<td>more blah</td>
</tr>
</table>

JQuery link entire table row to anchor to trigger fancybox

I have found multiple ways to link an entire table row to another page with jQuery. But every solution I've tried for this does not work with anchors which point to a div that triggers a fancybox.
I have the following HTML
<tbody class="result" data-href="#details1">
<tr>
<td rowspan="2" class="resultlogo">
<img class="resultlogoimg" src="images/logos/logo-orshop.png">
</td>
<td class="resulthead">
<h1><a class="detaillink" href="#details1">Orshop</a></h1>
</td>
<td rowspan="2" class="resultprice">
<h1>€ 69.00</h1></td><td rowspan="2" class="resultrating">
<span class="markbg"><h1>8,3</h1></span>
</td>
</tr>
<tr>
<td class="resultpc"><h2>3074ES, Rotterdam</h2></td>
</tr>
</tbody>
With the following jQuery to trigger the click event:
$(".result").click(function() {
window.document.location = $(this).data("href");
});
The <tbody> tag wraps 2 table rows because of the way a result row is layed out. I want to show div contents in a fancybox based on the user clicking a row (or tbody tag).
Is it not possible to use data-href with anchors?
If you are going to wrap the 2 table rows, set you data attributes in the <table> tag, and not in the <tbody> tag.
Then you only need a simple fancybox initialization script like:
$(".result").fancybox();
And use the fancybox's special data attributes to set the href and the type of content like
<table class="result" data-fancybox-type="inline" data-fancybox-href="#details1">...</table>
See JSFIDDLE

ng-repeat in table and conditional tr

I have a collection of elements of different types. I want to iterate them using ng-repeat, and conditionally draw the right tr per each type.
I can't use ng-repeat-start since I want to use virtual scrolling and none of the libraries I found supports the start/end concept.
Here is a jsfiddle: http://jsfiddle.net/mx6v8j98/1/, which doesn't work. here is the HTML part:
<div ng-app ng-controller="MyCtrl">
<table>
<tbody>
<tr ng-repeat="item in itemsList" ng-switch="$even" ng-class-even="'even'" ng-class-odd="'odd'">
<div ng-switch-when="true">
<td>{{item}} is even</td>
<td>even content</td>
</div>
<div ng-switch-default>
<td>{{item}} is odd</td>
<td>odd content</td>
</div>
</tr>
</tbody>
</table>
</div>
In my real world case, I have many td with complex content, so I don't want to use ng-if/ng-switch-when on each
Update: I can put the ng-repeat on the <tbody> tag, but that looks ugly and I'm not sure what the consequences are regarding styling
Update II: In my case, the 'tr' tag itself is rendered differently according to a condition
As stated in another answer, <div> is not allowed as a child element of <tr>.
You are clearly trying to use <div> as a logical container for ng-switch-when, but since ng-switch-when (and ng-switch-default) supports multi-element, you don't need this container:
<tr ng-repeat="item in items" ng-switch="$even">
<td ng-switch-when-start="true">{{item}} is even</td>
<td>even content 1</td>
<td>even content 2</td>
<td ng-switch-when-end>even content last</td>
<td ng-switch-default-start>{{item}} is odd</td>
<td>odd content 1</td>
<td>odd content 2</td>
<td ng-switch-default-end>odd content last</td>
</tr>
It seems you cannot put <DIV> within <TR> but before <TD>.
Solution 1: Put conditional expression in every <TD>.
<!-- TDs for even row -->
<td ng-if="$even">{{item}} is even</td>
<td ng-if="$even">even content</td>
<!-- TDs for odd row -->
<td ng-if="!$even">{{item}} is odd</td>
<td ng-if="!$even">odd content</td>
Solution 2: For fairly complex table structure, you'd consider create your own directive to represent row cells.

angular.js: A Table from nested data structure?

I have the following data structure: a list of courses, and for every course, a list of semesters. I need to build a table with a row for every semester of every course, and a column with the course's name which spans all the rows for that course.
I'm trying to use angular to generate the table, but because the data structure is nested I can't simply do ng-repeat in the tr tag. So I tried doing this:
<table border="1">
<div ng-repeat="course in data">
<tr>
<td rowspan="{{course.semesters.length}}">{{course.name}}/td>
</tr>
<tr ng-repeat="semester in course.semesters">
<td>{{semester.info}}</td>
</tr>
</div>
</table>
This utterly fails - the table is generated outside the repeated div. Seems to me I'm missing something basic about how ng-repeat works.
Try tbody instead of div:
<table border="1">
<tbody ng-repeat="course in data">
<tr>
<td rowspan="{{course.semesters.length}}">{{course.name}}/td>
</tr>
<tr ng-repeat="semester in course.semesters">
<td>{{semester.info}}</td>
</tr>
</tbody>
</table>

How to avoid using JavaScript with CSS attribute selector

I am trying to hide subsequent tr's with role="metadata" and the same data-group-id as the first occurring tr.
I cannot use JavaScript here and I am trying to achieve this using pure CSS.
<table>
<tbody>
<!-- BEGIN this tr should be visible -->
<tr data-group-id="1" role="metadata">
<td>
First rows group title
</td>
</tr>
<!-- END this tr should be visible -->
<tr data-group-id="1" role="data">
<td>
Row belonging to group 1
</td>
</tr>
<!-- BEGIN this tr should be hidden -->
<tr data-group-id="1" role="metadata">
<td>
Rows group title
</td>
</tr>
<!-- END this tr should be hidden -->
<tr data-group-id="1" role="data">
<td>
Another row belonging to group 1
</td>
</tr>
<!-- BEGIN this tr should be visible -->
<tr data-group-id="2" role="metadata">
<td>
Second rows group title
</td>
</tr>
<!-- END this tr should be visible -->
<tr data-group-id="2" role="data">
<td>
Row belonging to group 2
</td>
</tr>
</tbody>
</table>
Selectors like this...
[data-group-id="1"][role~="metadata"] ~ [data-group-id="1"][role~="metadata"]
display: none
... work very well, except that data-group-id may change dynamically.
Something like this would be perfect (I know that this is invalid CSS code, its just my fantasy with regular expressions to help illustrating the problem):
[data-group-id="(.*?)"][role~="metadata"] ~ [data-group-id="\\1"][role~="metadata"]
Is there any way I can achieve this using only CSS?
Thanks in advance.
Seems to me that using the data-group-id in CSS is impractical, especially since it's dynamically mutable and conditions of wether an element is hidden or not change. You end up with a huge chunk of CSS thats impossible to maintain.
In the initial rendering, it might be better to add a className so you determine serverside wether the initial state should be shown or not.
<tr data-group-id="1" role="data" class="hidden">
<td>Another row belonging to group 1</td>
</tr>
I am assuming JavaScript is used to dynamically change data-group-id, so why not use JavaScript to add/remove the className "hidden" when/where it makes sense. At least in JavaScript you CAN use regular expressions ;)
When you get to the point where you have to write impossible, long winded, error prone and unmaintainable CSS expressions, you're doing something wrong.
You're going to have to write some code to achieve this anyways, might as well do it the clean way instead of trying to shoehorn it into a styling language that isn't fit for the job.

Categories

Resources