Jquery - can't target the right element with $(this) [duplicate] - javascript

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
$(this) doesn't work in a function
Im having a problem targeting the right element in my code. I have a list of thumbnails on my page, and when you click on a "I dislike this" icon the targeted video change for another one.
Here's the HTML
<li class="videoBox recommended">
<div class="spacer" style="display: block;"></div>
<div class="features">
<div>
<a class="dislike_black" title="I dislike this" onclick="ThumbsDown(30835, 'relevance', '1');"></a>
</div>
</div>
<a href="...">
<h1>...</h1>
<div class="information">...</div>
</li>
Ajax is:
function ThumbsDown(id,sort,page) {
$.ajax({
url: "/change/videos/"+id+"/thumbsdown/",
type: "POST",
data: {
"sort": sort?sort:"",
"page": page?page:""
},
success: function(data) {
//$("#content .videoList ul li.videoBox").html(data); // THIS IS WORKING, but replaces ALL the divs
$(this).parent("li.videoBox").html(data); // Cant get this to work!
}
});
What Iam doing wrong? even $(this).css("border","1px solid red") is not "working". (I tried with background color, and color too) I dont see anything.
$(This) refers to the "a" tag where the function is called right? So im searching for his parent named videobox... Help?
So can I target

You should not use onclick, you should bind it to an event, especially as you could easily make this degrade well if the user does not have ajax.
Change your <a> tags to this:
<a href="/change/videos/1/thumbsdown/"
data-sort="sort"
data-page="page"
class="dislike_black"
title="I dislike this"></a>
jQuery event:
$('.dislike_black').click(function(e) {
e.preventDefault(); // Prevent link from clicking
var $aTag = $(this); // I use $aTag to denote a jq object
$.ajax({
url: $aTag.attr('href'),
type: "POST",
data: {
"sort": $aTag.data('sort'), // data-sort attr value
"page": $aTag.data('page') // data-page attr value
},
success: function(response) {
$aTag.closest(".videoBox").html(response);
}
});
});
Now it works without javascript, and you're not using nasty onclick! Untested/no warranty.

Almost. In order to make this work, you need to pass in the context to the .ajax() call.
Like
$.ajax({
url: "/change/videos/"+id+"/thumbsdown/",
type: "POST",
context: document.body, // for instance
data: {
"sort": sort?sort:"",
"page": page?page:""
},
success: function(data) {
//$("#content .videoList ul li.videoBox").html(data); // THIS IS WORKING, but replaces ALL the divs
$(this).parent("li.videoBox").html(data); // Cant get this to work!
}
});
The above code would cause that all ajax handlers will have this pointing to document.body. So you would need to replace the document.body with the element you are looking for. So, if you for instance call your function in some kind of a click handler you could just call context: this and the magic is done.
See jQuery Ajax Doc section "context" for more details.

I believe all you needed to change in your original code was to get the reference to this outside of the success function, like this:
function ThumbsDown(id,sort,page) {
var self = this
$.ajax({
url: "/change/videos/"+id+"/thumbsdown/",
type: "POST",
data: {
"sort": sort?sort:"",
"page": page?page:""
},
success: function(data) {
//$("#content .videoList ul li.videoBox").html(data); // THIS IS WORKING, but replaces ALL the divs
$(self).parent("li.videoBox").html(data); // Cant get this to work!
}
});

Related

jQuery parents() selector failing

I have an anchor, and I have attached an onClick callback to it, so once it is clicked, an AJAX request is fired which calls a view that deletes the image from the database. It should also remove <div class="image-preview"> altogether, too, however that is not happening for some reason.
When I tested div removal code in JSFiddle, it works. The image is successfully getting removed from the database and delete_view is involved in the process. I have also tried to console.log from inside the success callback and I can see a debug message. console.log($(this).parents('.image-preview')); returns Object { length: 0, prevObject: Object(1) }, thus I think the selector is failing.
What could be the reason?
HTML:
<div id="information">
<div class="image-previews">
<div class="image-preview">
<img src="/media/tmp/None/IMG_20190507_144128.jpg" width="80" height="54">
<p><a id="115" class="delete-temp-image-link">delete</a></p>
<label><input type="radio" name="main" value="IMG_20190507_144128.jpg">main</label>
</div>
</div>
<div id="div0">
<div>Name: IMG_20190507_144128.jpg</div>
<div>Size: 3.03MB</div>
<div>Type: image/jpeg</div>
<div class="progressNumber">100%</div>
</div>
</div>
jQuery:
var $deleteClicked = function(event) {
var url = Urls.deleteTempImage(event.target.id);
$.ajax({
url: url,
data: {
'id': event.target.id
},
success: function (data) {
console.log('spam');
$(this).parents('.image-preview').remove();
}
});
}
$(document).on('click', '.delete-temp-image-link', $deleteClicked);
view:
def delete_view(request, id):
img = get_object_or_404(TemporaryImage, id=id)
img.delete()
return HttpResponse('successfull')
$(this) isn't available to your named click callback function. One way to make your code more explicit would be to store $(this), as others have said - or, simply use the id that you're already passing anyway. For example:
var $deleteClicked = function(event) {
var url = Urls.deleteTempImage(event.target.id);
$.ajax({
url: url,
data: {
'id': event.target.id
},
success: function (data) {
console.log('spam');
$("#"+event.target.id).closest('.image-preview').remove();
}
});
}
$(document).on('click', '.delete-temp-image-link', $deleteClicked);
Also, note that I used jQuery .closest() instead of .parents(). From the jQuery docs, .closest() does the following:
For each element in the set, get the first element that matches the
selector by testing the element itself and traversing up through its
ancestors in the DOM tree.
Check out the docs page for a description of the differences between .closest() and .parents(). The main difference is that .closest() only traverses up the DOM tree until it finds a match, rather than traversing all the way up to the root element. I doubt there are huge performance implications, but since you're selecting only one <div>, it's slightly more precise code.
You have to store $(this) before run $.ajax because you are using it in a wrong context.
var $deleteClicked = function(event) {
var url = Urls.deleteTempImage(event.target.id);
var storedThis = $(this);
$.ajax({
url: url,
data: {
'id': event.target.id
},
success: function (data) {
console.log('spam');
storedThis.parents('.image-preview').remove();
}
});
}
$(document).on('click', '.delete-temp-image-link', $deleteClicked);
This should work as expected.
Try this code for jQuery.
var $deleteClicked = function(event) {
var url = Urls.deleteTempImage($(this).attr('id'));
$.ajax({
url: url,
data: {
'id': $(this).attr('id')
},
success: function (data) {
console.log('spam');
$(this).parents('.image-preview').remove();
}
});
}
$('.delete-temp-image-link').on('click', $deleteClicked);
Same problem occur to me as well.
Actually '$(this)' is tricky as it may seem.
'$(this)' cannot be used in success function as it lost it scope in success function.
Try to define '$(this)' outside the success(ie, before ajax),eg
const element = $(this)
And then in your success function:
element.parents('.image-preview').remove();
This should definitely solve your problem.
Hope this helps!

How to lock / set / block variable inside .on jquery

So, I have a jQuery AJAX call that gets data from the server (some text, some links).
Inside AJAX success callback function I got a .on that is bind to <a> that load for me next page and get me the text of the clicked link (let's say stackoverflow.com).
The problem starts here because in the newly loaded page I got anchors...
After every click on anchor links I got new .text() value.
$.ajax({
url: url,
type: type,
dataType: dataType,
success: function(data){
$('.container').append(data);
$('.container').on('click', 'a', function(e){
e.preventDefault();
var clickLinkName = $(this).text();
console.log(clickLinkName);
$('.container').load($(this).attr('href'));
});
}
});
I would like to know how to lock clickLinkName variable. OR any other way to save only first hit.
I think this would do the trick:
$.ajax({
url: url,
type: type,
dataType: dataType,
success: function(data) {
$(".container").append(data);
var clickLinkName; // Declared here.
$(".container").on("click", "a", function(e) {
e.preventDefault();
// If not initialized, initialize.
if(!clickLinkName) {
clickLinkName = $(this).text();
}
console.log(clickLinkName);
$(".container").load($(this).attr("href"));
});
}
});
That would save only the first value in the variable clickLinkName. This answers your question, but I'm sure there are better ways of doing this.

jQuery function doesn't work after after loading dynamic content

I'm using below code. This is bootstrap 3 delete conformation message.
$(document).ready(function(){
$('a.btnDelete').on('click', function (e) {
e.preventDefault();
var id = $(this).closest('div').data('id');
$('#myModal').data('id', id).modal('show');
});
$('#btnDelteYes').click(function () {
var id = $('#myModal').data('id');
var dataString = 'id='+ id ;
$('[data-id=' + id + ']').parent().remove();
$('#myModal').modal('hide');
//ajax
$.ajax({
type: "POST",
url: "delete.php",
data: dataString,
cache: false,
success: function(html)
{
//$(".fav-count").html(html);
$("#output").html(html);
}
});
//ajax ends
});
});
This is the trigger element that I'm using
<div data-id="MYID"><a class="btnDelete" href="#">Delete</a></div>
And I'm using the same HTML element dynamically to trigger delete and it doesn't work.
Can someone point me the correct way to do it?
You have to use event delegation
$(document).on("click" , '#btnDelteYes' ,function () {
Pretty much: bind the click higher up to something that exists when the script is run, and when that something is clicked, tell it to pass the click event to the #btnDelteYes element instead
I cant understand what exactly you are doing on your code due to missing information, but the answer is: you should use event delegation on the dynamically inserted content
you can try
$('[data-id=MYID]').on('click','.btnDelteYes',function({
e.preventDefault();
var id = $(this).closest('div').data('id');
$('#myModal').data('id', id).modal('show');
});
here <div data-id="MYID"> should be a hard coded html content and The idea is to delegate the events to that wrapper, instead of binding handlers directly on the dynamic elements.

Onclick works only after second click

I have a list in HTML which looks like
<a onclick="open_file()" id="3.txt">3.txt</a>
My open_file() function is looking this
function open_file() {
$("a").click(function (event) {
var file_name = event.target.id;
$("#f_name").val(file_name);
$.ajax({
url: "docs/" + file_name,
dataType: "text",
success: function (data) {
$("#text_form").val(data);
$('#text_form').removeAttr('readonly');
$('#delete_button').removeAttr('disabled');
$('#save_button').removeAttr('disabled');
}
})
});
}
The problem is function finally loads data into all fields(text_form and f_name) only after two clicks on such link. It works even if I at first click on one file, then click on another and it loads. Is there any way to fix this?
What you're currently doing is adding an onclick event to a link that calls a function that adds another onclick event via jQuery.
Remove the onclick property and the open_file() function wrapper so that jQuery adds the event as you intended.
You do not need onclick="open_file()" this:
<div id='linkstofiles'>
<a id="3.txt">3.txt</a>
//other links go here
</div>
$("#linkstofiles a").click(function (event) {
var file_name = event.target.id;
$("#f_name").val(file_name);
$.ajax({
url: "docs/" + file_name,
dataType: "text",
success: function (data) {
$("#text_form").val(data);
$('#text_form').removeAttr('readonly');
$('#delete_button').removeAttr('disabled');
$('#save_button').removeAttr('disabled');
}
})
});
You don't need to bind a click event again in the function when you have onclick in your html.
Also for $ is not defined, you need to put jquery library in the head.

Trying to delete specific id

$('.icn-trash').on('click', function(e) {
e.preventDefault();
deleteBookmark($('.del').data('bookmarkid'));
});
function deleteBookmark(bookmarkID) {
$.ajax({
url: '/BookmarkApi/delete/' + bookmarkID,
type: 'POST',
success: function(response) {
$('.icn-trash').closest('.del').remove();
console.log('removed');
},
error: function(error) {
}
});
}
HTML - it will be generated dynamically for every bookmark folder.
<a href="#" class="del" data-bookmarkid="xxx">
<span class="actions" style="z-index:300">
<i class="icn-trash"></i>
</span>
</a>
Everytime, I try to delete the specific id of the bookmark folder, multiple folders are removed. It should only remove one specific folder when clicking trash icon. When I clicked trash icon on 6th folder, the 1st, 2nd, 3rd, 4th, 5th folders will disappear and i refreshed again only to find 1st folder actually being removed from database.
I want to have 6th folder disappear and removed from database.
Help appreciated.
Try this way
$(document).on('click', '.icn-trash',function(evt) {
evt.preventDefault();
var b_id=$(this).closest('.del').data('bookmarkid')
$.ajax({
url: '/BookmarkApi/delete/' + b_id,
type: 'POST',
success: function(response) {
$(this).closest('.del').remove();
console.log('removed');
},
error: function(error) {
}
});
});
I would bind the event on the a tag:
$('.del').on('click', function(e) {
e.preventDefault();
deleteBookmark(this);
});
function deleteBookmark(ele) {
$.ajax({
url: '/BookmarkApi/delete/' + $(ele).data('bookmarkid'),
type: 'POST',
success: function(response) {
$(ele).remove();
console.log('removed');
},
error: function(error) {
}
});
}
Or if you still want to bind on .icn-trash:
$('.icn-trash').on('click', function(e) {
e.preventDefault();
deleteBookmark($(this).closest('.del'));
});
function deleteBookmark(ele) {
$.ajax({
url: '/BookmarkApi/delete/' + ele.data('bookmarkid'),
type: 'POST',
success: function(response) {
ele.remove();
console.log('removed');
},
error: function(error) {
}
});
}
You are removing content using class attribute that return collection of all the links and remove the links.
$('.icn-trash').on('click', function (e) {
debugger
event.preventDefault()
deleteBookmark(this);
});
function deleteBookmark(obj) {
debugger
bookmarkID = $('.del').data('bookmarkid');
$(obj).remove();
$.ajax({
url: '/BookmarkApi/delete ,
data: { bookmarkID: bookmarkID},
type: 'POST',
success: function (response) {
console.log('removed');
},
error: function (error) {
}
});
}
From the jQuery Documentation of closest API
For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
Now what is happening in the code $('.icn-trash').closest('.del').remove();
$(.icn-trash') is returning the set of all element elements having the class icn-trash. And then you are using this set to find the closest element with class .del which will return a set of all anchor tags (in your html example). Finally you are removing the entire set. Hence multiple bookmarks are getting deleted.
I am assuming you need to delete the anchor tag which has the data-bookmarkid as bookmarkID
$('.icn-trash').on('click', function(e) {
e.preventDefault();
deleteBookmark($('.del').data('bookmarkid'));
});
function deleteBookmark(bookmarkID) {
$.ajax({
url: '/BookmarkApi/delete/' + bookmarkID,
type: 'POST',
success: function(response) {
// get the element with data-bookmarkid = bookmarkID and remove it
$("[data-bookmarkid='" + bookmarkID + "']").remove()
console.log('removed');
},
error: function(error) {
}
});
}
EDIT: I didn't read the last part of your question
When I clicked trash icon on 6th folder, the 1st, 2nd, 3rd, 4th, 5th folders will disappear and i refreshed again only to find 1st folder actually being removed from database.
Can you make sure that the bookmarkIds are correct in the data-bookmarkid attribute? Since clicking on 6th trash icon is removing the 1st folder from the database, there seems to be a problem either with your server code or the data-bookmarkid attribute is incorrect in the 6th trash icon
EDIT2: Why you are getting the wrong bookmarkId (Didn't investigat enough thoroughly earlier, got involved in something else)
Again quoting from jQuery documentation for data API
Return the value at the named data store for the first element in the jQuery collection, as set by data(name, value) or by an HTML5 data-* attribute.
So analyzing your code deleteBookMark($('.del').data('bookmarkid')): $('.del') will contain all the elements with class name del (in your example all the anchor tags). Calling .data('bookmarkid') with the entire set will return the bookmark id of the first anchor tag. The best way to do this is to first obtain the element which was clicked. This can be done by modifying your code
Again from jQuery Documentation for Event Listener
When jQuery calls a handler, the this keyword is a reference to the element where the event is being delivered;...
To create a jQuery object from the element so that it can be used with jQuery methods, use $( this ).
This means that
$('.icn-trash').on('click', function(e) {
e.preventDefault();
deleteBookmark($('.del').data('bookmarkid'));
});
In the listener you have attached, this will refer to the .icn-trash element you clicked on. So now you know which element was clicked, find the closest .del element and then get its data-bookmarkid attribute. i.e.
$('.icn-trash').on('click', function(e) {
e.preventDefault();
var curIconTrash = $(this),
closestAnchor = curIconTrash.closest('.del'),
bookMarkId = closestAnchor.data('bookmarkid')
deleteBookmark(bookmarkId);
});
Or taking the advantage of jQuery chaining
$('.icn-trash').on('click', function(e) {
e.preventDefault();
deleteBookmark($(this).closest('.del').data('bookmarkid'));
});
Note: This was also suggested by #sreedhar-r
Hope this helps! Cheers :-)

Categories

Resources