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.
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
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")
});
});
I am building a site which allows the user to download files from a folder on the server.
The files are pulled from a database and stored in a HTML table. Each row has a download button. I know i cant just put id='download'.
What would be the best way to handle a JavaScript function when the button is clicked.
Should i set something like download-214124
and then just put ("download-*") as the selector in jQuery?
As you said you can't use a common ID to all element since ID must be unique.
Instead you can use a common class to all the elements, then use a data-* attribute to store the id like
<button class="download" data-id="1235">Download</button>
then
$('.download').click(function(){
var id = $(this).data('id');
//do download code for id here
})
Note: If you are dealing with dynamic elements, then you will have to use event delegation to register the handlers like
$(document).on('click', '.download', function() {
var id = $(this).data('id');
//do download code for id here
})
Event binding on dynamically created elements?
HTML5 offers data-attribute that allows you to store data respective to the DOM element. This makes life super easy to hook up with JavaScript. jQuery has data() function to access data-attribute of the element.
You can do something like below.
HTML
<table>
<tr><td>
<p>file with id 1</p>
<button data-id="1">download</button>
</td></tr>
<tr><td>
<p>file with id 2</p>
<button data-id="2">download</button>
</td></tr>
<tr><td>
<p>file with id 3</p>
<button data-id="2">download</button>
</td></tr>
</table>
Javascript
$('button').on('click', function(e){
e.preventDefault();
var id = $(this).data('id');
alert('Do ajax request to download file with id ' + id);
});
Here is the jsfiddle for that.
If JavaScript is being used to build the HTML table, you can attach the event handlers at runtime without needing any IDs.
A good example of this would be when you're building an HTML structure by looping through an array of results via JavaScript. In such a case, you can use closures to maintain references to the result data that corresponds to particular HTML elements, and use that data when event handlers are invoked.
In the example below, the event handler that is attached to each button is able to directly call up the value property of a corresponding object in an array; we didn't need to add anything to the button element (neither an ID nor a data- attribute) to maintain that reference.
var dataResults = [{title:"One",value:1}, {title:"Two",value:2}, {title:"Three",value:3}, {title:"Four",value:4}];
var output = document.getElementById("output");
for (var i = 0, len = dataResults.length; i < len; i++) { // 1. Loop through results
var btn = document.createElement("button"); // 2. Create your HTML element(s)
btn.value = dataResults[i].title; // 3. Set HTML based on result values
btn.innerHTML = dataResults[i].title;
(function(result) { // 4. Use a closure to capture the current result item
btn.addEventListener("click",function() {
alert("You clicked button " + result.value);
}); // 5. Add an event handler that references the result item.
})(dataResults[i]); // (Pass the current result item into the function expression as a parameter)
output.appendChild(btn); // 6. Add your HTML to the page.
}
<div id="output"></div>
Of course, none of that is relevant if JavaScript isn't responsible for building the HTML in your application!
<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
so what I'm triying to achieve is that I want one element to append some other elements to div and change its ID attribute (or something similar).
i have tried something like this
$('#add3').click(function(){
$('#add3').attr("id", "add4");
$('.third_row1').append('something to append');
});
and also tried something like this:
$('#add').click(function(){
var vari = $("<div id='add2'>add another user</div>");
$('#add').remove();
$('.third_row1').append(vari);
$('.third_row1').append('something to append');
});
so clicking one button (like second example) has no effect on third, fourth ... n click
same thing with the second example
thanks in advance for help
UPD
ok, so here's how I generate selects which I want to append
<jsp:useBean id="obj1" class="com.Users" scope="page"/>
<div class="third_row1">
<select name="mySelect1" id="mySelect1">
<c:forEach var="item1" items="${obj1.items}">
<option>${item1}</option>
</c:forEach>
</select>
</div>
all I want to do is to add same select, but with different ids and names
Since elements IDs are changed dynamically, you should use delegated event handlers with .on().
For example:
$(document).on("click", "#add3", function() {
$('#add3').attr("id", "add4");
$('.third_row1').append('something to append');
});
If all these elements (#add, #add3) are inside page static element, it will be better to use this element instead of document for perfomance:
$("static_element_selector").on("click", "#add3", function() {
And just to note: since this inside event handler points to clicked DOM element, you can use this.id = "add4" instead of $('#add3').attr("id", "add4");. It is shorter and works slightly faster.