Jquery UI sortable have no e.target on children - javascript

I have a sortable list of folders using JQuery UI.
The thing is that the folders have a child-element that is a delete button. I try to get that element and with jquery get the name of that folder. But I found out that the sortable function destroys all e.target. Below is the code of deleting a folder
<script>
function deleteFolder(){
var name = $(this).siblings('.name').html();//this is undefined
var folder = $(this).parents('.folders');
$.ajax({
url: 'serverScripts/home/deleteFolder.php',
data: {name: name},
success: function(text){
if(text == 'success'){
folder.remove();
}
}
});
};
</script>
<div class='folder>
<div class='name'>Hello</div>
<div class='deleteBtn' onclick='deleteFolder()'>Delete</div>
</div>

You'll be much better off using jQuery to bind your event handler instead of an "onclick" attribute:
<script>
$(function() {
$('.folder .deleteBtn').click(function() {
var name = $(this).siblings('.name').html();//this is undefined
var folder = $(this).parents('.folders');
$.ajax({
url: 'serverScripts/home/deleteFolder.php',
data: {name: name},
success: function(text){
if(text == 'success'){
folder.remove();
}
}
});
});
});
</script>
When you bind the event handler with an old-fashioned "onclick" attribute, jQuery can't help you. When you do something like the above, then the library can normalize the "event" object, establish this properly, etc. If you want the event object, you can declare an argument to the handler:
$('.folder .deleteBtn').click(function(event) {

$(this) is not what you think it is.
The onClick event is bound to the <div class="deleteBtn">, this is the <div class="deleteBtn"> actually the window object and not the <div class="folder"> which is why the selector is not finding any siblings() with the .name class.

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!

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.

Event delegation not working jquery

So I'm just getting started with event delegation and I'm still fairly confused by it but here goes:
I have a button which adds a rating in ajax, once clicked again I'd like it to remove the rating, here's the code with annotations (and some parts removed to make it look more clear).
$(document).on("click", '.add_rating', function() {
l.start();
var input = $(this).prev().children('.my_rating');
var score = input.val();
var what_do = input.attr('action_type');
var cur_average = $('.current_average').val();
var data = {};
data.score = score;
data.media_id = <?php echo $title_data->media_id; ?>;
data.what_do = what_do;
$.ajax({
dataType: "json",
type: 'post',
url: 'jquery/actions/add_remove_rating',
data: data,
success: function(data) {
if (data.comm === 'success') {
//do some other stuff there, irrelevant
$('.ladda-button').removeClass('btn-primary');
$('.ladda-button').removeClass('btn-sm');
$('.ladda-button').addClass('btn-danger btn-xs');
$('.ladda-label').html('Remove');
$('.ladda-button').addClass('remove_rating'); <-- add the remove rating class I want to call if the button is clicked again
input.attr('action_type', 'remove_rating');
l.stop();
}
}
});
$('.remove_rating').on('click', function() { <-- this doesn't work, why?
alert('remove was clicked');
});
});
I can't seem to trigger this:
$('.remove_rating').on('click', function() { <-- this doesn't work, why?
alert('remove was clicked');
});
Any help appreciated!
Edit: on a side note, I don't actually need this to work as php figures out if we're removing or adding a score based on the action_type attribute. I just wanted to find out why it's not triggering.
change your code to:
$(document).on("click", '.add_rating', function() {
l.start();
var input = $(this).prev().children('.my_rating');
var score = input.val();
var what_do = input.attr('action_type');
var cur_average = $('.current_average').val();
var data = {};
data.score = score;
data.media_id = <?php echo $title_data->media_id; ?>;
data.what_do = what_do;
$.ajax({
dataType: "json",
type: 'post',
url: 'jquery/actions/add_remove_rating',
data: data,
success: function(data) {
if (data.comm === 'success') {
//do some other stuff there, irrelevant
$('.ladda-button').removeClass('btn-primary');
$('.ladda-button').removeClass('btn-sm');
$('.ladda-button').addClass('btn-danger btn-xs');
$('.ladda-label').html('Remove');
$('.ladda-button').addClass('remove_rating'); <-- add the remove rating class I want to call if the button is clicked again
input.attr('action_type', 'remove_rating');
l.stop();
$('.remove_rating').on('click', function() { <-- this doesn't work, why?
alert('remove was clicked');
});
}
}
});
});
EXPLANATION:
first have a look here: Understanding Event Delegation.
event delegation is used when you need to create event handlers for elements that do not exist yet. you add a .remove_rating class to elements dynamically, however you are trying to attach a handler to elements with the above mentioned class before you even attach it.
you are attaching the class when the asynchronous ajax call returns, in the success function, however your event handler block is being processed right after you send the ajax, and not after the ajax returns (ajax is async rememeber?). therefore, you need to wait until the ajax returns and the elements are created, and only then attach the handler to them.
alternatively, using event delegation, you can attach the handler to the document, like you did in the following line:
$(document).on("click", '.add_rating', function() {
it means, that you attach the handler to the document, and whenever any element ON the document is clicked, if that element has the class '.add_rating' then execute the handler.
therefore, you may attach another handler to the document to monitor for clicks on elements with the .remove_rating class as follows:
$(document).on("click", '.remove_rating', function() {
this is called event delegation, because you delegate the event to a parent element.
Because class was added after click event initialised. You need to use live event handlers, like this:
$( document ).on('click', '.remove_rating', function() {
In this case .remove_rating click handler will work on dynamically created elements and on class name changes.

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

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!
}
});

Categories

Resources