Can not register function for option in pjax - javascript

Pjax will not allow me to specify functions as an option when calling it directly.
$(document).on('click', 'a.inferno-preview', function(event) {
return $.pjax.click(event, {
container: '#preview-overlay',
fragment: '#preview-overlay',
send: function() {
return $('#preview-overlay').removeClass('hidden');
},
complete: function() {}
});
});
In this case, the 'send' and 'complete' functions are not being executed, while 'container' and 'fragment' is working well. Why is this and what do I need to do to make Pjax recognize my functions?
By the way: I can not use the conventional form of using Pjax, I need more control about the happening, so I need to use the $.pjax.click object. Yet it would work fine with the functions in the common way like in the following:
$(document).pjax('a.inferno-preview', '#preview-overlay', {
send: function() { alert('this will work.'); }
});

In pjax send and complete events are not called if a request if retrieved from cache so you will not get your overlay down. Instead use success or complete depending on your particular use case.

Related

jQuery wait for a function to complete before new fires

I have two functions in jQuery that I want to fire in a specific order. The first function is an ajax function which updates a partial view. The other one is supposed to do some styling on the partial view, once the ajax function has completed - this function takes a parameter.
ajaxFunction();
stylingFunction(params);
I have tried the following:
ajaxFunction(function() {
stylingFunction(params)
});
Also, I have tried to use a callback:
ajaxFunction(stylingfunction(params));
ajaxFunction(callback)
{
//Do update
callback()
}
None of these do however work. The styling appears shortly where after it dissapears because the partial view is getting updated. Where am I going wrong here?
Both functions are written in my "parent" view.
You can use .done() and .fail() chained to the $.ajax call ...
I created a couple callback functions with psuedo-code inside the successCallback() since you said you only need to run the styling function "sometimes". You will want to test whatever condition inside that function to determine if you want to run the styling function. Hope this helps.
(function($) {
$(function() { //document.ready
$.ajax({ cache: false,
url: "/blah/vlah/lah",
data: { somedata: somedata }
})
.done(successCallback)
.fail(failCallback);
});
function successCallback(data) {
if (someCondition) {
stylingFunction(params);
}
};
function failCallback(jqXHR, status, error) {
console.log(jqXHR);
console.log(error);
console.log(status);
};
})(jQuery);
I created another gist which handles ajax event delegation, you may want to review and incorporate anything that seems helpful to your situation.
https://gist.github.com/inceptzero/a753d020648f49da90f8
I also created this gist on github for an ajax request queue which is a bit more elegant and robust.
https://gist.github.com/inceptzero/e64756f9162ca6aeeee5
Since you are using jQuery you could const ajaxFunc = callback => $.ajax({...}).done( data => callback) Also you could use async/await. You can read more about it on MDN.

Global ajaxSuccess event before local success event

I have an ASP MVC application that lets a user add multiple partial views to a div with jQuery ajax calls.
jQuery("#AddNew").click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) {
jQuery("#DivId").append(html);
}
});
return false;
});
The problem is that since a user must be authorized for the action returning the partial view, when a user's session has timed out, it is rendering the login page instead of the partial view. I have multiple places that are using similar ajax calls, so I added the following as a global ajaxSuccess event:
jQuery(document).ajaxSuccess(function (event, request, settings) {
var isLogin = jQuery(request.responseText).find('.login-form').length;
if (isLogin > 0) {
var url = document.URL;
var rootPath = '#Request.Url.GetLeftPart(UriPartial.Authority)';
var path = url.replace(rootPath, '');
var pathEncoded = encodeURIComponent(path);
var loginURL = rootPath + "/Account/Login?returnUrl=" + pathEncoded;
location.href = loginURL;
}
});
This works, as it will redirect the user to the login page when an unauthorized ajax request is made. However, it is still adding the html to the div, which is visible for a short time before the redirect.
Is there a way to get the global event to trigger before the local one? The jQuery API shows that the local success event is triggered before the global ajaxSuccess event, so I tried changing the ajax call to use complete, rather than success. This does work, but it seems like if for some reasons I needed to add code in the future that only executes on success, that I'll run into the same problem. Is there a better way to handle this?
I might advise creating your own API wrapping the ajax method which ensures the functionality you desire (in particular, the order of operations). Here's a very over-simplified example:
var async = function(props) {
var finished = $.Deferred();
$.ajax(props)
.done(function(response) {
// detect auth timeout, handle consisently
if(response.isAuthTimeout) {
// render login ui
finished.reject('auth-timeout');
} else {
finished.resolve.apply(finished, arguments);
}
})
.fail(function() {
finished.reject.apply(finished, arguments);
})
return finished;
};
Then, in practice you'll make calls to async (or whatever you decide to call your wrapper) rather than the native $.ajax API.
Make sense?

What is a proper way to add listeners to new elements after using AJAX to get the html content? (jQuery, Javascript)

I am making something that can loads new setting pages via AJAX, I am not sure what's the most efficient way to bind listeners to those elements from the new content page?
Here's my thought. I can make a function that compares file path, and for each condition, then I will apply correct listeners to those new elements based on what page that AJAX loaded. I feel like it will makes the function so big if I have a large amount of pages.
Thanks!
Two ways:
1) Bind on a non-dynamic parent container using .on()
$('.some-parent-class').on('click', '.element', function() {
// DO STUFF!
});
2) Bind the new elements after ajax call is completed
$.ajax(url, {
// ajax options
}).done( function(data) {
var newEl = $('<div class="element"></div>');
// Setup your newEl with data here...
newEl.on('click', function() {
// do stuff
});
newEl.appendTo($('.some-parent-class'));
});
The former usually results in quicker ajax response times, but may also slow click responsiveness down.
Use jQuery's .on() to handle event delegation. The first element you supply is a static element (never removed / replaced). the first argument is the event you wish to delegate against, mouseover/click, etc. The 2nd argument is the element we wish to have the event fire on when the event occurs. The 3rd argument is the callback, which is the function to run when the event fires.
$(document).on('event', 'elementIdentifier', function(){
//your code
});
$(".parent-div").on("click", ".child-div-class-name" ,function(){
somefunction();
});
all the new inserted elements inside the .parent-div will be having the listeners onclick
Adding on to Populus' answer, which is great as it is, a logically equivalent solution to his second option would be to use Promises:
var iGotYou = new Promise(function (res, rej) {
$.ajax({
//ajax paramaters
})
.done(function( data ) {
//handle the data as necessary...
//then resolve the Promise
res();
});
});
//the Promise has been resolved
iGotYou.then(function (response) {
//add the event listener now that the promise has been fulfilled
document.getElementById('someId').addEventListener('click', function (e) {
//whatever you want to do on click event
});
})
I'm not entirely sure what you're asking here, but you can use jQuery's .on() function to bind to elements that already exist in your document, OR elements that will exist in the future.
Here's a quick example:
$(document).ready(function () {
$(document).on('click', '#new-button', function() {
alert("You clicked the new button");
});
//get some HTML via ajax. Let's assume you're getting <button id="new-button">Click me</button>
$.get('url', function(res) {
$('body').append(res);
});
});

Adding in loading and error text with jQuery Ajax

I was wondering how easy is to to expand this code so that it shows an error if it cannot connect and whilst it is connecting it shows a loading text or loading image. It seems pretty standard behaviour on ajax driven sites but I haven't found much useful information online on how to achieve it.
$(document).ready(function () {
var loadUrl = 'http://sheldonbrown.com/web_sample1.html';
$("#close").click(function () {
$("#country_slide").hide();
});
$("#country").click(function () {
$("#country_slide").show();
$("#country_slide").html(ajax_load).load(loadUrl);
});
});
Depending on the context of your application, you can subscribe callbacks to fire on certain global AJAX events. Say, whenever an AJAX call starts, or whenever an AJAX call throws an error.
$(document)
.ajaxStart(function (e) {
$('body').showMyAwesomeLoadingGIF();
})
.ajaxComplete(function (e) {
$('body').hideMyAwesomeLoadingGIF();
});
This will cause those two callback functions to fire during the appropriate lifecycle events on every AJAX call made in your document.
If, for some reason, you want a certain AJAX call not to trigger your global AJAX event handlers, you can specify that that particulat AJAX call is not global.
$.ajax({
global : false,
// blah
})
More information on global AJAX event handling here.
EDIT
If you want to maintain a bit more granular control, there's $.ajaxSetup(), but since jQuery themselves discourages its use, I'm thinking you might be left with having to fashion your own solution.
Personally, I'd use a wrapper function with a closure to set my custom option values if they're something you expect to do repeatedly.
var ajax = (function () {
var defaults = { };
return function (opts) {
opts = $.extend({}, defaults, opts);
// place what you want to happen when an AJAX call starts here
return $.ajax(opts)
// place corresponding events here
.done(function (m) {
})
.fail(function (x,s,e) {
})
.complete(function (m) {
});
};
}());
// then use that in your code like how you'd use $.ajax():
ajax({
url : 'http://my.domain.com/api/users',
type : 'GET'
}).done(function (m) {
console.log('Done GET users.');
});
// ... and you can be sure that it has default options and default event handlers,
// while being able to add on to them if you wish.

Clearing a jquery document.ready() call

How do I clear out anonymous functions that are set to trigger via a jQuery document.ready() call?
For example:
<script type="text/javascript">
//some code sets a doc ready callback
$(document).ready(function ()
{
alert('ready');
});
//my attempt to prevent the callback from happening
window.onload = null;
$(document).unbind("ready");
</script>
The alert happens regardless of my attempts to circumvent it. Is there any way to do this?
You'd probably get the most appropriate answer if you described what problem you're really trying to solve.
jQuery doesn't have a publicly documented way to undo or block document.ready() handlers. If you control the code, you can use a global variable and a conditional like this:
var skipReady = false;
$(document).ready(function ()
{
if (!skipReady) {
alert('ready');
}
});
// skip the document.ready code, if it hasn't already fired
skipReady = true;
Or, if you want to hack into jQuery a bit (beyond the documented interfaces), you can do this:
$(document).ready(function() {
alert("ready");
});
// stop the ready handler
$.isReady = true;
You can see this last one work here: http://jsfiddle.net/jfriend00/ZjH2k/. This works because jQuery uses the property: $.isReady to keep track of whether it has already fired the ready handlers or not. Setting it to true makes it think it has already fired them so it won't every do it again.
This works:
$(document).bind("ready", function () { alert("hey!"); });
$(document).unbind("ready");
Seems like a bug to me - all other events in jQuery are able to be unbound. Omitting this one is inconsistent.
Not a direct answer as to the omission, but here's some related info from jQuery docs:
All three of the following syntaxes are equivalent:
$(document).ready(handler)
$().ready(handler) (this is not recommended)
$(handler)
There is also $(document).bind("ready", handler). This behaves similarly to the ready method but with one exception: If the ready event has already fired and you try to .bind("ready") the bound handler will not be executed. Ready handlers bound this way are executed after any bound by the other three methods above.
$(document).ready() is dependent on the onLoad event which is triggered by the browser meaning you can not prevent it from happening. If the alert() is determined by some condition then I would use an if/else statement to decide whether it is called.
Super old question, but came across the need to do this recently to prevent document.ready code I didn't control from running in certain instances. This can be achieved by proxying jQuery's ready function, rather like a test spy. The following will work:
var ready = $.prototype.ready;
// proxy the ready function
$.prototype.ready = function ( fn, allowed ) {
allowed = allowed || false;
if ( allowed ) {
ready.call( this, fn );
}
};
All calls to $( document ).ready will now be ignored. You can override this behaviour by passing true as the second argument: $( document ).ready( fn, true )

Categories