Using each() for checking which class is clicked - javascript

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');
}
});

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');

CSS binding not working in Knockout JS

I am new to Knockout JS, therefore need your help to fix one small issue. I am trying to bind css style with a table row in CSHTML page, based on a condition. I have added 2 rows but displaying only one for each item using 'visible' attribute. Following is my cshtml code:
<table class="listing">
<tbody class="no-wrap" data-bind="foreach: searchResultsListing.pagedItems, select: searchResultsListing">
<tr class="selectable" data-bind="visible: !$root.isMatchedCase($data), css: { selected: $root.searchResultsListing.isSelected($data) }">
<td class="check"><span></span></td>
--
--
<tr/>
<tr class="selectablematch" data-bind="visible: $root.isMatchedCase($data), css: { selected: $root.searchResultsListing.isSelected($data) }">
<td class="check"><span></span></td>
--
--
<tr/>
Underlying Typescript: Inside app.listing.ts File:
isSelected(item: T) {
return this.selectedItems.indexOf(item) >= 0;
}
As you can see, based on the result of isMatchedCase() method (which returns a boolean), I am displaying either of the tr (selectable or selectablematch). The problem is the css on the tr is getting binded only for the first tr, i.e. with the class selectable, and not getting binded with the selectablematch tr. The method 'isSelected($data)' is not getting called when the checkbox in the first td is clicked for 'selectablematch' tr. Can you guys please let me know what I am missing here?
I am little confused as to why you need to have 2 tr to begin with. What you could do is have a computed which would return the correct class for you and have only one row which will be always visible. Not need to deal with hide/show etc.
Look at this article on the css binding and how it is done. Here is what I am suggesting:
<table class="listing">
<tbody class="no-wrap" data-bind="foreach: searchResultsListing.pagedItems, select: searchResultsListing">
<tr data-bind="css: { rowClass($data), selected: $root.searchResultsListing.isSelected($data) }">
<td class="check"><span></span></td>
<tr/>
</tbody>
</table>
And your pureComputed (wrapped in a function so we can pass the $data):
var rowClass = function(data) {
return ko.pureComputed(function(){
return isMatchedCase(data) ? 'selectablematch' : 'selectable')
)}
}
I think that should get you going in the right direction.

How to use slideToggle on a set of elements?

I'm attempting to use the jQuery slideToggle() function to minimize a set of table rows. The problem I'm encountering is that while the set of rows are minimized, the animation does not seem to be taking effect. I think it has something to do with the manner in which I'm using slideToggle, calling it on a set of results instead of on a parent element, but am not sure.
I'm using this bit of javascript and jquery to minimize a set of rows.
$('td').on("click", "a.collection-minimize, a.list-minimize", function(event) {
event.stopPropagation();
// Get the class of the following row
var minimize_class = $(this).parent().parent().next().attr('class');
// trim whitespace
minimize_class = minimize_class.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
// Minimize all following rows of the same class.
$(this).parent().parent().siblings('.' + minimize_class).slideToggle();
});
An example set of rows:
<tr class="collection-original">
<td>
<a class="collection-minimize" onclick="return false" href="#">Minimize collection</a>
</td>
</tr>
<tr class=" collection-original" style="display: table-row;"></tr>
<tr class=" collection-original" style="display: table-row;"></tr>
<tr class=" collection-original" style="display: table-row;"></tr>
<tr class=" collection-original" style="display: table-row;"></tr>
A live page where this is being used can be viewed here: http://iodocs.vky.me/whitehat#Application-API-PUT-Modify-an-application.
See this: http://jsfiddle.net/DEPjD/
minimize_class = minimize_class.replace(/^\s\s*/, '').replace(/\s\s*$/, '').trim();
Or:
minimize_class = minimize_class.replace(/^\s\s*/, '').replace(/\s\s*$/, '').replace(/ /g, '');

onclick defined text-var returns emptystring on log

var listname=$(this).parents(".x-grid3-row-table").children(".x-grid3-cell-inner.x-grid3-col-1").text();
console.log(listname);
the console.log returns following:
(an empty string)
can you help me on why listname is empty? and could you also tell me how to pass listname as parameter to a server-side method in an Ext.Ajax.request?
this is the html-code coming from my generated page:
<table class="x-grid3-row-table>
<tr>
<td class="x-grid3-col x-grid3-cell x-grid3-td-1 " tabindex="0" style="text-align: left;width: 265px;">
<div class="x-grid3-cell-inner x-grid3-col-1" unselectable="on">foo_bar#domain.de</div>
</td>
<td class="x-grid3-col x-grid3-cell x-grid3-td-2 x-grid3-cell-last " tabindex="0" style="width: 59px;">
<div class="x-grid3-cell-inner x-grid3-col-2" unselectable="on">
<span class="free">free</span>
</div>
</td>
</tr>
<tr class="x-grid3-row-body">
<!-- 7 Elements Markup down, who all act wrapping for the following -->
<div class="details">
<!-- some other markup elements, who also contain data, but are not further interesting-->
<td class="data"> foo bar detail data </td><!-- not of interest-->
<td class="edit"><input value="edit" onclick="see function on top" type="button" /> </td>
</div>
</tr>
</table>
target is to extract: foo_bar#domain.de and pass it to a server-method as parameter. the method is supposed to make a Window, but that's a different story.
the onclick call is from a expanded grid panel body, which is wrapped in a table('.x-grid3-row-table') with the given html-code.
You have a space between class names in your children selector, however your markup suggests that both the class names are of same elements.
To select an element with more than one class names the selector should not have space between class names as .classname1.className2.
var listname=$(this).parents(".x-grid3-row-table").children(".x-grid3-cell-inner.x-grid3-col-1").text();
console.log(listname);
should work.
Further clarification:
If you have space between class names as in question it would mean that you are trying to select an element having .x-grid3-col-1 class within .x-grid3-cell-inner class. Which is parent child relationship.
Edit:
If your button is in the next row you can use .prev() selector of JQuery with combination of using tr as parent selector rather than table.
listname=$(this).parents("tr").prev().children(".x-grid3-cell-inner.x-grid3-col-1").text();
Or if it is in same row then simply
listname=$(this).parents("tr").children(".x-grid3-cell-inner.x-grid3-col-1").text();
There might be a cleaner way of doing this but I came up with this as your button click handler, it assumes that the text() your looking for is one table row up from the button.
var $rows,button=this,i;
$rows=$(".x-grid3-row-table tr");
for(i=0;i<$rows.length;i++){
// get the button of that row
// not sure how to as your button is not
// in a table row with the code you posted
if($rows[i].getElementsByTagName("input")[0]===
button){
break;
}
}
// I assume the button is in a row before the button
console.log($($rows[i-1])
.find(".x-grid3-cell-inner.x-grid3-col-1")
.text()

jQuery .next() elements

This change from mootools drives me crazy.
HTML
<tr class="teamicon">
<td style="text-align: center;" width="100%" valign="middle">
//Blahblah
</td>
</tr>
<tr class="teamval">
<td valign="middle" width="100%">
//Blahblah
</td>
</tr>
What I want to achieve. When with class "teamicon" is clicked I want to show/hide tr with class teamval with animation. However, I can't make it animate properly. Looks like inside "teamval" must be animated first (or am I wrong?).
My try:
jQuery(document).ready(function(){
$('.teamval').slideUp(400);
$('.teamicon').click(function(){
if ($(this).next('tr').is(":hidden"))
{
$(this).next('tr.teamval').$('td').slideDown(400, function(){
$(this).next('tr.teamval').slideDown(400);
});
}
else
{
$(this).next('tr.teamval').$('td').slideUp(400, function(){
$(this).next('tr.teamval').slideUp(400);
});
}
});
});
OFC. This is wrong ("$(this).next('tr.teamval').$('td')" returns error in firebug). How can I achieve this?
I can't swap to div though.
You could do one of:
$(this).next('tr.teamval').slideDown(...) // whole tr
$(this).next('tr.teamval').find('td').slideDown(...) // td descendant
The error is because you are trying to access a $ property on the jQuery element set, which doesn't exist. Instead we can use find, which searches for matching descendants of elements in the current set.
EDIT:
Okay, I think you want:
if ($(this).next('tr').is(":hidden"))
{
var nextTeamval = $(this).next('tr.teamval');
nextTeamval.find('td').slideDown(400, function(){
nextTeamval.slideDown(400);
});
}
The only potential problem is if teamval contains a td within a td (nested table). You can try this jsFiddle demo.

Categories

Resources