$(this) not selecting element in callback function - javascript

I have 2 different set of codes, the only difference is the location of $(this).closest('.organizer_listing').slideUp('fast');. In the first set of code, it works, but I prefer for that line of code to be as in the 2nd set of code inside the callback function, which no longer works - slideUp does not seem to be executed.
Why is this so? How should I fix it?
Variation 1
$("input[type=checkbox]:checked").each(function() {
$(this).closest('.organizer_listing').slideUp('fast'); // Remove listings visually from list
// Send AJAX request to delete from database
var listing_id = $(this).closest('.organizer_listing').data('listing_id');
$.ajaxSetup({ cache: false });
$.getJSON(base_url + 'organizer/delete_favorite',
{listing_id: listing_id},
function(json) {
$.modal.close();
});
});
Variation 2
$("input[type=checkbox]:checked").each(function() {
// Send AJAX request to delete from database
var listing_id = $(this).closest('.organizer_listing').data('listing_id');
$.ajaxSetup({ cache: false });
$.getJSON(base_url + 'organizer/delete_favorite',
{listing_id: listing_id},
function(json) {
$.modal.close();
$(this).closest('.organizer_listing').slideUp('fast'); // Remove listings visually from list
});
});

Variation two doesn't work because in your $.getJSON callback, this is no longer the current element in your each loop, but rather the jqXHR object.
You can easily work around this by saving the value of this to a new variable, which your callback will "close over" (have access to):
var self = this;
$.getJSON(base_url + 'organizer/delete_favorite',
{listing_id: listing_id},
function(json) {
$.modal.close();
$(self).closest('.organizer_listing').slideUp('fast'); // Remove listings visually from list
});

It does not work anymore because this in the callback of the $.getJSON is not anymore your checkbox !
Do this:
$("input[type=checkbox]:checked").each(function() {
var $cb = $(this); // save your ref to the checkbox
var listing_id = $cb.closest('.organizer_listing').data('listing_id');
$.ajaxSetup({ cache: false });
$.getJSON(base_url + 'organizer/delete_favorite',
{listing_id: listing_id},
function(json) {
$.modal.close();
// use $cb
$cb.closest('.organizer_listing').slideUp('fast');
});
});
When you want to use it, you should always ask yourself what is the value of this in the current context.

Related

why am I getting same quote from jsonp result

I have the following jquery code, that pulls json data from a url; however, it is giving me the same quote over and over, instead of random. If I use url directly on browser it does randomize the quote. What am I missing? Thanks
$(document).ready(function() {
$("#getMessage").on("click", function(){
$.getJSON("https://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&callback=", function(a) {
console.log(a[0].content + " " + a[0].title)
$("#quote-content").html(a[0].content)
$("#quote-title").html(a[0].title)
});
});
You can either turn off AJAX cache for jQuery, like this:
$(document).ready(function() {
$.ajaxSetup({ cache: false });
//...
});
Or you could change the url for every request (so it doesn't get cached), something like this could work:
$(document).ready(function() {
$("#getMessage").on("click", function(){
$.getJSON("https://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&callback=&"+new Date().getTime(), function(a) {
//...
});
});
});
Also, I don't think you need the callback= parameter

jQuery: Updating global var and re-running function

I have a function that has another function nested that binds a click event to re-run that function with a different ajax URL:
function getInternal() {
var callUrl = 'https://url.com'; // URL ON LOAD
$.ajax({
dataType: "json",
url: callUrl,
success: function(data) {
var obj = data;
$( document ).ready(function(callUrl) {
$( "a.dept" ).click(function() {
var filterDept = $(this).attr('id');
callUrl = 'https://url.com/' + filterDept; // URL TO UPDATE
getInternal(callUrl); // RUN THIS FUNCTION AGAIN
});
});
Unfortunately the click event continues to return the same data. It doesn't look like callUrl is updating.
How do I update a global variable from within a function to re-run itself?
The first line of your function sets your variable to a specific value: var callUrl = 'https://url.com'; Thus, every single time you run this function, the variable will be set to 'https://url.com'.
By moving your variable outside of the function it will become a global variable, and the portion of your code that updates callUrl will persist.
That being said, your code is all sorts of mixed up. You have $( document ).ready() within an AJAX callback, a click event that gets redefined within that with each call, nothing seems to be closed, and you've supplied a parameter for getInternal(); despite the fact that it takes none.
Is something like this what you're after?
$(document).ready(function() {
//On click of link, run AJAX call to changing URL (based on clicked link's ID)
$( "a.dept" ).click(function() {
var filterDept = $(this).attr('id');
var callUrl = 'https://url.com/' + filterDept;
getInternal(callUrl);
});
});
function getInternal(callUrl) {
$.ajax({
dataType: "json",
url: callUrl,
success: function(data) {
alert("Call made to " + callUrl);
}
});
}

AJAX jQuery on click dynamically created only works first time

I am trying to create a dropdown menu that I dynamically insert into using jQuery. The objects I'm inserting are notifications, so I want to be able to mark them as read when I click them.
I have an AJAX call that refreshes the notifications every second from the Django backend.
Once it's been refreshed, I insert the notifications into the menu.
I keep an array of the notifications so that I don't create duplicate elements. I insert the elements by using .append(), then I use the .on() method to add a click event to the <li> element.
Once the click event is initiated, I call a function to .remove() the element and make an AJAX call to Django to mark the notification as read.
Now my problem:
The first AJAX call to mark a notification as read always works. But any call after that does not until I refresh the page. I keep a slug value to identify the different notifications.
Every call I make before the refresh uses the first slug value. I can't figure out why the slug value is tied to the first element I mark as read.
Also, if anyone has a better idea on how to approach this, please share.
Here's my code:
var seen = [];
function removeNotification(elem, urlDelete) {
elem.remove();
console.log("element removed");
$.ajax({
url: urlDelete,
type: 'get',
success: function(data) {
console.log("marked as read");
},
failure: function(data) {
console.log('failure to mark as read');
}
});
}
function insertNotifications(data) {
for (var i = 0; i < data.unread_list.length; i++) {
var slug = data.unread_list[i].slug
var urlDelete = data.unread_list[i].url_delete;
if (seen.indexOf(slug) === -1) {
var elem = $('#live-notify-list').append("<li id='notification" +
i + "' > " + data.unread_list[i].description + " </li>");
var parent = $('#notification' + i).wrap("<a href='#'></a>").parent();
seen.push(slug);
$( document ).ready(function() {
$( document ).on("click", "#notification" + i, function() {
console.log("onclick " + slug);
removeNotification(parent[0], urlDelete);
});
});
}
}
}
function refreshNotifications() {
$.ajax({
url: "{% url 'notifications:live_unread_notification_list' %}",
type: 'get',
success: function(data) {
console.log("success");
insertNotifications(data);
},
failure: function(data) {
console.log('failure');
}
});
}
setInterval(refreshNotifications, 1000);
I really don't know what do you mean with parent[0] in
removeNotification(parent[0], urlDelete);
I think you can simply try $(this)
removeNotification($(this), urlDelete);
but to be honest I find to put
$( document ).ready(function() {
$( document ).on("click", "#notification" + i, function() {
console.log("onclick " + slug);
removeNotification(parent[0], urlDelete);
});
});
inside a loop .. its bad thing try to put it outside a function and use it like
$( document ).ready(function() {
setInterval(refreshNotifications, 1000);
$( document ).on("click", "[id^='notification']", function() {
console.log("onclick " + slug);
removeNotification($(this), urlDelete);
});
});
and try to find a way to pass a urlDelete which I think it will be just one url

How to place a jQuery snippet into a global file

I have a JavaScript file here http://www.problemio.com/js/problemio.js and I am trying to place some jQuery code into it that looks like this:
$(document).ready(function()
{
queue = new Object;
queue.login = false;
var $dialog = $('#loginpopup')
.dialog({
autoOpen: false,
title: 'Login Dialog'
});
var $problemId = $('#theProblemId', '#loginpopup');
$("#newprofile").click(function ()
{
$("#login_div").hide();
$("#newprofileform").show();
});
// Called right away after someone clicks on the vote up link
$('.vote_up').click(function()
{
var problem_id = $(this).attr("data-problem_id");
queue.voteUp = $(this).attr('problem_id');
voteUp(problem_id);
//Return false to prevent page navigation
return false;
});
var voteUp = function(problem_id)
{
alert ("In vote up function, problem_id: " + problem_id );
queue.voteUp = problem_id;
var dataString = 'problem_id=' + problem_id + '&vote=+';
if ( queue.login = false)
{
// Call the ajax to try to log in...or the dialog box to log in. requireLogin()
}
else
{
// The person is actually logged in so lets have him vote
$.ajax({
type: "POST",
url: "/problems/vote.php",
dataType: "json",
data: dataString,
success: function(data)
{
alert ("vote success, data: " + data);
// Try to update the vote count on the page
//$('p').each(function()
//{
//on each paragraph in the page:
// $(this).find('span').each()
// {
//find each span within the paragraph being iterated over
// }
//}
},
error : function(data)
{
alert ("vote error");
errorMessage = data.responseText;
if ( errorMessage == "not_logged_in" )
{
//set the current problem id to the one within the dialog
$problemId.val(problem_id);
// Try to create the popup that asks user to log in.
$dialog.dialog('open');
alert ("after dialog was open");
// prevent the default action, e.g., following a link
return false;
}
else
{
alert ("not");
}
} // End of error case
}
}); // Closing AJAX call.
};
$('.vote_down').click(function()
{
alert("down");
problem_id = $(this).attr("data-problem_id");
var dataString = 'problem_id='+ problem_id + '&vote=-';
//Return false to prevent page navigation
return false;
});
$('#loginButton', '#loginpopup').click(function()
{
alert("in login button fnction");
$.ajax({
url:'url to do the login',
success:function() {
//now call cote up
voteUp($problemId.val());
}
});
});
});
</script>
There are two reasons why I am trying to do that:
1) I am guessing this is just good practice (hopefully it will be easier to keep track of my global variables, etc.
2) More importantly, I am trying to call the voteUp(someId) function in the original code from the problemio.js file, and I am getting an error that it is an undefined function, so I figured I'd have better luck calling that function if it was in a global scope. Am I correct in my approach?
So can I just copy/paste the code I placed into this question into the problemio.js file, or do I have to remove certain parts of it like the opening/closing tags? What about the document.ready() function? Should I just have one of those in the global file? Or should I have multiple of them and that won't hurt?
Thanks!!
1) I am guessing this is just good practice (hopefully it will be
easier to keep track of my global variables, etc.
Yes and no, you now have your 'global' variables in one spot but the chances that you're going to collide with 'Global' variables (ie those defined by the browser) have increased 100% :)
For example say you decided to have a variable called location, as soon as you give that variable a value the browser decides to fly off to another URL because location is a reserved word for redirecting.
The solution to this is to use namespacing, as described here
2) More importantly, I am trying to call the voteUp(someId) function
in the original code from the problemio.js file, and I am getting an
error that it is an undefined function, so I figured I'd have better
luck calling that function if it was in a global scope. Am I correct
in my approach?
Here's an example using namespacing that will call the voteUp function:
(function($) {
var myApp = {};
$('.vote_up').click(function(e) {
e.preventDefault();
myApp.voteUp();
});
myApp.voteUp = function() {
console.log("vote!");
}
})(jQuery);
What about the document.ready() function? Should I just have one of
those in the global file? Or should I have multiple of them and that
won't hurt?
You can have as many document.ready listeners as you need, you are not overriding document.ready you are listening for that event to fire and then defining what will happen. You could even have them in separate javascript files.
Be sure your page is finding the jquery file BEFORE this file is included in the page. If jquery is not there first you will get function not defined. Otherwise, you might have other things conflicting with your jquery, I would look into jquery noConflict.
var j = jQuery.noConflict();
as seen here:
http://api.jquery.com/jQuery.noConflict/
Happy haxin
_wryteowl
Extending what KreeK has already provided: there's no need to define your "myApp" within the document ready function. Without testing, I don't know off the top of my head if doing so is a potential source for scope issues. However, I CAN say that the pattern below will not have scope problems. If this doesn't work, the undefined is possibly a script-loading issue (loading in the right order, for example) rather than scope.
var myApp = myApp || {}; // just adds extra insurance, making sure "myApp" isn't taken
myApp.voteUp = function() {
console.log("vote!");
}
$(function() { // or whatever syntax you prefer for document ready
$('.vote_up').click(function(e) {
e.preventDefault();
myApp.voteUp();
});
});

jQuery: Referencing the calling object(this) when the bind/click event is for a class

Thanks for reading this.
I am dynamically generating some data which includes a select drop-down with a text box next to it. If the user clicks the select, I am dynamically populating it (code below). I have a class on the select and I was hoping the following code would work. I tested it with an ID on the select and putting the ONE on the ID I got it to work. However, in changing the code to reference a class (since there will be multiple data groups that include a select with a text box next to it) and $(this), I could not get it to work. Any ideas would be helpful. Thanks
The relevance of the text box next to the select is the second part of the code...to update the text box when an option is selected in the select
.one is so the select is updated only once, then the .bind allows any options selected to be placed in the adjacent text box.
$('.classSelect').one("click",
function() {
$.ajax({
type: "post",
url: myURL ,
dataType: "text",
data: {
'_service' : myService,
'_program' : myProgram ,
'param' : myParams
},
success:
function(request) {
$(this).html(request); // populate select box
} // End success
}); // End ajax method
$(this).bind("click",
function() {
$(this).next().val($(this).val());
}); // End BIND
}); // End One
<select id="mySelect" class="classSelect"></select>
<input type="text">
$(this) is only relevant within the scope of the function. outside of the function though, it loses that reference:
$('.classSelect').one("click", function() {
$(this); // refers to $('.classSelect')
$.ajax({
// content
$(this); // does not refer to $('.classSelect')
});
});
a better way to handle this may be:
$('.classSelect').one("click", function() {
var e = $(this);
$.ajax({
...
success : function(request) {
e.html(request);
}
}); // end ajax
$(this).bind('click', function() {
// bind stuff
}); // end bind
}); // end one
by the way, are you familiar with the load() method? i find it easier for basic ajax (as it acts on the wrapped set, instead of it being a standalone function like $.ajax(). here's how i would rewrite this using load():
$('.classSelect').one('click', function() {
var options = {
type : 'post',
dataType : 'text',
data : {
'_service' : myService,
'_program' : myProgram ,
'param' : myParams
}
} // end options
// load() will automatically load your .classSelect with the results
$(this).load(myUrl, options);
$(this).click(function() {
// etc...
}); // end click
}); // end one
I believe that this is because the function attached to the success event doesn't know what 'this' is as it is run independently of the object you're calling it within. (I'm not explaining it very well, but I think it's to do with closures.)
I think if you added the following line before the $.ajax call:
var _this = this;
and then in the success function used that variable:
success:
function(request) {
_this.html(request); // populate select box
}
it may well work
That is matching one select. You need to match multiple elements so you want
$("select[class='classSelect']") ...
The success() function does not know about this, as any other event callback (they are run outside the object scope).
You need to close the variable in the scope of the success function, but what you really need is not "this", but $(this)
So:
var that = $(this);
... some code ...
success: function(request) {
that.html(request)
}
Thanks Owen. Although there may be a better to write the code (with chaining)....my problem with this code was $(this) was not available in the .ajax and .bind calls..so storing it in a var and using that var was the solution.
Thanks again.
$('.classSelect').one("click",
function() {
var e = $(this) ;
$.ajax({
type: "post",
url: myURL ,
dataType: "text",
data: {
'_service' : myService,
'_program' : myProgram ,
'param' : myParams
},
success:
function(request) {
$(e).html(request); // populate select box
} // End success
}); // End ajax method
$(e).one("click",
function() {
$(e).next().val($(e).val());
}); // End BIND
}); // End One

Categories