complex jquery selector : challenge - javascript

I've searched among jquery selectors for some time now, but can't find any solution to my problem.
I've got an html table filed by a foreach. On each line, several links that pop up tooltips. My problem : can't find the right selector.
<table>
<?php foreach($article) :?>
<tr>
<td>
<div class="none" style="display:none;">
<div class="tooltip_1">
"The content of my tooltip_1"
</div>
<div class="tooltip_2">
"The content of my tooltip_2"
</div>
</div>
<div class="cell">
a link
a link
</div>
</td>
<tr>
<?php endforeach; ?>
</table>
To show my tooltip, I use qTip, and it works like this :
$('a[class="link_to_tooltip_1"]').qtip({
content: $('jquery selector'),
(... other options)
});
So basicaly, I would need something like
content: $('self.parentNode.parentNode > div[class="none"] > div[class="tooltip_1"]'),
in other words :
start from link "link_to_tooltip_1"
go back to parent div "cell"
go back to parent td
then go to child div "none"
and finally select child div "tooltip_1"
Thanks a lot.

// this is "complex" version;
// assumes .cell and .none are nested inside same container, whether <td> or <li> or anything
$(".link_to_tooltip_1").each(function () {
console.log($(this).closest(".cell").siblings(".none").find(".tooltip_1"));
// $(this).qtip({ content: /* use above selector */ });
});
// this is the "not-so-complex" version;
// assumes both items are nested arbitrary level deep inside same <td>
$(".link_to_tooltip_1").each(function () {
console.log($(this).closest("td").find(".tooltip_1"));
// $(this).qtip({ content: /* use above selector */ });
});
jsFiddle Link

$('a.link_to_tooltip1').closest('tr').find('.tooltip_1');
is probably what you're seeking for ?

why not place your tooltip like this ? :
<table>
<?php foreach($article) :?>
<tr>
<td>
<div class="cell">
<span class="tooltip_1" style="display:none;" >"The content of my tooltip_1"</span>a link
<span class="tooltip_2" style="display:none;" >"The content of my tooltip_2"</span>a link
</div>
</td>
<tr>
<?php endforeach; ?>
</table>
and
$('a[class="link_to_tooltip_1"]').qtip({
content: $(this).children("span"),
(... other options)
});
Edit
I didn't know you can't use $(this). So in this context, you can do :
$('a[class="link_to_tooltip_1"]').each(function(){
var content = $(this).prev("span");
$(this).qtip({
content: content,
(... other options)
});

Here is the selector you are looking for:
"td:has(.cell .link_to_tooltip_1) .none .tooltip_1"
Explanations:
You can't go backwards (match an element, and then its parent). However you can select an element and verify that it contains elements that match an other selector:
"td:has(.cell .link_to_tooltip_1)"
This selects the parent <td> of .link_to_tooltip_1. So this does exactly the .link_to_tooltip_1.parentNode.parentNode you described.
Then you just have to select .none .tooltip_1 in the selected <td>:
"td:has(.cell .link_to_tooltip_1) .none .tooltip_1"
So your example code becomes:
$('a[class="link_to_tooltip_1"]').qtip({
content: $("td:has(.cell .link_to_tooltip_1) .none .tooltip_1"),
(... other options)
});
And as you were asking for, this is done with just a jquery selector :-)

I'd try something like this:
add a class to the elements with tooltips and rel attribute with the target class of element holding data
link with tooltip yar!
then in JS
$('a.iHaveATooltip').bind('mouseenter', function(){
$(this).addClass('showingTooltip');
}).bind('mouseleave', function(){
$(this).removeClass('showingTooltip');
}).qtip({
content: function(){ return $('.' + $('.showingTooltip').attr('rel')).html() },
(... other options)
});
it's the only idea I can come with to cheat the lack of support for generic data referencing based on DOM structure. Though can't promise it will work as I don't know the plugin and don't know if passing function as an argument won't collide with how it's implemented - you might have to change the plugin to allow it to accept function as content parameter.
good bye and good luck,
Tom

Related

How to target child class and hide the parent one [duplicate]

How can I select the <tr> containing the child <div class="test">, as below?
<table>
<tr> <!-- this tr is what I want to select -->
<td>
<div class="test"> text </div>
</td>
</tr>
</table>
You can use parents or closest for that, depending on your needs:
$("div.test").parents("tr");
// Or
$("div.test").closest("tr");
(The initial selector can be anything that matches your div, so ".test" would be fine too.)
parents will look all the way up the tree, possibly matching multiple tr elements if you have a table within a table. closest will stop with the first tr it encounters for each of the divs.
Here's an example using closest:
Live copy | Live source
HTML:
<table>
<tr id="first"> <!-- this tr I want to select -->
<td>
<div class="test"> text </div>
</td>
</tr>
<tr id="second"> <!-- this tr I want to select -->
<td>
<div class="test"> text </div>
</td>
</tr>
<tr id="third"> <!-- this tr I want to select -->
<td>
<div class="test"> text </div>
</td>
</tr>
</table>
JavaScript:
jQuery(function($) {
var rows = $("div.test").closest("tr");
display("Matched " + rows.length + " rows:");
rows.each(function() {
display("Row '" + this.id + "'");
});
function display(msg) {
$("<p>").html(msg).appendTo(document.body);
}
});
Output:
Matched 3 rows:
Row 'first'
Row 'second'
Row 'third'
Use selector :has() like:
$("tr:has(div.test)");
Find jQuery documentation here :has() Selector
$('.test').parent('tr')
this selects exactly what you want.
you should use
$('.test').parents('tr');
For Example:
http://jsfiddle.net/7T9nN/
The below targets the parent with class of .test somewhere within its children and in the below example changes background to red...
$(document).ready(function(){
$('.test').parents('tr').css('background-color', 'red');
});
For me this is extremely powerful when trying to target exported html from indesign. Powerful because indesign does not let you tag 's but through this you can tag a and then the through this JQuery.
$('.test').parent().parent(); or $('.text').parent().closest('tr');

Javascript remove specific css value

I am trying to remove the word "Quantity" from below and I think I am close but obviously something is off since it's not working.
<div class="DetailRow" style="display: ;">
<div class="Label">
<label>Quantity</label>
With:
<script type="text/javascript">
$(document).ready(function(){
$('#text_qty_').parent().parent().remove();
$('#qty_').parent().parent().remove();
$('.QuantityInput').remove();
$('label[for="Quantity"]').css('display', 'none').remove();
});
</script>
Try doing it with pure js after adding an id.
<div class="DetailRow" style="display: ;">
<div class="Label">
<label id ="text">Quantity</label>
<script type="text/javascript">
$(document).ready(function(){
document.getElementById("text").innerHTML = "";
});
</script>
Your label needs an id. In this example, I'll use "quantity" as the id.
$('label[id="quantity"]').hide();
This will work but this will apply the style to all labels.
$('label')
Using Pure JavaScript is best though.
Try this $('label').html('');.
$('label[for="Quantity"]') will not retrieve <label>Quantity</label> since it doesn't have the attribute for. Just use $('label') or $('.Label label') and it will work.
Try this if you want to remove the label element itself:
var labels = $('label');
if( labels.text() == 'Quantity' ){
labels.remove();
}
To just remove the word Quantity without removing the label element:
labels.text('');
If you want to remove its parent:
labels.parent().remove();
Also to remove the parent's parent, the <div class="DetailRow"> use this:
labels.parent().parent().remove();
JSFiddle
You can use plain javascript and existing markup with querySelector:
var el = document.querySelector('.DetailRow .Label label');
if (el) {
// do stuff
}
If you want to remove the content, then:
el.textContent = '';
If you want to remove the element, then:
el.parentNode.removeChild(el);
and so on…
I think you can check the label value, and remove the label if the value equals to "Quantity"
Try this:
<div class="DetailRow">
<div class="Label">
<label>Quantity</label>
</div>
</div>
And the script:
$(document).ready(function(){
$(".DetailRow label:contains('Quantity')").hide();
});
http://codepen.io/Himechi90/pen/rOJYjX
Thank you Griffith! This worked perfectly. Full code for anyone trying to remove the quantity and quantity box from only some of your products on bigcommerce. Note that you need to create a separate product template and add this below %%Panel.Header%%
<script type="text/javascript">
$(document).ready(function(){
$('#text_qty_').parent().parent().remove();
$('#qty_').parent().parent().remove();
$('.QuantityInput').remove();
$('label').filter(function() { return $(this).text() === "Quantity"; }).remove();
});
</script>
Note also that your values for #text_qty_ etc may change depending on your template.
Thank you all for taking the time to help me!

Traversing on each span under table > tr > td > div

How to traverse on each span under table > tr > td > div ?
I would like to hide those span elements once click on the anchor tag that beneath the same tr level.
JSFiddle
$(document).ready(function() {
$(".hide").click(function(){
$('#table td div span').each(function(){
var $span = $(this);
$(this).siblings().hide();
var spanattr = $span.attr('class');
alert(spanattr);
});
});
});
HTML:
<table id="table">
<tbody>
<tr>
<td class="tdspan">
<div class="container">
<span class="spanelem">First</span>
</div>
</td>
<td class="tdspan">
<div class="container">
<span class="spanelem">Second</span>
</div>
</td>
<td class="tdspan">
<div class="container">
<span class="spanelem">3rd</span>
</div>
</td>
<td>
Hide
</td>
</tr>
</tbody>
<br>
</table>
<span id="text"></span>
I already searched for other questions and used the provided solution such as below link but I'm not able to figure it out.
jquery to traverse the div and get its span details
You don't need for loops there.
Simply .find() span with class .spanelem in a closest <tr> parent of the clicked element:
$(".hide").click(function(){
$(this).closest('tr').find('.spanelem').hide();
// Or using selector context (.find() equivalent but a bit shorter)
// $('.spanelem', $(this).closest('tr')).hide();
});
JSFiddle JSFiddle
References:
.closest()
.find()
selector context
Are you just trying to hide the spans themselves? You are hiding their siblings, and since they are the only children of their parent div, there is nothing else to hide. If you want to hide the spans themselves, then just change
$(this).siblings().hide();
to
$(this).hide();
If you have multiple rows, then you can just crawl up the tree from the .hide button that was clicked to its ancestor row, then find all the spans within that row. You may want to search on a particular class, or all spans, but I don't know for sure how you identify which elements you want to hide.
Something like
$(this).closest('tr').find('span').each(function() {
Updated JSFiddle here: https://jsfiddle.net/fk9jgrLx/4/
If your table structure is as in provided example, and if you will have multiple rows:
$(document).ready(function() {
$(".hide").click(function(){
$(this).parent().siblings().find('span').hide();
});
});
https://jsfiddle.net/L1j9psz6/1/ - remove all spans from row...

jQuery tooltip is not displayed anymore after updating table data

I have a table with a single span element in td.
<table>
<tbody>
<tr>
<td id="td">
<span id="span1">this is span1</span>
</td>
</tr>
</tbody>
</table>
I create a jQuery tooltip for span1.
$('#span1').tooltip({
content: function(){
return "tooltip_span1";
},
items: $('#span1')
});
I update the content of td adding a second span with id 'span2' by concatenating.
var tdHtml = $('#td').html();
tdHtml+="<br> <span id=\"span2\">this is span2</span>"
$('#td').html(tdHtml);
I add a tooltip for span2 which will be displayed correctly.
$('#span2').tooltip({
content: function(){
return "tooltip_span2";
},
items: $('#span2')
});
However, the tooltip of span1 is not displayed anymore after updating the td content. Why?
Please see a jsFiddle example here.
Thanks very much for your answers.
You should use append, right now you are deleting and re-adding span1 (and removing previously added behavior)
$('#td').append("<br> <span id=\"span2\">this is span2</span>");
http://jsfiddle.net/dy7pq/2/
It looks like it's because you are treating the existing code as HTML and that the DOM reference is lost. It will work if instead you append a DOM fragment.
var newSpan = $('<span id="span2">this is span2</span>');
$('#td').append(newSpan);
See this fiddle for complete code: http://jsfiddle.net/harveyramer/b3xGM/1/

Using each() for checking which class is clicked

So here's my problem, I'm new to jQuery. What I am trying to do here is check for user to click on a certain table cell/row and it would then display a div named popup of an index the same as the table cell votes. Without having to make separate functions of all the rows in my table.
Using some numerical value will display all the dialogs from a click of the cell of the same value the first time and from the second time only the correct one.
I bet there's some other way to do it and maybe there's just a stupid error.
Using the index value in the click and dialog function won't work.
I am open to suggestions on improvement also.
The scripts:
<script type='text/javascript'>
$(document).ready( function() {
$('.votes').each(function(index) {
$('.votes:eq(index)').click(function() {
$('.popup:eq(index)').dialog();
});
});
});
</script>
HTML for the table part, only a snippet
<td class='votes'>5</td>
<td class='votes'>15</td>
<td class='votes'>25</td>
HTML for the div part, only a snippet of the div:
<div class='popup'>
<ul>
<li>John Johnsson</li>
<li>John Doe</li>
</ul>
</div>
<div class='popup'>
<ul>
<li>Matt Theman</li>
<li>Peter Watley</li>
</ul>
</div>
jsFiddle Demo
You don't have to iterate using each for .click, that will happen internally. You can use .index() to get the index of the element clicked with reference to its parent.
$('.votes').click(function() {
$('.popup').eq($(this).index()).dialog();
});
Initially, the main problem is that you are not using string concatenation to apply the index to the selector (demo):
$('.votes:eq(index)')
// the Sizzle selector engine doesn't know what the string "index" is.
instead of
$('.votes:eq(' + index + ')')
// using concatenation calls the .toString() method of index to apply "0" (or "1", "2", etc.)
// so that the parsed string becomes '.votes:eq(0)' which the Sizzle selector engine understands
Once the Sizzle selector engine understands which elements to target (demo), the second problem is how jQueryUI changes the DOM with the .dialog method.
Inital markup:
<table>
<tbody>
<tr>
<td class="votes">5</td>
<td class="votes">15</td>
<td class="votes">25</td>
</tr>
</tbody>
</table>
<div class="popup">
<ul>
<li>John Johnsson</li>
<li>John Doe</li>
</ul>
</div>
<div class="popup">
<ul>
<li>Matt Theman</li>
<li>Peter Watley</li>
</ul>
</div>
Once the first click event is handled, one of the div.popup elements is transformed into a jQueryUI Dialog and is appended to the body, removing it from its initial position, like so:
<table>
<tbody>
<tr>
<td class="votes">5</td>
<td class="votes">15</td>
<td class="votes">25</td>
</tr>
</tbody>
</table>
<div class="popup">
<ul>
<li>Matt Theman</li>
<li>Peter Watley</li>
</ul>
</div>
<div class="ui-dialog ui-widget ..."> ... </div>
So your initial indexes no longer apply. Fortunately, there are several solutions to both problems (a few of which I've listed below).
Solutions to Problem 1:
Use string concatenation as described above.
Use the .eq method instead, which will accept the index variable as-is
Use a delegate handler instead and grab the index from within the handler:
Example of 2:
$('.votes').eq(index);
Example of 3:
$('table').on('click', '.votes', function (e) {
var vote = $(this),
index = vote.parent().index(vote);
});
Solutions to Problem 2:
Create all of the dialogs initially and open them as needed.
Create the dialogs using a deep clone of the div element. (Not recommended)
Remove the td element to match the removed and re-appended div element. (Not recommended)
Example of 1:
var popups = [];
$('.popup').each(function (i, elem) {
var popup = $(elem).data('index', i).dialog({
"autoOpen": false
});
popups.push(popup)
});
$('table').on('click', '.votes', function (e) {
var vote = $(this),
index = vote.index();
popups[index].dialog('open');
});
I'm sure there are other solutions as well, but these are the ones I thought of of the top of my head.
Functional demo: http://jsfiddle.net/2ChvX/2/
UPDATE:
With your chosen table structure, you're actually looking for the index of the parent tr element as that is what corresponds with the div.popup element. To get the index of the parent tr element, change the line that gets the index from:
index = vote.index();
to:
index = vote.parent().index();
Updated fiddle: http://jsfiddle.net/AZpUQ/1/
Updated
FWIW, here's an example using the jQueryUI dialog (which I presume you are using?) and javascript sectionRowIndex and cellIndex.
Reusable code allowing you to identify the cell the user clicked in and perform appropriate action.
http://jsfiddle.net/KbgcL/1/
HTML:
<table id="myTable">
<tr>
<th>Label:</th>
<th>Washington</th>
<th>Idaho</th>
<th>California</th>
</tr>
<tr>
<td class='label'>Votes</td>
<td class='votes'>5</td>
<td class='votes'>15</td>
<td class='votes'>25</td>
</tr>
<tr>
<td class='label'>Voters</td>
<td class='voters'>5,000</td>
<td class='voters'>15,000</td>
<td class='voters'>25,000</td>
</tr>
</table>
<div id="msg"></div>
jQuery/javascript:
var myTr;
$('#msg').dialog({
autoOpen:false,
title: 'Report:'
});
$('#myTable tr td').click(function() {
myTr = $(this).closest('td').parent()[0].sectionRowIndex;
myCell = this.cellIndex;
myState = $('#myTable').find('tr:eq(0)').find('th:eq(' +myCell+ ')').html();
myVoters = $('#myTable').find('tr:eq(' +myTr+ ')').find('td:eq(' +myCell+ ')').html();
if (myTr==2 && myCell==3){
//California
$('#msg').html('There are ' +myVoters+ ' voters in ' +myState);
$('#msg').dialog('open');
}else if(myTr==1 && myCell==1){
$('#msg').html('There were ' +myVoters+ ' votes made in ' +myState);
$('#msg').dialog('open');
}
});

Categories

Resources