Cannot delete element created by jQuery [duplicate] - javascript

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed last year.
I use SignalR to push notifications. To be simple, I have created some elements using the following jQuery code:
<script>
$(document).ready(function(){
var connection = new signalR.HubConnectionBuilder().withUrl("/signalRServer").withAutomaticReconnect().build();
connection.start();
connection.on("ReceiveNotification", function(sender, workCenter, serviceType, notificationId){
event.preventDefault();
if($('#notifi-badge').length){
var currentNotificationCount = parseInt($('#notifi-badge').text());
$('#notifi-badge').text(currentNotificationCount + 1);
$('.notification-items').prepend('<li><a class="dropdown-item notification-item" style="font-family: vazir !important" Id="'+ notificationId +'" href="#">New '+ serviceType +' for '+ workCenter +' sent.</a></li>');
}else{
$('#notifi-badge').text('1');
}
});
});
</script>
and I use the following code to detect those created items:
<script>
$(document).ready(function(){
$('.notification-item').on("click", function(){
var selectedId = $(this).attr('Id');
var notificationBadge = parseInt($('#notifi-badge').text());
var formData = new FormData();
alert(selectedId);
.
.
.
</script>
SignalR works fine and I can push notifications. When I click those created elements, I expect to alert but it does not.

Listen to the click event bubbling up from .notification-item to the nearest parent that is present at runtime: see event delegation using .on(). Your issue is due to .notification-item being dynamically added and is not available at runtime, so no click event handler is bound to it.
Without looking at your markup, is it not clear which is the nearest parent that is present at runtime: in this case I can suggest listening to the click event at the level of the document instead:
$(document).on('click', '.notification-item', function(){ ... })
If the element .notification-items (the parent that you're appending elements to) is indeed present at runtime, then you can do this:
$('.notification-items').on('click', '.notification-item', function(){ ... })

The click event is not binded to new attached items(.notification-item).
To do so, you have to rebind events when each new items added:
call the event binding function after new element prepended:
<script>
$(document).ready(function(){
var connection = new signalR.HubConnectionBuilder().withUrl("/signalRServer").withAutomaticReconnect().build();
connection.start();
connection.on("ReceiveNotification", function(sender, workCenter, serviceType, notificationId){
event.preventDefault();
if($('#notifi-badge').length){
var currentNotificationCount = parseInt($('#notifi-badge').text());
$('#notifi-badge').text(currentNotificationCount + 1);
$('.notification-items').prepend('<li><a class="dropdown-item notification-item" style="font-family: vazir !important" Id="'+ notificationId +'" href="#">New '+ serviceType +' for '+ workCenter +' sent.</a></li>');
bindEvent();
}else{
$('#notifi-badge').text('1');
}
});
});
</script>
and declare bindEvent function
function bindEvent(){
$('.notification-item').unbind("click").bind("click", function(){
var selectedId = $(this).attr('Id');
var notificationBadge = parseInt($('#notifi-badge').text());
var formData = new FormData();
formData.append("notificationId", selectedId);
$.ajax({
type: "POST",
url: "/Page/DeleteNotification",
contentType: false,
processData: false,
data: formData,
success: function(response){
if(response.success){
$('#'+ selectedId +'').remove();
if(notificationBadge >= 1){
$('#notifi-badge').text(notificationBadge - 1);
}else{
$('.badge-notification').remove();
}
}else{
console.log("Error! Removing process failed.");
}
}
});
});
}

Related

jquery class selector yields unusable id

I am getting an id that is not addressable by jquery ("#"+id).something .
At document start I have a :
var g_justClicked = '';
$.ajaxSetup({
beforeSend:function(event){
if(g_justClicked) {
console.log('g_justClicked='+g_justClicked+' tagName='+$('#'+g_justClicked).tagName);
};
var wOffset = $('#'+g_justClicked).offset();
$('#loading').show();
},
complete:function(){
$('#loading').hide();
}
});
At document end I have another script (all elements with class spinner should set the global variable 'g_justClicked'):
$(document).ready(function () {
$('.spinner').click(function() {
g_justClicked = $(this).attr('id');
console.log('.spinner.click: g_justClicked='+g_justClicked);
});
This works fine, the variable is set and displayed correctly in ajaxSetup.
BUT: referencing it in tagName= or in wOffset = with
$('#'+g_justClicked).
results in
"TypeError: wOffset/tagName is undefined"
Note: all ids start with several characters, t.e. "boxshow12345" is a typical id.
What am I doing wrong?
I think was able to reproduce your scenario here: https://jsfiddle.net/mrlew/qvvnjjxn/3/
The undefined in your console.log is because you're accessing an inexistent jQuery property: .tagName. This property is only available to native HTML Element.
To retrieve the tag name from a jQuery Object, you should use: .prop("tagName"), or access the property accessing the native element with $('#'+g_justClicked)[0].tagName
So, if you change
console.log('g_justClicked='+g_justClicked+' tagName='+$('#'+g_justClicked).tagName);
to:
console.log('g_justClicked='+g_justClicked+' tagName='+$('#'+g_justClicked).prop("tagName"));
Will successfully log: g_justClicked=boxshow12345 tagName=BUTTON, as expected.
Note: In order to your logic work, you have to click .spinner first.
Your problem is that your ajax setup runs regardless of whatever you do in the click handler, and it runs before you even setup that handler. The initial value for g_justClicked is empty string, and this is what it tries to access in $('#'+g_justClicked), hence the error.
If you want to click the spinner and then pass the id to the beforeSend, do it like this:
$(document).ready(function() {
$('.spinner').click(function() {
var g_justClicked = this.id; //simplify this a bit
console.log('.spinner.click: g_justClicked=' + g_justClicked);
// call ajax
_setupAjax( g_justClicked );
});
});
function _setupAjax(g_justClicked) {
$.ajaxSetup({
beforeSend: function(event) {
if (g_justClicked) {
console.log('g_justClicked=' + g_justClicked + ' tagName=' + $('#' + g_justClicked).tagName);
};
var wOffset = $('#' + g_justClicked).offset();
$('#loading').show();
},
complete: function() {
$('#loading').hide();
}
});
}
UPDATE
If you don't want a separate function, just move your ajax setup into the click handler:
$(document).ready(function() {
$('.spinner').click(function() {
var g_justClicked = this.id; //simplify this a bit
console.log('.spinner.click: g_justClicked=' + g_justClicked);
// call ajax setup
$.ajaxSetup({
beforeSend: function(event) {
if (g_justClicked) {
console.log('g_justClicked=' + g_justClicked + ' tagName=' + $('#' + g_justClicked).tagName);
};
var wOffset = $('#' + g_justClicked).offset();
$('#loading').show();
},
complete: function() {
$('#loading').hide();
}
});
});
});
OK #mrlew.
Answer: I tried your .prop appoach, but still got "undefined". Now back to the roots:
The goal is to get the id of any element that was clicked to modify the busy indicators position, while ajax is running. Newly I am back to my original approach, without global variable and parameter passing:
$(document).ready(function () {
$('.spinner').click(function() {
_setupAjax();
});
});
which works, and:
function _setupAjax() {
$.ajaxSetup({
beforeSend: function() {
$('#loading').show();
wJustClicked = $(this).attr('id'); /// <- that doesnt work!
console.log("_setupAjax wJustClicked="+wJustClicked);
console.log('_setupAjax tagName=' + $('#' + wJustClicked).prop("tagName"));
....defining css based on id (no problem)..
which yields "undefined" twice. I tried so many ways to get that f.... id.
#mrlew
thanks a lot for your help. Meanwhile I found the solution. All trouble came from a timing problem. Here is what works (for all DIV, SPAN and IMG of class=spinner and having an id:
$(document).ready(function () {
_setupAjax();
$('.spinner').click(function() {
wJustClicked = $(this).attr('id');
if(wJustClicked == null) alert('Id missing on item clicked');
console.log('.spinner.click! id='+wJustClicked);
var wOffset = $('#' + wJustClicked).offset();
var xPos = Math.round(wOffset.left) + 8;
var yPos = Math.round(wOffset.top) + 4;
console.log(wJustClicked+' offset left='+wOffset.left+' top='+wOffset.top+' xPos='+xPos+' yPos='+yPos);
wDiv = 'loading';
$('#'+wDiv).css('left',xPos);
$('#'+wDiv).css('top',yPos);
});
and the js function:
function _setupAjax() {
$.ajaxSetup({
beforeSend: function() {
$('#loading').show();
},
complete: function() {
$('#loading').hide();
}
});
}
A strange thing remained (I have firebug installed), which I have solved with Math.round: the x and y position come overdetailed like 170.5134577 and 434.8768664 ?!?
I can live with that. But where does this pseudo precision come from?
Again thanks a lot to keep my hope upright.

javascript/jquery doesn't work in ajax

I have php page "Home.php", that present user posts(using ajax).
This is how I get the posts:
<script type="text/javascript">
function loadmore()
{
var val = document.getElementById("result_no").value;
var userval = document.getElementById("user_id").value;
$.ajax({
type: 'post',
url: 'fetch.php',
data: {
getresult:val,
getuserid:userval
},
success: function (response) {
var content = document.getElementById("result_para");
content.innerHTML = content.innerHTML+response;
// We increase the value by 2 because we limit the results by 2
document.getElementById("result_no").value = Number(val)+10;
}
});
}
</script>
<div id="content">
<div id="result_para">
</div>
</div>
In every post, there is a like button(which also uses ajax). This is how I save the likes:
<script type="text/javascript">
function likethis(likepostid)
{
$.ajax({
type: 'post',
url: 'fetchlikes.php',
data: {
getpostid:likepostid
},
success: function (response) {
}
});
}
</script>
Before I used ajax to present posts, all worked well. But now when I press the like button, it DOES save the like, BUT the javascript/jquery doesn't work. I tried to make alert when I pressed the LIKE button, but it didn't work.
This is the index.js code(the javascript). It add +1 likes, when the user press the button:
$('.btn-counter_likecount').on('click', function(event, count) {
event.preventDefault();
//alert("hello");
var $this = $(this),
count = $this.attr('data-count'),
active = $this.hasClass('active'),
multiple = $this.hasClass('multiple-count_likecount');
$.fn.noop = $.noop;
$this.attr('data-count', ! active || multiple ? ++count : --count )[multiple ? 'noop' : 'toggleClass']('active');
});
EDIT fetchlikes.php:
<?php
mysql_connect('localhost','root','');
mysql_select_db('blabla');
$postid=$_POST['getpostid'];
mysql_query("UPDATE user_post SET likes_count=likes_count+1 WHERE post_id='$postid'");
?>
Because your posts are being loaded dynamically, the javascript where you bind the event is running before the posts are actually loaded, thus the buttons don't exist when you try to bind the event. You can use delegated events in jQuery to handle this.
Your previous code
$('.btn-counter_likecount').on('click', function(event, count) {
....
});
New Code
$('#result-para').on('click','.btn-counter_likecount',function(event, count) {
....
}
This way the event will actually be bound to a parent element that already exists when jQuery's ready() function runs. This way, the event handler checks for matching elements when the event is fired rather than when the event is bound.
For further reading, look into jQuery's delegated events

Prevent previously requests on click

I have list of tables,
<table id="<%#DataBinder.Eval(Container.DataItem, "Certificate")%>" class="tbl_evenSearchResultRow" onmouseover="this.className='ResultGridRowSeleted'" onmouseout="this.className='tbl_evenSearchResultRow'" onclick="return SynopsisWindowOpen(this)">
onclick of each i use next function:
function SynopsisWindowOpen(obj) {
var title = $(obj).find("strong[name='title']").html();
var isParentools = 0;
if (window.location.href.indexOf('recent_releases.aspx') > -1)
isParentools = 1;
var url = "/ratings/Synopsis.aspx?logoonly=1&Certificate=" + obj.id + "&Title=" + encodeURIComponent(title) + "&parentools=" + isParentools;
$("#ratingModal").on("show.bs.modal", function (e) {
$.ajax({
url: url,
cache: false,
dataType: "html",
success: function (data) {
$("#ratingModal").find(".modal-body").html(data);
}
});
});
$("#ratingModal").on("hide.bs.modal", function (e) {
$(this).find(".modal-body").html('');
});
$("#ratingModal").modal('show');
return false;
}
By url i render body of modal : i get certificate from request.query and according to it render body
LoadSynopsisContent(Request.QueryString["Certificate"], Request.QueryString["parentools"]);
Problem : when i click at first - everything seems to be good, on second click in modal body firstly rendered body of first click and then of second click. And so on.
I don't know where is problem.
Firstly i use jquery load function, but then i change to simple ajax call with disabled caching.
Move the all event bindings to outside of the function and everything should work fine.
Thus, these parts should not be inside the function:
$("#ratingModal").on("show.bs.modal", ....);
$("#ratingModal").on("hide.bs.modal", ....);
Here is one way you could organize your code:
var url; //a global variable ... not a good idea though
function SynopsisWindowOpen(obj) {
....
url = .....
}
$(function() {
$("#ratingModal").on("show.bs.modal", ....);
$("#ratingModal").on("hide.bs.modal", ....);
});
However, the way would be to not use inline JavaScript but to take advantage of the power of jQuery to separate structure from behavior.
UPDATE
Instead of using a global variable url you can store the new url in a data attribute of the modal. Then you can get it from there when the modal opens.
In the function:
//calculate the url
var url = .....
//store the url in the modal
$('#ratingModal").data('table-url', url);
In the modal event handler:
$("#ratingModal").on("show.bs.modal", function(e) {
//retrieve the url from the modal
var url = $(this).data('table-url');
//use the url
$.ajax({ url: url, .... }):
});

Issue with .on() method

I am trying to make an MVC for training purposes and I am following a tutorial for that which is rather old. The implementation in the tutorial was made using live() but I decided to use jQuery 2.1.1 and have to implement on() method. I made a small use case for clarification.
I can insert new elements on the page while adding them in the DB
I can delete preloaded elements which existed in the DB at page load both from the DB and DOM
I can not remove elements which are added live neither from the db nor the DOM.
this is my entire code regarding that.
$(function(){
$.get('dashboard/xhrGetListings', function(o){
for (var i = 0; i < o.length; i++ )
{
$('#listInserts').append('<div>' + o[i].text + '<a class="del" rel="' + o[i].id + '" href="#">x</a></div>');
}
$('.del').on("click", function() {
delItem = $(this);
var id = $(this).attr('rel');
$.post('dashboard/xhrDeleteListing', {'id': id}, function(o) {
delItem.parent().remove(); // THIS IS NOT EXECUTED AT ALL
}, 'json');
return false;
});
}, 'json');
//Not necesarly relevant, it just helps for code clarity
$('#randomInsert').on("submit", function() {
var url = $(this).attr('action');
var data = $(this).serialize();
console.log(data);
$.post(url, data, function(o) {
$('#listInserts').append('<div>' + o.text + ' <a class="del" rel="' + o.id + '" href="#">X</a></div>');
}, 'json');
return false;
});
});
Another issue that I'm not focussing on at this point is that if I delete the parent inside the $.post method (as shown in the code above) it's not deleted, only if I move that line outside of the post method. Any clarification on that would be also very appreciated.
Use event delegation and event.preventDefault() it stops the default action
$('#listInserts').on("click", '.del' , function(event) {
event.preventDefault();
// your code come here
});

jQuery: event not being triggered on ajax-loaded elements [duplicate]

This question already has answers here:
Events triggered by dynamically generated element are not captured by event handler
(5 answers)
Closed 8 years ago.
I have a simple front-end in jQuery/HTML5 (+ backend-generated code which does not bring the issue, so I will omit it). The currently-in-use jQuery version is 1.8.3 and no version collision exists (i.e. no other jQuery version is loaded - it happened many times in other systems here).
The front-end invokes the following routines:
detailAjaxCall("\/client\/orders\/detailsLoad\/id\/3");
$(".upLink").click(function(){
console.log("subiendo");
var id = $(this).closest("tr").data('detail-id');
var url = "\/client\/orders\/detailMoveUp" + "/id/" + id;
detailAjaxCall(url);
return false;
});
$(".downLink").click(function(){
console.log("bajando");
var id = $(this).closest("tr").data('detail-id');
var url = "\/client\/orders\/detailMoveDown" + "/id/" + id;
detailAjaxCall(url);
return false;
});
$(".delLink").click(function(){
console.log("borrando");
var id = $(this).closest("tr").data('detail-id');
var url = "\/client\/orders\/detailDelete" + "/id/" + id;
detailAjaxCall(url);
return false;
});
Note: the url string are not malformed. they are generated by a json exporter (this chunk of code was extracted from the view source option in Google Chrome browser). Evaluating any of them will return a string with no backslashes.
The detailAjaxCall("/client/orders/detailsLoad/id/<number>") actually works: it returns the expected json code when I hit the url, and renders the appropiate table items:
function detailAjaxCall(url)
{
$.get(
url,
{},
function(data, status, xhr) {
//todo refrescar(data);
var table = $("#detail-list");
table.empty();
if (data.length == 0) {
$("<tr></tr>").addClass("empty").append($("<td></td>").addClass("empty").text("No hay detalles para este pedido")).appendTo(table);
} else {
$.each(data, function(index, element) {
$("<tr></tr>")
.data('detail-id', element['id'])
.append(
$("<td></td>")
.append(
$("<span></span>").addClass("product-name").text(element['producto_nombre'])
)
.append("<br />")
.append(
$("<span></span>").addClass("product-dims").text(
"Ancho: " + element['ancho'] +
", Largo: " + element['largo'] +
", Calibre: " + element['calibre']
)
)
)
.append($("<td></td>").addClass("quantity").text(element['cantidad']))
.append($("<td></td>").addClass("price").text(element['precio']))
.append(
$("<td></td>")
.append(
$("<a></a>").addClass("upLink").text("subir").attr("href", "javascript: void 0")
).append(" ")
.append(
$("<a></a>").addClass("downLink").text("bajar").attr("href", "javascript: void 0")
).append(" ")
.append(
$("<a></a>").addClass("delLink").text("eliminar").attr("href", "javascript: void 0")
).append(" ")
)
.appendTo(table);
});
}
},
'json'
).fail(function(){
$("#ajaxDetailErrorDialog").dialog("open");
});
}
Pay attention to the generation of the "<a></a>" since my problem is with them. They all have classes like delLink, upLink and downLink.
My issue starts here: calling $(".delLink").click(callback), $(".upLink").click(callback), $(".downLink").click(callback) does not seem to bind the events to the newly created items (althought they are created inside the ajax call). Seeing the source code for the click method, passing parameters, is like a call to on.
So: what am I doing wrong to bind the event dynamically, so newly created elements trigger my events as well?
You need to dynamically delegate the click handlers because you assign your click handlers before the new elements are created.
For example, delegate to the document:
$(document).on('click', '.upLink', function(){
console.log("subiendo");
var id = $(this).closest("tr").data('detail-id');
var url = "\/client\/orders\/detailMoveUp" + "/id/" + id;
detailAjaxCall(url);
return false;
});
This works because all clicks on the document will be checked by this handler, to see if they match .upLink. Even if you create new elements after this is assigned, the clicks still pass through this event.

Categories

Resources