I've got a set of tr tags in a table and some of them have a class of collapsible-parent. When I click on an element in the row it calls this javascript method:
function toggle() {
$(this).closest("tr").nextUntil(".collapsible-parent").toggleClass("open");
}
But none of the rows inbetween are having the open class added. So the HTML is something like so:
<tr class="collapsible-parent">
<td>
<span onclick="toggle()"><i class="fa fa-chevron-circle-right"></i></span>
</td>
...
</tr>
<tr>....</tr>
<tr>....</tr>
<tr class="collapsible-parent">....</tr>
so if I trigger that method on the first tr shown, I'd want the second and third tr to have the open class added to them.
What have I done wrong?
I just now realised that you have fixed your problem, though I will keep the answer for future reference as it is a tricky bug.
The onclick event listener is not captured correctly by jQuery. I have managed to run this successfully by adding an id on the span element and then adding an .on("click") listener using jQuery.
Add an id on the span element:
<span id="btn"><i class="fa fa-chevron-circle-right"></i></span>
and add a listener using jQuery:
$("#btn").on("click", function() {
$(this).closest("tr").nextUntil(".collapsible-parent").toggleClass("open");
});
Related
I am creating a responsive data table that adds a row each time I click on a add button that is in the end of the row. And the add button turns into a delete button. Here's the code I made
For the Table:
<table id="invoice_table_data">
<tr id="last_row">
<td contenteditable id="item_name"></td>
<td contenteditable id="item_code"></td>
<td contenteditable id="description"></td>
<td>
<button type="button" name="btn_add" id="btn_add" class="btn btn-xs btn-success">+</button>
</td>
</tr>
</table>
When for adding is clicked:
$("#btn_add").click(function() {
$("#invoice_table_data").append('<tr id="myTableRow'+'" ><td id="item_name'+n+'">'+item_name+'</td><td id="item_code'+n+'"> '+item_code+'</td><td id="description'+n+'">'+description+'</td><td><button type="button" name="delete_" id="delete_" data-idx="'+n+'">x</button></td></tr>');
n+=1;
And my delete function:
$('#delete_').click( function () {
var nb=$(this).data('idx');
$("#last_row"+nb).remove();
});
However when I click on delete nothing seems to happen. Can anybody help?
Identifiers in HTML must be unique, So create the element using CSS class. then Class Selecctor can be used.
Change script to render HTML as
<button type="button" class="delete_">x</button>
Currently what you are using is called a "direct" binding which will only attach to element that exist on the page at the time your code makes the event binding call.
Use .on() method with Event Delegation approach while generating elements dynamically. So change your code to
$("#invoice_table_data").on('click', ".delete_", function(){
$(this).closest('tr').remove();
});
var n = 1;
$("#btn_add").click(function() {
$("#invoice_table_data").append('<tr><td>item_name' + n + '</td><td><button type="button" class="delete_" data-idx="' + n + '">x</button></td></tr>');
n += 1;
});
$("#invoice_table_data").on('click', ".delete_", function() {
$(this).closest('tr').remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="invoice_table_data">
<tr id="last_row">
<td id="item_name"></td>
<td>
<button type="button" name="btn_add" id="btn_add" class="btn btn-xs btn-success">+</button>
</td>
</tr>
</table>
Use attribute selector and event delegation
$(document).on('click', "[id^='delete_']", function () {
var nb=$(this).data('idx');
$("#last_row"+nb).remove();
});
Try this :
$('document').on('click', '#delete_', function () {
var nb=$(this).data('idx');
$("#last_row"+nb).remove();
});
You need to use on method, since your delete button not yet been exists.
You have two separate problems.
Problem 1
You can't have the same id multiple times on the page. That's just a basic rule of HTML. You can only use it once. If you use the same id more than once, only the first time will be counted.
Solution
If you want to be able to target multiple elements, use classes, or target a single parent and grab it's children using element.firstElementChild
Problem 2
When you write .click, you are telling the browser to watch for when a user clicks on the element that you are targeting.
However, that element has to exist when the page first loads. That is because the lines of Javascript are only parsed once by the browser. It reads through your code, and if the element you want to click on doesn't exist right then, your code is skipped.
Solution
So what you have to do to address this is to add the event listener, the .click, onto an element which isn't dynamic. Remember that every click event gets passed up the chain, from the inner most element that the user clicked on, to that element's parent, to the next parent, and so on until it reaches the body element. So if you add a .click onto the parent of your list, it'll be attached correctly.
Using jQuery, it would be something like:
$('#invoice_table_data').on('click', 'button.delete', function(event){
//run code here
});
Change your script which is dynamically adding the delete button to give the button a class name of btnDelete or something similar.
$("#btn_add").click(function() {
$("#invoice_table_data").append('<tr id="myTableRow'+'" ><td id="item_name'+n+'">'
+item_name+'</td><td id="item_code'+n+'"> '
+item_code+'</td><td id="description'+n+'">'
+description+'</td><td><button type="button" class="btnDelete" name="delete_" id="delete_" data-idx="'+n+'">x</button></td></tr>');
n+=1;
});
Then the script for your delete button is:
$("body").on("click", ".btnDelete", function (e) {
var rowToDelete = $(this).closest("tr");
rowToDelete.remove();
});
http://codepen.io/ailinmcc666/pen/ZBgXBZ
I'm trying to add a new class "ok" to an <a href> when it's checked.
I'm using bootstrap, jquery and bootstrap table from http://wenzhixin.net.cn/p/bootstrap-table.
the jsfiddle : http://jsfiddle.net/x0wegnhs/1/
Can you help me to release that ?
<tr>
<td class="bs-checkbox"><input data-index="0" name="btSelectItem" type="checkbox"></td>
<td style="text-align: left; ">file 1</td>
</tr>
Use closest to find the nearest tr, then find to find the anchor link. Use toggleClass with a boolean value to turn on/off that ok class based on the checked state.
http://jsfiddle.net/TrueBlueAussie/x0wegnhs/6/
$(':checkbox').change(function () {
$(this).closest('tr').find('td a').toggleClass('ok', $(this).is(':checked'));
});
Side notes on jQuery vs direct access:
As #Karl-André Gagnon points out this can, apparently, be shortened a little by going RAW JS for the checked property like this:
$(':checkbox').change(function () {
$(this).closest('tr').find('td a').toggleClass('ok', this.checked));
});
However, I would normally have had a variable for the $(this) element and my selector constants, so:
$this.is(checkedSelector)
becomes the following when minified:
t.is(c)
which is then actually shorter than:
this.checked
because this and the checked property cannot be minified :)
You do not need to find closest tr as somebody mentioned. You must do for each loop with jquery. When you do that, you are positioned at input tag (your "this" let me say it like that is referenced to input field when you loop). So you need first go out your input tag because you can't use next() because there is no other tags except parent tags after that input tag in that hierarchy position. That's why you need to use first parent() (to get outside where you are), so you could be positioned in td parent tag. Then you use next() to go to next td tag, and then you use find("a") to find your a tag and add to it class "ok".
$(document).ready(function(){
$("input[name=btSelectItem]").each(function () {
if (this.checked){
$(this).parent().next().find("a").addClass("ok");
}
});
});
You asked for the solution of this:
I'm trying to add a new class "ok" to an when it's checked.
You can find it here - with piece of code I described, class will be added on any a tag next to it's checkbox. You can inspect the source and see for yourself that class ok is added to checked checkbox.
http://jsfiddle.net/upquya6p/2/
For each td element in a table I have an attached ng-click. Here is the (simplified) html for each table cell:
<td ng-click="cellClicked($event)">
<span ng-if="!cellEdit">{{event.eventName}}</span>
<input type="text" ng-if="cellEdit" ng-model="event.eventName">
</td>
And my (simplified) ng-click function:
scope.cellClicked = function (event) {
rowScope.cellEdit = true
angular.element(event.target).find('input').focus()
}
Its my goal to:
User clicks a table cell
Cell changes to "edit mode"
Give focus to the input element located inside the td.
Right now this is working as long as the user clicks inside the td element but not on the span element:
console.log(angular.element(event.target)) #--> [td...] (as desired)
However if the user clicks on the span element within the td:
console.log(angular.element(event.target)) #--> [span...]
In this use case assigning focus does not work. I was hoping to access the parent element of the span doing something like:
angular.element(event.target.closest('td'))
or
angular.element(event.target.parentNode)
But it appears when an element gets passed through via $event and accessed there is no parent context.
How can I either:
Prevent clicking the span element firing the td's ng-click
On click of span element pass through it's html parent
Changing:
angular.element(event.target)
to:
angular.element(event.currentTarget)
fixed my issue.
It seems to me using event.currentTarget is preferred to event.target in the majority of usage cases.
event.target.closest('td') won't work because event.target is a DOM element and it doesn't have method closest. You need to create a jQuery object to use this method.
Try to find closest td like this:
angular.element(event.target).closest('td')
In Angular 7.x
myClickHandler($event) {
this.selectedElement = <Element>$event.target.closest('.list-item');
}
html:
<div class="list-item" (click)="myClickHandler($event)">...</div>
I'd like to add a nice light yellow highlight to the table row that the user is interacting with. They click on an 'A' link with an 'onclick' function call that uses jquery to do stuff (not important). The onclick is in an 'A' tag and in a table cell 'TD'.
Here is the table cell:
<td>
<a href="javascript:void(0);"
onclick="deleteSchedule('Ajax/Admin_Delete_Schedule.cfm?SID=12345');"
title="Delete User"><img src="images/Delete_x16_.png" border="0"></a>
</td>
How do I get the reference for the table row and then set the background color?
Do I need to give each table row a unique ID?
Since the answers are so detailed and excelelnt, I'll add this:
I'd like to do this within my function but I'm not sure how to do it with 'this'.
Thanks!! and OMG! stackoverflow is the greatest!!!
I could not get the below closest or parent examples to work but I did get this to work:
$(".rowClick").on("click", function() {
$(this).closest("tr").css('backgroundColor', '#FFFF99');
});
and of course I added the class 'rowClick' to the 'A' tag. The problem now is when the user clicks on another row the result is two rows highlighted. Any suggestions to remove the highlight from the previously selected row. (I'm guessing to change the background color on all the table rows then set the one clicked on.) - Thanks Again!
I recommend giving the anchors a class name, ie "rowClick", and use JavaScript to toggle a class to the TR.
<tr>
<td>
...
<a class="rowClick">
...
</td>
</tr>
A CSS definition:
.bgYellow{ background-color: #FFFF00; }
And here's an example using jQuery:
$(".rowClick").on("click", function() {
$(this).closest("tr").addClass("bgYellow");
});
Depending on what you're doing, you can modify the function to instead toggleClass or other misc. options.
First of all, do not use an inline onclick method for this. Set up a proper jQuery event delegation function. So do something like this:
$(function(){
$('td a').click(function(e){
// 'e' refers to the event target here
var row = $(e.target).closest('tr');
// Insert whatever color value where yellow is
$(row).css('backgroundColor', 'yellow')
})
})
Even better would be to create a css class like
.tr-highlighted { background: yellow; transition: 200ms linear; }
Then add/remove the class with the class toggle function
$(function(){
$('td a').click(function(e){
// 'e' refers to the event target here
var row = $(e.target).parent();
// Insert whatever color value where yellow is
$(row).toggleClass('tr-highlighted')
})
})
If you must use an inline onclick declaration, the above should still apply, however you will need to access this within your function to refer to the event target, instead of e being passed as an argument.
Alternatively, you can do this with no JS at all if you only want it highlighted while the person is hovering over the table row
tr:hover { background: yellow; transition: 200ms linear; }
To accomplish this, you can use the jQuery .closest() function.
$("td").click(function(e){
$(e.target).closest("tr").css("background-color","yellow");
$(e.target).closest("tr").siblings().css("background-color","white");
});
This code in plain English would be something like:
For each table cell that is clicked:
Find the nearest row and change its background color to yellow.
Find all of the other rows in the table and change their background colors to white.
http://jsfiddle.net/ogzankse/2/
EDIT: I changed the code to better reflect your situation. Instead of attaching the click event listener to the row itself, I added anchor tags inside of each row and attached the listener to that. I added a class to the anchor tag so that anchors outside of the table are ignored. The code now searches for the <td> that the clicked <a> tag is inside of, and then finds the nearest row and applies the CSS. The code is now:
$("a.intable").click(function(e){
$(e.target).parent().closest("tr").css("background-color","yellow");
$(e.target).parent().closest("tr").siblings().css("background-color","white");
});
http://jsfiddle.net/ogzankse/3/
I have been trying for over a week now to slideToggle a table row when the 'more info' button is clicked but nothing seems to be working at all.
I'm new to Jquery so if anyone ca help me slideToggle the 'more-info-1', 'more-info-2', 'more-info-3' tr tags. the main problem is that those id's are created dynamically through php and I don't understand how to select them in Jquery - like using 'more-info-' or something.
I would like it to work like this example:
Here minus the iframes of course.
The user will click the 'more info' button and then the 'more-info-' tr will slide down.
Here is the page source: (I don't know how to insert HTML properly on Stack OverFlow, is there a special way of doing it - the code button does not work properly with HTML)
html
div id="output-listings"
div class="main-info"
table class="listings"
tbody
tr id="more-info-1" class="mi-1"
td
div id="more-1" class="more-information"/div
/td
/tr
tr id="main-info-1"
tdLeftlane News/td
tdwww.leftlanenews.com//td
tda id="link-1" class="more-info-link" href="#"More info/a/td
/tr
tr id="more-info-2" class="mi-2"
td
div id="more-2" class="more-information"/div
/td
/tr
tr id="main-info-2"
tdMotor Authority/td
tdwww.motorauthority.com/ /td
tda id="link-2" class="more-info-link" href="#"More info/a/td
/tr
tr id="more-info-3" class="mi-3"
td
div id="more-3" class="more-information"/div
/td
/tr
tr id="main-info-3"
tdAutoblog/td
tdhttp://www.autoblog.com//td
tda id="link-3" class="more-info-link" href="#"More info/a/td
/tr
/tbody
/table
/div
/div!--end output-listings--
/html
I would greatly appreciate the help.
Though craig's response works, you can limit your code and allow jquery to grab all of your TR elements within a certain scope, and parsing out the id as he suggested, etc.
$(".listings tbody tr").each(function(index) {
// hide by default
$(this).css({'display': 'none'});
// set the onclicks
$(this).click(function() {
// your dosomething can change your appearance
dosomething(the_id_you_parse_out);
});
});
Not sure if thats working code, I just threw it together so you could get the gist of how to use jquery's selector.
From a quick glance it looks like you want something like this.
$('#link-1').click(function(){
$('#more-info-1').slideToggle()
})
You can also generalize this script to work with all three by changing how the classes are set up, or by having the inner function parse the number of th link that is clicked and feed that into the inner jQuery call:
$('.more-info-link').click(function(){
var id = $(this).attr('id');
var num = id.substr(id.length-1,1);
$('#more-info-'+num).slideToggle();
})
To keep the trs from being visible add style='display:none' to them.
Depending on whether you need to assign a specific id to your elements for another purpose, you can actually do this without needing to give individual id's.
In this example, on load we first hide any tr that have the class toggleable. Then we tell jQuery to jump up the dom a couple of levels, and hide the next tr - this removes the need to call an id.
Example jQuery for this:
$(document).ready(function(){
$("#tableToggle tr.toggleable").hide();
$("#tableToggle .tableToggleButton").click(function(){
$(this).parent().parent().next('tr').slideToggle();
});
});
Example modified table:
<table id="tableToggle">
<tbody>
<tr>
<td><div class="tableToggleButton">More info 1</div></td>
</tr>
<tr class="toggleable">
<td>Main info 1</td>
</tr>
<tr>
<td><div class="tableToggleButton">More info 1</div></td>
</tr>
<tr class="toggleable">
<td>Main info 1</td>
</tr>
</tbody>
</table>
Since jquery code usually executes only when the DOM is ready, you'll always see the TR's even if only for a millisecond until your js code hides it if you don't use CSS initially to hide it.
So most of the contributors here probably answered your question. I'd just like to add that you could initially hide the TR's using CSS and then use JS to do the rest.
A good rule of thumb is to try and get your "default" pageview by only using CSS, and then add the rich functionality with the jquery code. Or at least that's what I'd do.