jQuery - Can not select a dynamic created element - javascript

Here is my HTML structure:
<table id="items" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<td> </td>
<td>Name</td>
<td>Description</td>
<td>Location</td>
</tr>
<tr>
<td>
<button type="button" class="btn btn-default btn-lg">
<span class="glyphicon glyphicon-plus"></span>
</button>
</td>
<td><input type="text" id="addName"></td>
<td><input type="text" id="addDescription"></td>
<td></td>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
</tfoot>
</table>
And here is my jQuery code:
function getTable(){
var args = new Object();
args.op = "getTable";
$.post("./service.php", args , function(data)
{
var dataObj = JSON.parse(data);
for(var i = 0; i<dataObj.length; i++){
$('table#items tbody').append("<tr class=\"items_tr\" id=\"item"+dataObj[i].sn+"\"><td>"+dataObj[i].sn+"</td><td>"+dataObj[i].name+"</td><td>"+dataObj[i].description+"</td><td>"+dataObj[i].belonged+"</td></tr>");
}
});
}
getTable();
$('tbody').children("tr").hide();
$("tbody tr").hide();
$("tr.items_tr").hide();
The Last 3 statements do not work at all.
Cannot select created <tr>s.
Why and how can I select them?
$("tr").hide();
This one hides only <tr>s inside <thead>, things that have already been created.
more questions - How about .each() function?
I want to bind a click event on each td tag, and I failed again..
How to iterate all new added <td>s?

For the last three statements to work, the elements have to exist. You are executing those methods before the Ajax response was received. Move the calls inside the $.get callback, after you added the elements (i.e. after the loop).
Kind of related (because they explain how async stuff works):
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
How do I return the response from an asynchronous call?

If you are trying to hide these elements on an event, add them to an event handler for example:
$(document).ready( function () {
getTable();
$(element).on('click', function () {
$('tbody').children("tr").hide();
$("tbody tr").hide();
$("tr.items_tr").hide();
});
)};
If you are trying to hide these elements right after call the getTable function then add the 3 functions to the $.post success function
code should look like:
function getTable(){
var args = new Object();
args.op = "getTable";
$.post("./service.php", args , function(data)
{
var dataObj = JSON.parse(data);
for(var i = 0; i<dataObj.length; i++){
$('table#items tbody').append("<tr class=\"items_tr\" id=\"item"+dataObj[i].sn+"\"><td>"+dataObj[i].sn+"</td><td>"+dataObj[i].name+"</td><td>"+dataObj[i].description+"</td><td>"+dataObj[i].belonged+"</td></tr>");
}
$('tbody').children("tr").hide();
$("tbody tr").hide();
$("tr.items_tr").hide();
});
}
getTable();

Hi jquery binds events on document.ready if there are elements which are created after document.ready then you need to register those elements for those events using .bind() function of jquery. But be sure first unregister alredy attached elements. using unbind();
Refer bind and unbind functions.

Related

Uncaught ReferenceError: Function is not defined using external js file

I have a table of rows with contact details and a call button in every row, which when clicked should call the customer.
I am using onclick on call the function defined in external js file (I know not the best practice and potentially due to outside scope, but I am passing the phone number as well)
I am getting error Uncaught Referenceerror: function is not defined
https://jsfiddle.net/e1z25y3w/3/
<table>
<th>
<td>#</td>
<td>Name</td>
<td>City</td>
<td>Phone Number</td>
<td>Call</td>
</th>
<tr>
<td>1</td>
<td>John</td>
<td>Melbourne</td>
<td>+61123456789</td>
<td><a role="button" onclick="callPhone('+61123456789')">Call</a></td>
</tr>
<tr>
<td>2</td>
<td>Tanya</td>
<td>Sydney</td>
<td>+61987654321</td>
<td><a role="button" onclick="callPhone('+61987654321')">Call</a></td>
</tr>
</table>
Jquery 3.4.1 included at the bottom of the page
javascript file also included after jquery
$(function () {
//const phoneNumberInput = document.getElementById("phone-number");
function callPhone(phonenumber) {
alert(here);
log("calling phone number " + phonenumber.value);
//e.preventDefault();
phoneNumberInput = phonenumber;
makeOutgoingCall();
}
});
What is the best way to execute this?
because the "callPhone" function isn't in the global scope, so when you to try call it, will give "callPhone is not defined".
1- first solution is to write it on the global scope.
function callPhone(phonenumber) {
console.log('running')
}
https://jsfiddle.net/mena234/rakeopg2/9
2- The second solution is to store it in a global variable.
let referanceStore = null
$(function () {
//const phoneNumberInput = document.getElementById("phone-number");
function callPhone(phonenumber) {
// any code here...
console.log('running')
}
referanceStore = callPhone
});
and use referancecStore to call your function
ex:
referanceStore('+61987654321')
https://jsfiddle.net/mena234/z391euhm/7
3- Third solution is to use the javascript click event and dataset instead.
https://jsfiddle.net/mena234/z391euhm/22/
That is one of the reasons why you shouldn't use an inline event handler (onclick="callPhone('+61123456789')")
Your inline event handler can't find the function callPhone(phonenumber) because it is defined within the anonymous callback function passed to your $( ... ) so it is only visible in it.
So the first idea of how to solve it would be to make the callPhone globally visible. This however is a bad idea as it pollutes the global namespace.
You instead should get rid of your inline event handlers and attach the event handler within the scope where callPhone is defined, using e.g. event delegation and data attributes:
$(function() {
function callPhone(phonenumber) {
console.log("calling phone number " + phonenumber);
}
// use event delegation to listen a click on elements with the data-action attribute beeing callPhone
$(document).on('click', '[data-action="callPhone"]', function(evt) {
// get the contents of the data attribute phone-number
// and pass it to the callPhone function
callPhone($(evt.target).data().phoneNumber)
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td>#</td>
<td>Name</td>
<td>City</td>
<td>Phone Number</td>
<td>Call</td>
</tr>
<tr>
<td>1</td>
<td>John</td>
<td>Melbourne</td>
<td>+61123456789</td>
<td><a role="button" data-phone-number="+61123456789" data-action="callPhone">Call</a></td>
</tr>
<tr>
<td>2</td>
<td>Tanya</td>
<td>Sydney</td>
<td>+61987654321</td>
<td><a role="button" data-phone-number="+61987654321" data-action="callPhone">Call</a></td>
</tr>
</table>

Button click only works on one button out of appended list of buttons

JQUERY
i have 4 buttons that are pulled from a database and appended to a list, but only this first appended button works. All the rest wont do anything.
function getaplist(){
$.getJSON('/geticsassignments',
function(data){
console.log(data)
for (var i = 0; i < data.length; i++){
var assign = ("<tr><th><button class='btn btn-warning' id='getaptext'
value=''>"+ data[i].aparatus +"</button></th></tr>")
$('#aptbody').append(assign)
}
$('#getaptext').on('click', function(){
$("#getaptext").removeClass("btn btn-warning").addClass("btn btn-danger")
var aparatus = $(this).text()
alert(aparatus)
$.getJSON('/sendap',{
}, function(data){
console.log(data)
})
})
})
}
getaplist()
<div id='aplist'>
<table class="table">
<thead>
<tr>
<th><p style="text-align: center;">Aparatus</p></th>
</tr>
</thead>
<tbody id='aptbody'>
</tbody>
</table>
</div>
There are two problems with your code.
1- ID must be unique on the DOM.
2- You're trying to add event listeners on dynamically created elements which doesn't work the way you are trying to do.
Solution :
First Make sure the id are unique. And add event listeners with class name for example
$(document).on('click','.btn',function(){
$(this).removeClass("btn btn-warning").addClass("btn btn-danger")
var aparatus = $(this).text()
...
})
This will work for all the elements event which are added dynamically on your page
You're using the same id, getaptext, for every button. The id attribute has to be unique. You'll have to make the ids different, or use something else like a common name or class.

jQuery Click Event for Dynamically Created Links Not Working

I am displaying a list of users in a table. Then, I have a button to allow a user to view more details about a specific user. However, I am having a hard time getting the ID for the user that is clicked on. I am not sure why it's not working. What am I doing wrong? I tried several options, and none of them work.
Partial code of how data the links are generated in my view.
if (Model != null) {
if (Model.Count() > 0) {
foreach (var item in Model) {
<tr>
<td><div class="centerText">#item.UserID</div></td>
<td><div class="centerText">#item.FirstName</div></td>
<td><div class="centerText">#item.LastName</div></td>
<td><div class="centerText">Details</div></td>
</tr>
}
}
}
My jQuery function
$(function () {
$('.Detail').on('click', function (event) {
var dt = $(this).attr('id');
console.log('dt');
});
});
I also tried it this way:
if (Model != null) {
if (Model.Count() > 0) {
foreach (var item in Model) {
<tr>
<td><div class="centerText">#item.UserID</div></td>
<td><div class="centerText">#item.FirstName</div></td>
<td><div class="centerText">#item.LastName</div></td>
<td><div class="centerText">Details</div></td>
</tr>
}
}
}
Here is the Javascript function that I created. It kept giving
function test(e){
console.log(e);
};
I get this error:
0x800a1391 - JavaScript runtime error: 'test' is undefined
updated on 11/21/15 #7:53 AM EST
I removed the for loop and created a single cell with 1 click button. The click event is not registered. I tried it with 'on', 'live', and 'delegate' with no success.
<div class="table table-responsive" style="width:100%;height:100%;">
<table class="table table-bordered table-condensed table-striped">
<thead>
<tr>
<th><div class="centerText">Date Created</div></th>
<th colspan="2"></th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="6"><div class="centerText">Detail</div></td>
</tr>
</tbody>
</table>
</div>
#section Scripts {
<script type="text/javascript">
$('.table tbody tr td div').delegate('.Detail','click', function ()
{
console.log('you click me');
});
</script>
}
You are trying to get the attribute id which doesn't exist. Use below to get data-id
$(function () {
$('.Detail').on('click', function (event) {
var dt = $(this).data('id');
console.log(dt);
});
you can also use
var dt = $(this).attr("data-id");
Second one (remove var):
function test(e){
console.log(e);
};
Partial code of how data the links are generated in my view. change id instead of data-id.
if (Model != null) {
if (Model.Count() > 0) {
foreach (var item in Model) {
<tr>
<td><div class="centerText">#item.UserID</div></td>
<td><div class="centerText">#item.FirstName</div></td>
<td><div class="centerText">#item.LastName</div></td>
<td><div class="centerText">Details</div></td>
</tr>
}
}
}
My jQuery function
$(function () {
$('.Detail').on('click', function (event) {
var dt = $(this).attr('id');
console.log('dt');
});
});
I also tried it this way:
if (Model != null) {
if (Model.Count() > 0) {
foreach (var item in Model) {
<tr>
<td><div class="centerText">#item.UserID</div></td>
<td><div class="centerText">#item.FirstName</div></td>
<td><div class="centerText">#item.LastName</div></td>
<td><div class="centerText">Details</div></td>
</tr>
}
}
}
Here is the Javascript function that I created. It kept giving. (Remove var before function).
function test(e){
console.log(e);
};
Here is how I reproduced your problem with JavaScript runtime error: 'test' is undefined.
Scenario
I guess that you've defined the function test probably in your jQuery DOM ready function $(function(){...}.
If so, the function test is undefined because by the time the DOM is loading, AND the event handlers on DOM elements are being registered (in your case the onclick in the link), the function test is not yet known to the document, and therefore undefined.
Solution
Try to move your test function's declaration outside of jQuery's DOM ready function. That is,
$(function(){
//code that has to run once the DOM is ready
});
function test(e){
console.log(e);
}
DEMO
I found what was causing the problem. I had a modal popup within the form. I was looking to add a textarea, so I added this code '
<textarea name="reasonForArchiveText" id="reasonForArchiveText" />
That's the code that was preventing me from getting the click event. As I was playing around with the code, I commented out the modal popup, and things started to work. Then, I commented section of the modal until I finally found the culprit. The minute that I commented it out, the code works.

Select div text next to clicked button within table row

Here is a sample table.
<table class="table table-bordered">
<tbody>
<tr>
<tr>
<td>Stuff<div id="ParentID" style="display:none">145689</div></td>
<td><button class="btn btn-small">Send</button></td>
</tr>
</tbody>
</table>
I want to select the text within the div tag where id=ParentID that is closest to that button clicked. I will have multiple row in the future so it has to be unique to that row.
I have right now
var qry = $(this).closest('#ParentID').text();
Doesn't work obviously
This is how it can be done:
$(".btn").on("click", function() {
var text = $(this).closest("tr").find("div").text();
// ...
});
Note that elements should have unique IDs, so there can't be several <div> elements with ID "ParentID". I hope you use it as example only.
try this
$(".btn").on("click", function() {
$(this).parent('tr').find('div#ParentID').text();
});
$('button').click(function(){
var dataYouWant = $(this).parent().find('div').html();
});
You could do this, which gives the result:
$('.btn').click(function() {
alert($(this).parent().prev().children('div').text());
});
Try it out here: http://jsfiddle.net/YLcjf/2/
(I guess you should benchmark all these solutions. Not sure if 'find' has some greedy algortithm penalty associated with it)
$("button").click(function(){
alert($(this).parents("tr")
.find("div#ParentID").text());
});
JS Fiddle to test: http://jsfiddle.net/leniel/suRfG/

jQuery remove elements after creation

I'm building a jQuery sortable list where the user can add items from a table, drag and sort and/or remove them. I can add and sort no problem, but I can't work out how to remove an item element after it has been added. I'm relatively new to js / jQuery, so I have a feeling there's something new to learn here about how it works!
I'll leave out the ui.sortable stuff here as I'm only concerned with removing items..
<table>
<tr>
<td><a class="addrelease" href="#" cat_id="1">add</a></td>
<td>Item 1</td>
</tr>
<tr>
<td><a class="addrelease" href="#" cat_id="2">add</a></td>
<td>Item 2</td>
</tr>
</table>
<div id="list"></div>
<script>
$("a.addrelease").click(function (e) {
e.preventDefault();
cat_id = $(this).attr('cat_id');
remove_str = " remove";
str = cat_id + remove_str;
$(str).appendTo("#list").hide().fadeIn();
});
$("a.remove").click(function (e) {
alert("This function doesn't seem to be called");
$(this).parent().remove(); //Doesn't happen..
});
</script>
I'm guessing that javascript doesn't recognize the new generated items - but I'm not sure, so I'm not sure where to start fixing it
Cheers
You should use live function to attach events to dynamically added elements.
Try this to bind click event to a.remove elements:
$("a.remove").live("click", function (e) {
alert("This function doesn't seem to be called");
$(this).parent().remove(); //Doesn't happen..
});
You're absolutely right, javascript won't recognise new items.
jQuery selectors will normally only match against elements currently in the document. When you use $("a.remove").function(), jQuery builds a list of nodes matching "a.remove", then calls function() on each of them.
The .live() function is special, and doesn't attach events directly to elements - instead, events bubbling up to the top of the DOM are evaluated to see if they match the selector.
IMHO, the best approach is to bind the remove handler when you create the new list entry:
str = cat_id + remove_str;
var remove = $(str);
remove.appendTo("#list").hide().fadeIn();
remove.click(function(e) { .... })
Disclaimer: Typed late at night & not tested!
Here is my answer of how I think you should modify your code:
http://jsfiddle.net/RY5CP/
<table>
<tr>
<td><a class="addrelease" href="#" rel="1">add</a></td>
<td>Item 1</td>
</tr>
<tr>
<td><a class="addrelease" href="#" rel="2">add</a></td>
<td>Item 2</td>
</tr>
</table>
<div id="list"></div>
<script type="text/javascript">
$("a.addrelease").click(function(e) {
e.preventDefault();
var catId = $(this).attr('rel');
var itemName = $(this).closest('td').next('td').text();
var newItem = '<p>' + catId + ' ' + itemName + ' remove';
$(newItem).appendTo('#list').hide().fadeIn();
});
$("a.remove").live('click', function(e) {
$(this).parent('p').remove();
});
</script>
It's not valid to use cat_1, cat_2 as HTML attributes. You can use the rel attribute if you need to have a specific value to be associated to your items
Use the live() method to have the click event handler automatically attached to items dynamically created

Categories