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
Related
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");
});
I have some <tr> elements with unique IDs.
<tr id="683535">some code</tr>
<tr id="683536">some code</tr>
<tr id="683537">some code</tr>
I want users to click on <tr>, after what a js function will be called. And I need to get this ID inside of current function without using events like <tr onclick="". Is this even possible?
You could do
$('tr').on('click',function(){
var id = $(this).attr('id');
});
In your event listener you should have a variable for the event.
Example:
$("body").on("click", "tr", function(e){
var row = $(this);
console.debug(row); //Should print clicked TR
console.info(row.attr("id")); //Should print the ID
});
If you don't want events, than your only way to interact with browser is classic hyperlink with <a> tag, where you can also include js functions like do stuff with your uid so you can simply generate such hrefs for each row inside your row generator.
In my rails app, I am loading a table from an #results variable such that each table row is a #result. For each #result table row I'm looking to have buttons associated with that #result. I'm trying to use a Javascript eventlistener for each button and then listen for the event in the js.erb file
When running the app, it looks like only the first row of button has the event listener, how can I fix this?
Also, how would I be able to pass my #result to my Javascript so I can utilize parts of that object?
I'm trying to do this through Javascript as I'd like to copy something in to the clipboard and save a file onto the computer.
js.erb
var copyTextareaBtn = document.querySelector('.button1');
copyTextareaBtn.addEventListener('click', function(event) {
# work with the #result that was clicked over here
});
html.erb
<% #results.each { |result| %>
<tr>
<td><%= result[:id] %></td>
<td>
<button class="button1"> B1 </button>
<button class="button2"> B2 </button>
<button class="button3"> B3 </button>
</td>
</tr>
<% } %>
You can indeed add an event listener to every element. The issue is document.querySelector will return the first first matched element. To get all of them, you would use document.querySelectorAll. We could rewrite your JavaScript to:
var btns = document.querySelectorAll('.button1');
Array.prototype.forEach.call(btns, function addClickListener(btn) {
btn.addEventListener('click', function(event) {
// code here to handle click
});
});
Note that querySelectorAll returns a NodeList which is like an array but unfortunately not an array. So it doesn't have forEach and similar methods found on the Array class. Thus the work around above to iterate over the nodes by using forEach from Array.prototype.
However, a much better approach is to listen for events up at the parent element or container for your form or at the document level. Events bubble up so you can listen to the click event once and filter to only the type you want to respond to. That would be one event listener instead of N (where N is the number of buttons).
The problem is you incremented the numbers of each className like button1, button2 and called in javascript only class button1 in order to call all button1's you need to give class button1 to each of your buttons in HTML.
EDIT: Try the code below then.
var button1 = document.getElementsByClassName("button1");
Object.keys(button1).map( function (key) {
var button = button1[key]
button.addEventListener("click", function(){
alert("button1")
});
});
<tr>
<td colspan="2">
<div>
<table id="dataTable">
<tbody>
<tr></tr>
<tr id="row_1"></tr>
<tr id="row_2"></tr>
<tr id="row_3"></tr>
</tbody>
</table>
</div>
</td>
</tr>
How can I get the value of a id in tr using jQuery? I have tried .attr but failed.
var row = jQuery('<tr>').attr("id", "row_" + item.autoID);
row.append(jQuery('<td>').append(jQuery('<input>').attr('type', 'checkbox', 'javascript:deleteChecked(' + item.autoID + ');').attr('id', 'check_id_')));
<input type="button" value="Delete" id="delete_check" disabled onclick="deleteChecked()"/>
I'm trying to get the tr attribute 'row_' + id. I have a checkbox. If you select the checkbox and then hit delete. It should delete the row with the specific id or all the checked rows.
So far I have got:
jQuery(document).on('click', '#check_id_', function(id){
jQuery('#delete_check').attr("disabled",!jQuery('#check_id_').is(":checked"));
//var row = jQuery(this).closest('tbody').find('tr').attr('id');
// console.log(row); //doesn't work
});
function deleteChecked(id){
//grab the checked row ids
}
Any help appreciated.
If I understand your requirement correctly, I would suggest approaching this problem in a slightly different way.
You simple cannot have duplicate IDs in your HTML. ID lookups use a fast lookup dictionary that can only store one element per id value so only the first is ever found.
Avoid using inline event handlers (like onclick="") at all costs in jQuery. It separates the handler registration from the handler response for no benefit and does not allow some of the additional cool event features jQuery provides (e.g. multiple handlers).
Use delegated event handler for your delete operations. This simplifies the HTML and allows for dynamic elements/rows in a far simpler way.
The way your question reads, it seems odd to use checkboxes instead of buttons for the delete. Use buttons instead unless you have good reason not to.
The rows do not need ID's unless those IDs are used for some other purpose. Just delete the row closest to the delete button that is clicked.
Use the $('<htmltag>', {'prop': 'value', 'prop2', 'value2'}) syntax to create new elements with properties. It is shorter and easier to read.
So, putting all that together, you get the following to create a new row:
var row = $('<tr>', {
"id": "row_" + item.autoID,
text: "NEW ROW"
});
row.append($('<td>').append($('<input>', {
'type': 'button',
'value': 'X',
'class': 'deleteme'
})));
$('#dataTable').append(row);
and this simple code to delete the row that has its deleteme 'X' button pressed:
$('#dataTable').on('click', '.deleteme', function(){
$(this).closest('tr').remove();
});
This is a delegated event handler. It delegates responsibility for listening for the click event to a non-changing ancestor element. When a click event bubble up to that element, it then applies the jQuery selector (in this case the class deleteme) and then runs your callback function against any matching elements that caused the event in the first place. The upshot is that the deleteme buttons only need to exist at event time for this to work.
Clean and simple.
JSFiddle: http://jsfiddle.net/TrueBlueAussie/k5rh82cz/
Now if you actual aim is different, you need to explain how you want it to appear too :)
To iterate the rows with checked checkboxes in them and fetch their ID's, something like this should do the trick:
$('#dataTable')
.find('input[type="checkbox"]:checked')
.closest('tr')
.each(function(ind, ele){
var id = $(ele).attr('id');
//do something with the id here
});
See this demo fiddle
HTH,
-Ted
I have a block of list element which I need to add when "Add" button is clicked.
HTML:
<li>
<div><h3 >User name sss updated this.
<input type="button" value="X" class="delete"/></br></h3>
</div>
SOME TEXT HERE
</li>
jQuery:
$(".delete").click(function(){
$(this).closest("li").slideUp();
});
$("#addPost").click(function(){
var inData = '<li><div><h3>User name sss updated this.<input type="button" value="X" class="delete"></input></br></h3></div>';
$("#midContent ul").append(inData+'Sarthak</li>');
});
This block has a delete button and a jQuery function attached to it.
If the block already exist on the page, its working fine.
But, when I add this block using jQuery append, the block is rendered rightly, but delete functionality does not work on newly added block.
Where I am going wrong?
Also, what will be the better way to add this block than hardcoding in JS code? (just by referring the element already on page by using id or class)
You need to delegate events for dynamically created DOM nodes. You can delegate to the parent div, or the document itself.
$(document).on('click', '.delete', function(e) {
//your code here
});
The second argument in the click handler is the selector for which you are attaching the click handler.
Further reading: http://learn.jquery.com/events/event-delegation/
Try to use the event .on('click',function(){}) on dynamically created elements.
$(".delete").on('click',function(){
$(this).closest("li").slideUp();
});
$("#addPost").on('click',function(){
var inData = '<li><div><h3>User name sss updated this.<input type="button" value="X" class="delete"></input></br></h3></div>';
$("#midContent ul").append(inData+'Sarthak</li>');
});
Also, why create a variable when you could append the code directly?