UPDATED!!
The code after
$.get(url, { id: id, action: action }, function(data) {
does not fire? Complete method below.
function modifyPermit(id, action) {
var url = "ajax/permit_modify.aspx";
$.get(url, { id: id, action: action }, function(data) {
if (data == "SUCCESS") {
// Update page
$.get("ajax/permit_getall.aspx", function (data) {
$("#ctl00_ContentPlaceHolder1_permitList").html(data);
}).error(function(err) {
alert(err);
});
} else {
alert(data);
}
});
}
Using .Net.
Regards,
Robert
You seem to be using a wrong variable for the url here (you defined url_mod but used url in your AJAX request):
var url_mod = "ajax/permit_modify.aspx?id=" + id + "&action=" + action;
$.get(url, function(data) {
which should should become:
var url = "ajax/permit_modify.aspx?id=" + id + "&action=" + action;
$.get(url, function(data) {
Also instead of manually having to call the encodeURIComponent function for each parameter (which by the way you forgot to do in your second AJAX request) I would recommend you using the following construct:
var url = 'ajax/permit_modify.aspx';
$.get(url, { id: id, action: action }, function(data) {
This way jQuery will take care of generating the properly encoded url. The same concept could be applied in your first AJAX request. Notice how you could pass as second parameter to the $.get function key/value pairs that jQuery will use to construct the proper url.
UPDATE:
After having an offline chat with the OP it turned out that the problem was not related to the AJAX code shown in his question but rather with the way he was calling the modifyPermit function. It was inside the onclick handler of a button without returning false. This in turn triggered a full postback to the server leaving no time for the AJAX request to execute. The correct solution was to return false to prevent the default action of the button:
onclick="modifyPermit(1,'a'); return false;"
Fix found by #darin which tuned out to be simple: just add return false; after the method call on the button.
modifyPermit(1,'a'); return false;
Many thanks to Darin for all the time and effort he put in the helping me solve this issue. Could not have don it without you!
/Bob
Related
This topic is covered in a few other questions, but I had some difficulty applying the suggested approaches into this use case. I have a checkbox list, where a user can select n sub-sites to publish their post to. since this list could grow to be 100+, I need an efficient way to perform an expensive task on each one. It's okay if it takes awhile, as long as Im providing visual feedback, so I planned to apply an "in progress" style to each checkbox item as its working, then move to the next item int he list once it is successfully published. Also note: I'm working in the WordPress wp_ajax_ hook but the PHP side of things is working well, this is focused on the JS solution.
This code is working right now (console.logs left in for debug), but I've seen multiple warnings against using async: true. How can I achieve a waterfall AJAX loop in a more efficient way?
//Starts when user clicks a button
$("a#as_network_syndicate").click( function(e) {
e.preventDefault(); //stop the button from loading the page
//Get the checklist values that are checked (option value = site_id)
$('.as-network-list').first().find('input[type="checkbox"]').each(function(){
if($(this).is(':checked')){
blog_id = $(this).val();
console.log(blog_id+' started');
$(this).parent().addClass('synd-in-progress'); //add visual feedback of 'in-progress'
var process = as_process_syndication_to_blog(blog_id);
console.log('finished'+blog_id);
$(this).parent().removeClass('synd-in-progress');
}
});
});
function as_process_syndication_to_blog(blog_id){
var data = {
"post_id": $('#as-syndicate_data-attr').attr("data-post_id"), //these values are stored in hidden html elements
"nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
"blog_id": blog_id
};
var result = as_syndicate_to_blog(data);
console.log('end 2nd func');
return true;
}
function as_syndicate_to_blog(data){
$.ajax({
type : "post",
dataType : "json",
async: false,
url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id},
success: function(response) {
if(response.type == "success") {
console.log(response);
return response;
} else {
}
},
error: {
}
});
}
Indeed, doing synchronous AJAX request is bad because it will block the browser during the whole AJAX call. This means that the user cannot interact with your page during this time. In your case, if you're doing like 30 AJAX calls which take say 0.5 seconds, the browser will be blocked during 15 whole seconds, that's a lot.
In any case, you could do something following this pattern:
// some huge list
var allOptions = [];
function doIntensiveWork (option, callback) {
// do what ever you want
// then call 'callback' when work is done
callback();
}
function processNextOption () {
if (allOptions.length === 0)
{
// list is empty, so you're done
return;
}
// get the next item
var option = allOptions.shift();
// process this item, and call "processNextOption" when done
doIntensiveWork(option, processNextOption);
// if "doIntensiveWork" is asynchronous (using AJAX for example)
// the code above might be OK.
// but if "doIntensiveWork" is synchronous,
// you should let the browser breath a bit, like this:
doIntensiveWork(option, function () {
setTimeout(processNextOption, 0);
});
}
processNextOption();
Notice: as said by Karl-André Gagnon, you should avoid doing many AJAX requests using this technique. Try combining them if you can, it will be better and faster.
If you can't pass the whole block to the server to be processed in bulk, you could use a jQuery queue. This is using your sample code as a base:
var $container = $('.as-network-list').first();
$container.find('input[type="checkbox"]:checked').each(function(){
var $input = $(this);
$container.queue('publish', function(next) {
var blog_id = $input.val(),
$parent = $input.parent();
console.log(blog_id+' started');
$parent.addClass('synd-in-progress'); //add visual feedback of 'in-progress'
as_process_syndication_to_blog(blog_id).done(function(response) {
console.log(response);
console.log('finished'+blog_id);
$parent.removeClass('synd-in-progress');
next();
});
});
});
$container.dequeue('publish');
function as_process_syndication_to_blog(blog_id){
var data = {
"post_id": $('#as-syndicate_data-attr').attr("data-post_id"), //these values are stored in hidden html elements
"nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
"blog_id": blog_id
};
return as_syndicate_to_blog(data).done(function(){ console.log('end 2nd func'); });
}
function as_syndicate_to_blog(data){
return $.ajax({
type : "post",
dataType : "json",
url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id}
});
}
I don't have a test environment for this so you may need to tweak it for your use case.
I have an ajax call in my javascript that returns and loads a partial view into a div. This function used to work but then all the sudden it stopped. I do not think I changed any code or anything that would cause issue but obviously something is going on. The Ajax call will work on the first time when you click on the button in which it is called but never again until you reload the page. I have tried adding more parameters and moving the javascript around but it still did not work. Is there any reason why this could happen?
I have tried moving the javascript out of the onOpen event and the same thing still happens. I have also put an alert call to make sure it is getting to the success call and the alert is called. I have also installed fiddler to check the call and the call is never made except on the first click of the button. This is a very frustrating error and all help is much appreciated.
Here is my Javascript:
#section scripts
{
<script type="text/javascript">
$(document).ready(function () {
$("#assets-button").on("click", function ()
{
$('#assets-container').bPopup(
{
modal: true,
onOpen: function () {
$.ajax({
type: 'GET',
url: '#Url.Action("EmployeeAssets", "Employee",new { id = Model.ID, empNo = Model.EmployeeNumber, username = Model.UserName })',
success: function (data) {
$('#assets-container').html(data);
}
});
},
onClose: function () {
var f = $('#assets-container').children('form');
var serializedForm = f.serialize();
var action = '#Url.Action("EmployeeAssets","Employee",new {empNo = Model.EmployeeNumber})';
$.post(action, serializedForm);
}
});
});
});
</script>
}
Here is the action that I am trying to call:
[HttpGet]
public ActionResult EmployeeAssets(int id, int empNo, string username = null)
{
var assets = _employeeDb.EmployeeAssets.FirstOrDefault(e => e.EmpNo == empNo);
if (assets == null)
{
var firstOrDefault = _employeeDb.EmployeeMasters.FirstOrDefault(e => e.EmployeeNumber == empNo);
if (firstOrDefault != null)
{
username = firstOrDefault.UserName;
}
var newasset = new EmployeeAsset()
{
EmpNo = empNo,
UserName = username
};
_employeeDb.EmployeeAssets.Add(newasset);
_employeeDb.SaveChanges();
assets = newasset;
}
return PartialView(assets);
}
You may try using the cache property of the settings object you are passing to the AJAX call. According to the jQuery documentation for .ajax the default for cache is set to true, so I wonder whether your browser is accessing a cached copy of the result after the first request. Looks like you could also set the dataType, and that will default the cache back to false.
Also, I would suggest putting your alert inside of the onOpen event handler in addition to the success handler just to be sure that's also being called. So that may help you debug a bit further.
I have some jQuery code that doesn't work as expected.
$('a[href^="http://"]').not('[href^="http://mydomain.com"], [href^="http://itunes.apple.com"]').click(function (e) {
e.preventDefault();
console.log("external: " + this.getAttribute('href'));
var url = this.getAttribute('href');
foo.track(
"External",
{ 'URL': url },
function (url) {
location.href = url
}
);
});
For this example, I'm tracking all external clicks from my domain, except for iTunes apps store. Assume foo.track() is a 3rd party method I'm using to track some events for reporting. The last parameter to it is an anonymous function that is executed once the tracking call successfully returns.
The code above is trying to navigate everything to http://mydomain.com/1 for some reason. However, the console.log statement succesfully logs the expected values. It's as if the url variable isn't referencing the value I expect. I've also tried replacing location.href = url with window.location = url but I get the same result.
What am I doing wrong?
Just remove the parameter from the navigation function. Like this:
$('a[href^="http://"]').not('[href^="http://mydomain.com"],
[href^="http://itunes.apple.com"]').click(function (e) {
e.preventDefault();
console.log("external: " + this.getAttribute('href'));
var url = this.getAttribute('href');
foo.track("External", { 'URL': url }, function (/*url*/) { location.href = url });
});
The aim of this code is to delete a comment with AJAX. The function is called as follows:
DeleteComment(166);
And the code that runs is:
// Each delete button
function DeleteComment(CommentID) {
$.ajax({
url: AJAXURL + "?action=del&id=" + CommentID,
success: function (data) {
// Parse the data
if (data.substring(0, 1) == "1") {
$('#cid' + CommentID).hide();
} else {
alert(data.substring(2, data.length));
}
}
});
}
However the $('#cid' + CommentID).hide(); line never fires as CommentID isn't retained, I'm new to Jquery, could someone show me how to change this so the comments ID is retained when the ajax success is called?
put the $('#cid' + CommentID).hide(); before $.ajax({ and then add $('#cid' + CommentID).show(); to your else condition..
Hide it first and then reshow it if deletion fails...
Not the most graceful solution, but the path of least resistance from where you are.
Can you post more of the surrounding code? As is, your code looks like it should work. But I see a troublesome comment: // Each delete button. The way you are binding the DeleteComment function to the buttons must not be working the way you assume.
Try this instead:
// Iterate over each delete button.
// The .each(...) provides you a function, a.k.a. local scope, for each button.
$(".deleteButtons").each(function (idx, el) {
// This is very important: you must create a local variable to hold the ID.
// How to get the ID is up to you.
var id = getTheCorrespondingCommentId(idx, el);
// Now you can safely pass the local variable to the DeleteComment function:
$(el).click(function() { DeleteComment(id); });
});
I'm using the bit.ly url shortening service to shorten certain url's being sent to a "share on twitter" function. I'd like to load the bit.ly url only when a user actually presses the share button (due to bit.ly's max 5 parallel reqs limitation). Bit.ly's REST API returns a JSON callback with the shortened url, which makes the whole scenario async.
I've tried the following to stop the click event, and wait for the JSON call to return a value before launching the click.
I have the following simplified code in jQuery(document).ready():
Updated code (oversimplified)!
jQuery("#idofaelement").click(function(event) {
event.preventDefault(); //stop the click action
var link = jQuery(this);
bitlyJSON(function(shortUrl) {
link.attr("href", function() {
//process shortUrl
//return finalized url;
}).unbind().click();
});
});
And the following code to handle the bitly shortening (works just fine):
function bitlyJSON(func) {
//
// build apiUrl here
//
jQuery.getJSON(apiUrl, function(data) {
jQuery.each(data, function(i, entry) {
if (i == "errorCode") {
if (entry != "0") {
func(longUrl);}
} else if (i == "results") {
func(entry[longUrl].shortUrl);}
});
});
} (jQuery)
The href gets its value changed, but the final .click() event never gets fired. This works fine when defining a static value for the href, but not when using the async JSON method.
As you outlined yourself:
event.preventDefault(); //stop the click action
That means, BROWSER IS NOT GOING TO THAT URL, if you wish to actually go forward to the long-url location, simply do something like:
document.location.href = longurl;
iirc, jquery doesn't trigger "click" on A elements. I'd try old good "location.href=whatever" in the callback.
bitlyJSON(function(shortUrl) {
link.attr("href", function() {
//process shortUrl
//return finalized url;
});
location.href = link.attr("href");
});
I think what you actually want is to return false; from the click event, to prevent the actual following of the href, right?
Like:
jQuery("#idofaelement").click(function(event) {
//event.preventDefault(); //stop the click action
var link = jQuery(this);
bitlyJSON(function(shortUrl) {
link.attr("href", function() {
//process shortUrl
//return finalized url;
}).unbind().click();
});
return false;
});
#Tzury Bar Yochay pointed me in the right direction by suggesting I use location.href to update the url. Also #Victor helped with his answer.
I got things kinda working combining the answers, but had issues with the history in firefox. Seems that updating window.location indeed redirected the user, but also removed the "source page" from the history. This did not happen in chrome, safari, ie8, ie8-compatibility or ie7.
Based on this response to another question I was able to create a workaround giving the following working code + made a few changes:
jQuery("#idofaelement").one("click", function(event) {
bitlyJSON(function(shortUrl) {
jQuery("#idofaelement").attr("href", function() {
//process shortUrl
//return finalized url;
});
setTimeout(function() {
window.location = jQuery("#idofaelement").attr("href");
}, 0);
});
return false;
});
Thanks for all the help!