Complex jQuery filter() not working - javascript

I am trying to dynamically insert links to return to the top of the document at the end of every section of a web page (sad to say, but it's table-based layout). I'm using the jQuery filter() selector, and while I get no error, it's not making any changes in the browser output. When I use alert() with the variable, it says Object object. I understand that the problem is in the line where I define the filter itself, but I was unable to find a similar example, and I don't know how to fix it.
Here's the code:
HTML
<table>
<tr class="head"><td colspan="2">section title 1 </td></tr>
<tr><td>text</td>
<td><img /></td>
</tr>
<tr><td>text</td>
<td>< img /></td>
</tr>
<tr class="head"><td colspan="2">section title 2 </td></tr>
<tr><td>text</td>
<td><img /></td>
</tr>
<tr><td>text</td>
<td>< img /></td>
</tr>
<!-- you get the point -->
JavaScript
$(document).ready(function(){
var lastRow = $('tr').filter(function(){
return $(this).next()==$(".head"); // Here's the problem, IMO
});
var a = '<tr class="toTop"><td class="top" style="text-align:right" colspan="2">go to top ↑</td></tr>';
lastRow.after(a);
});
The script attempts to select each row that precedes a row with class="head" and insert a row with a top link.

That's because you are comparing 2 different objects that is always false, you should use is method or length property:
var lastRow = $('tr').filter(function(){
return $(this).next(".head").length;
// return $(this).next().is(".head");
});
However, I'd suggest using .prev() method:
$('tr.head').prev(); // selects the previous sibling tr element

Related

Sort row in array as easily as possible (Javascript)

I have this table with 750 rows of infomation. Its extracted using php. However, in one of the rows I have this image popping up, the image src will either be 1.jpg or 0.jpg. This will chose between https://gyazo.com/81f37995cfb2fbeaec157716d06b3816 these two pictures.
So how can I possibly sort this row after what picture it displays and how to make the code as simple as possible to ensure that it wont take to long time/effort for the computer using the website ordering the line. (Using Javascipt of course)
So the code is supposed to order the rows over again to put for example the td's with <img src="0.jpg" /> in it gets placed first and then put the td's with <img src="1.jpg" /> at the end. To sort them.
Example code:
<table>
<tbody>
<tr>
<th>Name</th>
<th>Checked or unchecked</th>
</tr>
<tr>
<td>Name1</td>
<td><img src="1.jpg" /></td>
</tr>
<tr>
<td>Name2</td>
<td><img src="0.jpg" /></td>
</tr>
</tbody>
</table>
You can use this function:
function sortCol(desc) {
const tbl = document.querySelector("table>tbody");
const rows = Array.from(tbl.rows).slice(1).sort((a, b) =>
a.querySelector("img").src.localeCompare(b.querySelector("img").src)
);
if (desc) rows.reverse();
rows.forEach(row => tbl.appendChild(row));
}
Call it with argument true when you want to have a descending sort order. If you have more than one table on your page, you need to qualify the selector at the start of the function to target the right table.

Don't work get element by id

I'm trying to get to this ID (contentContainer) in a webpage:
... //code before is OK, i can get values, etc. Then comes this:
<!-- *********************** CONTENT BELOW ************************** -->
<table align="center" id="contentContainer" width="100%">
It seems I can't get to this part of the code (after that line with CONTENT BELOW). I tryed to use the code in Tampermonkey:
var a= document.getElementById("contentContainer").length;
console.log(a);
I can use this kind of var check to the code before that code, without any problem. Any Ideas of whats happening and how to get the code I want (in contentContainer)?
A single DOM node doesn't have a .length property. A node list, which is an array-like collection of HTML elements does.
var tbl = document.getElementById("contentContainer"); // Get a reference to the single table node
console.log(tbl); // Log what was refererenced
// Get a reference to all of the row elements in the table
// (which returns a node list).
var rows = tbl.querySelectorAll("tr");
console.log(rows.length); // Log how many nodes are in the node list
<table align="center" id="contentContainer" width="100%">
<tr>
<td>Row 1</td>
</tr>
<tr>
<td>Row 2</td>
</tr>
<tr>
<td>Row 3</td>
</tr>
</table>
Without other information it seems that your call to get the element by Id is trying to get the length property at the same time which will fail to get the element in the first place. So try getting rid of the .length.

.each() function on affect current object

having some issues with my code below, first here is the HTML:
<table class="finance-table">
<tbody><tr>
<th></th>
<th>Deposit</th>
<th>Balance</th>
<th>Fees</th>
<th>Total Payable</th>
<th>Term</th>
<th>Fixed Rate</th>
<th>Representative APR</th>
<th>Monthly Pmt</th>
</tr>
<tr class="hp">
<td><strong>HP</strong></td>
<td id="td_finance_deposit">£11700.00</td>
<td id="td_finance_balance">£105300.00</td>
<td id="td_finance_fees">£298.00</td>
<td id="td_finance_total_inc_deposit">£146255.50</td>
<td id="td_finance_term">60 mths</td>
<td id="td_finance_rate">5.50%</td>
<td id="td_finance_apr">10.1%</td>
<td id="td_finance_monthly_payments">£2242.59 p/m* x 60 mths</td>
</tr>
</tbody></table>
There is about 10 of these tables [within the same document], all with the same id's and class's. I'm using an each loop to execute some code against each table found, however it only seems to be working on the first table and disregards the others.
Below is the jQuery, like I said works find on the first table, but ignores the rest!
<!-- Remove First and Final Payment from Showroom Finance Examples -->
<script>
$(".finance-table").each(function(key, value) {
// Display loading
var html = $(this);
// Remove the First Payment and Final Payment Column
$(this).find("#td_finance_first_payment, #td_finance_final_payment").remove();
$(this).find("th:contains('1st Pmt')").remove(); $(this).find("th:contains('Final Pmt')").remove();
// Get the Term and update the monthly payment
var term = $(this).find("#td_finance_term").html(); // .replace(/\D/g,'')
var payments = ($(this).find("#td_finance_monthly_payments").html()).split('x')[0];
($(this).find("#td_finance_monthly_payments")).html(payments + " x " + term);
})
</script>
Edit:
Please note, I can't change the HTML at all
You should first give a unique ID to each <td>, perhaps with your DB identifier for that record. You don't need it now but this will allow you to do other thing later if you need it.
Then change all the <td> ids to classes:
<td class="td_finance_fees">£298.00</td>
Finally change all your javascript accordingly to use class instead of IDs:
$(this).find(".td_finance_first_payment, .td_finance_final_payment").remove();
Using Attribute Equals Selector
Change your code from:
$(this).find("#td_finance_first_payment, #td_finance_final_payment").remove();
to:
$(this).find('td[id="td_finance_first_payment"], td[id="td_finance_final_payment"]').remove();
Do this type of change for all areas of #xxx to id="xxx"
What this does is find all tds with attribute id="xxx", rather than using #id identifier, this is forces jQuery to do a tree search.
Also your HTML does not match your code, (theres no td_finance_first_payment in your html, I assume you removed it?)
Edit: This solution is useful if you 100% cannot edit the html (comes from a source you have no control over, such as an API or internal software). Best solution would be to fix the ids!

Why does this Javascript only run once per page?

I have this Try-it-Yourself section to my website but for some reason when I am wanting to have more than one Try-it-Yourself section it will only work for the one at the top of the page. So if I had three of them on a page the top one would work in the way I want but the next two would do nothing.
I have the following HTML:
<div class="tryit">
<table>
<tr>
<td>Try It Yourself</td>
</tr>
<tr>
<td><textarea id="input" rows="10" cols="47"></textarea></td>
</tr>
<tr>
<td><input onclick="update();" type="button" value="Update"></td>
</tr>
<tr>
<td><iframe id="output" name="output" width="600" height="300" ></iframe></td>
</tr>
</table>
</div>
And the following Javascript:
function update()
{
var tryitoutput = document.getElementById('input').value;
window.frames['output'].document.documentElement.innerHTML = tryitoutput;
}
Thank you.
As others mentioned, this is happening because there can't be more than one HTML element with same value of ID attribute. In your case javascript only finds the first element, that's why it doesn't work on later Update buttons. The simplest approach would be to set different ID attribute values for different "Try it yourself" boxes:
Slightly modify your JS, see following jsFiddle example
function update(tryItIndex) {
var tryItOutput = document.getElementById('input-' + tryItIndex).value;
window.frames['output-' + tryItIndex].document.documentElement.innerHTML = tryItOutput;
}
That's because you are referring to the textarea and the output by id which means it will always just retrieve the first one. A quick fix would be having unique id's for these fields and send the names as parameters to the update function like update(inputId, outputId)

Accessing next sibling

I have a HTML snippet like below :
<tr><td></br></td></tr>
<tr title="title"><td></td><td>凝固検査専用容器</td></tr>
<tr id='map_6011' />
<tr id='map_6012' />
<tr id='map_6010' />
<tr id='map_6184' />
<tr id='map_6336' />
<tr><td></br></td></tr>
<tr title="title"><td></td><td>血糖専用容器(NaF入り)</td></tr>
<tr id='map_2055' />
<tr id='map_3471' />
<tr><td></br></td></tr>
<tr title="title"><td></td><td>アンモニア専用容器</td></tr>
<tr id='map_2142' />
First I want to select each TR tag with the title "title", and then first sibling of that particular TR tag.(ie, next TR with an ID like 'map_xxxx').
I have my javascript like this :
var lblTRs=$("tr[title=title]");
for(var i=0;i<lblTRs.length;i++){
var obj=lblTRs[i];
var firstTRSibling=obj.nextSibling;
alert(firstTRSibling); //this gives [object Text]
}
But it doesn't give the actual TR sibling.The alert() gives [object Text].
What am I doing wrong here ?
Try like this:
var firstTRSibling;
while((firstTRSibling=obj.nextSibling).nodeType !== 3){
// ^-----indicates TEXT_NODE
obj=obj.nextSibling;
}
alert(firstTRSibling);
You have extra white-space characters between DOM elements, and they will be treated as text nodes.
I think you can simply use next:
$("tr[title='title']").each(function() {
var element = $(this).next();
});
BTW, <tr> should have closing tags (i.e. </tr>) and also contain the specified number of <td></td> tags inside.
Your problem is that the white space between each pair of <tr> elements is represented as a text node in the DOM. However, there are seemingly little-known properties of of table-related elements that make dealing with this quite easy. Specifically in this case, the rows property of <table> elements and the rowIndex property of <tr> elements. Assuming you have a <tr> element stored in a variable called tr, all you need is:
tr.parentNode.rows[tr.rowIndex + 1];
This works in all major browsers back to IE 4 and is part of the DOM standard. It is also faster and more compatible than using jQuery or another library.
Ok,I should use
var firstTRSibling=obj.nextSibling.nextSibling;
But why?_
As you're already are using jQuery, i'd recommend to use jQuery built-in next function.
It could be somthing like var lblTRs=$("tr[title=title]").next("tr");

Categories