JQuery - callback on function? ($.Deferred) - ajax

I currently have a function that looks like this:
$(function(){
$('.chained_to_vehicle_make_selector').remoteChainedTo('.chained_parent_vehicle_make_selector', '/models.json');
$('.chained_to_vehicle_model_selector').remoteChainedTo('.chained_parent_vehicle_model_selector', '/trims.json');
$('.chained_to_vehicle_trim_selector').remoteChainedTo('.chained_parent_vehicle_trim_selector', '/model_years.json');
});
As you can probably tell, each remoteChainedTo function is making an AJAX call, which is working fine, but takes a bit of time.
I then have a second code block:
$(function() {
$(".chzn-select").chosen();
$(".chained_parent_vehicle_make_selector").chosen().change( function() {$(".chained_to_vehicle_make_selector").trigger("liszt:updated"); });
$(".chained_parent_vehicle_model_selector").chosen().change( function() {$(".chained_to_vehicle_model_selector").trigger("liszt:updated"); });
$(".chained_parent_vehicle_trim_selector").chosen().change( function() {$(".chained_to_vehicle_trim_selector").trigger("liszt:updated"); });
$(".chained_child").chosen();
});
This section of the code works fine as long as it fires after the first section is complete. Because of the AJAX calls, however, it is currently firing before the previous section.
How can I implement a structure so that the second code block always fires after the first block is completely done? The remoteChainedTo function does not have a defined callback (that I can see), and in any case it would be impossible to know which of the three calls will finish last, hence wanting to put the callback somehow on the block, so that the second section of code fires only after the last AJAX call completes.
EDIT: After a bit more refactoring, my code now looks as follows:
function makeChains(){
$('.chained_to_vehicle_make_selector').remoteChainedTo('.chained_parent_vehicle_make_selector', '/models.json');
$('.chained_to_vehicle_model_selector').remoteChainedTo('.chained_parent_vehicle_model_selector', '/trims.json');
$('.chained_to_vehicle_trim_selector').remoteChainedTo('.chained_parent_vehicle_trim_selector', '/model_years.json');
}
var chainCall = $(function() {
makeChains();
});
chainCall.done(function() {
$(".chzn-select").chosen();
$(".chained_parent_vehicle_make_selector").chosen().change( function() {$(".chained_to_vehicle_make_selector").trigger("liszt:updated"); });
$(".chained_parent_vehicle_model_selector").chosen().change( function() {$(".chained_to_vehicle_model_selector").trigger("liszt:updated"); });
$(".chained_parent_vehicle_trim_selector").chosen().change( function() {$(".chained_to_vehicle_trim_selector").trigger("liszt:updated"); });
$(".chained_child").chosen();
});
But i'm still getting the error Object [object Object] has no method 'done'. Any hints appreciated.

Related

how to use callback when I click ajax in nightmarejs

lately I have been studing nightmare module I think it's very simple and useful but I have question.
how to use callback when I click ajax button
MyCode
var Nightmare = require('nightmare'),
nightmare = Nightmare();
nightmare
.goto('https://motul.lubricantadvisor.com/Default.aspx?data=1&lang=ENG&lang=eng')
.click('input[title="Cars"]')
.wait(1000)
.evaluate(function () {
//return $('#ctl00_ContentPlaceHolder1_lstModel option');
var links = document.querySelectorAll('#ctl00_ContentPlaceHolder1_lstMake option');
return [].map.call(links, function (e) {
return {value: e.value, name: e.text};
});
})
.end()
.then(function (items) {
console.log(items);
});
there is wait method. most people use wait methed I searched googling
.wait(1000)
I don't use wait method. because If it's network disconnect or slow. It's not good code
Could you help me callback method??
Thanks. So I have motify the code but It's doesn't work
var Nightmare = require('nightmare'),
nightmare = Nightmare();
nightmare
.goto('https://motul.lubricantadvisor.com/Default.aspx?data=1&lang=ENG&lang=eng')
.click('input[title="Cars"]')
.wait('#result > #ctl00_ContentPlaceHolder1_lstMake option')
.evaluate(function () {
$(document).ajaxSuccess(function () {
var links = document.querySelectorAll('#ctl00_ContentPlaceHolder1_lstMake option');
return [].map.call(links, function (e) {
return {value: e.value, name: e.text};
});
});
})
.end()
.then(function (items) {
console.log(items);
});
There are many ways to solve this. The easiest would be the following.
Suppose when an Ajax request finishes, it always changes something on the page. Most of these changes can be easily detected when waiting for specific elements to appear which can be matched by CSS selectors.
Let's say you click something and the result is written into the element matched by "#result". If there wasn't such an element before the click then you can wait until the existence of this element:
.click("button")
.wait("#result")
// TODO: do something with the result
You can also use CSS selectors to count things. For example, let's say there are ten elements that can be matched with "#result > a". If a click adds 10 more, then you can wait for the 20th using:
.click("button")
.wait("#result > a:nth-of-type(20)")
// TODO: do something with the result
The world of CSS selectors is pretty big.
Of course, you could use evaluate to add a general Ajax event handler like $(document).ajaxSuccess(fn) to be notified whenever some callback finished, but the source code of a page changes all the time. It would be easier to maintain your code if you would look for the results that can be seen in the DOM.
Use this, ajax callback..
$.ajax(url,{dataType: "json", type: "POST" })
.then(function successCallback( data ) { //successCallback
console.log(data);
}, function errorCallback(err) { //errorCallback
console.log(err);
});
// console.log(2);
});

BackboneJS .ajaxStart() and .ajaxStop() while fetching collection

I have a BackboneJS App where I fetch a bunch of collections. Now I want to apply some sort of loader to indicate that the collection is loading and the user gets to know that something is happening. So I want to use the .ajaxStart() and .ajaxStop()-method. So I was thinking about something like this:
this.artistsCollection.fetch(
$(document).ajaxStart(function () {
console.log('ajax start');
$('.someDiv').addClass('TEST');
}),
$(document).ajaxStop(function () {
console.log('ajax stop');
// stop doing stuff
})
);
Issue is that first time I trigger the .fetch() my console says ajax stop and the class is not applied!?!? Second time I trigger the .fetch() it works like it should and the class gets applied. Does anyone know whats the issue?
Please help anyone?
You're passing the returned result of adding the two event handlers with jQuery as parameters to the Collection fetch method. The Backbone Collection fetch method receives an options object which can include a success callback (see documentation).
I think if you move the listeners out of the method call it should work as you expect:
// Global AJAX listeners
$(document).ajaxStart(function () {
console.log('ajax start');
// do stuff
});
$(document).ajaxStop(function () {
console.log('ajax stop');
// stop doing stuff
});
this.artistsCollection.fetch();

jQuery Mobile transitions and AJAX Polling on a MasterPage

I am trying to use AJAX polling with jQuery to update a span element on a razor MasterPage in ASP.NET MVC3. The page uses the jQuery Mobile 1.0 framework that adorns simple view changes (like navigating from /home to /about) with some sort of "transition" animation.
This is the Javascript code that does the polling, while the "unreadBubble" span is located in the body - both are defined in the MasterPage!
<script type="text/javascript">
$(document).bind("pageinit", function poll() {
setTimeout(function () {
$.ajax({ url: "/Notification/GetUnreadNotificationsCount",
dataType: "json",
success: function (data) {
$('#unreadBubble').text(data.UnreadCount);
poll();
}
});
}, 1000);
});
So, imagine I have a HomeController and a NotificationController that both use the MasterPage and provide an Index view. The AJAX polling works on both views and updates the span every second as expected. As soon as I navigate from one view to another though, the span gets re-initialized with its default value from the MasterPage (empty) and doesn't update anymore. Interestingly the async GetUnreadNotificationsCount method is still called on the NotificationsController repeatedly - the span just doesn't update. I also tried to alert the span tag in JS and it wasn't null or something.
According to the documentation, jQuery Mobile also loads new pages with AJAX to insert this fancy "SWOOSH" transition animation. This seems to somehow disturb the JS/DOM initialization.
Do you have any idea how to resolve this? Should I bind to another event or can I somehow force the span tag to update?
Solution: It was a caching problem! The following did the trick:
Add class="command-no-cache" to your page div add the following JavaScript to the MasterPage:
$(":jqmData(role=page)").live('pagehide', function (event, ui) {
if ($(this).children("div[data-role*='content']").is(".command-no-cache"))
$(this).remove();
});
I would use the pagebeforeshow to actually bind the event, and pagehide to remove the event.
Did you try that instead of initializing only once in the pageinit event?
UPDATE: some code for example,
<script type="text/javascript">
var timer = null;
$(":jqmData(role=page)").bind("pagebeforeshow", function() {
timer = setTimeout(function() {
$.ajax({ url: "/Notification/GetUnreadNotificationsCount",
dataType: "json",
success: function (data) {
$('#unreadBubble').text(data.UnreadCount);
}
});
}, 1000);
});
$(":jqmData(role=page)").bind("pagehide", function() {
if (timer != null){
clearTimeout(timer);
timer = null;
}
});
</script>
Also corrected some other ""mistypes" along the way, have a look and compare to your code!
Hope this helps

Return false not working for jQuery live

Well this has me well and truly stumped. After searching for the last few hours I still cannot seem to work out where I am going wrong.
I am trying to append an AJAX response to a container when it gets clicked. That works fine but I don't want it to append another object when the elements from the AJAX response also gets clicked.... so:
<div id="container">
<!-- AJAX response to get inserted here, for example -->
<span id="ajaxResponse"></span>
</div>
Here is my script:
$('#container').click(function(e) {
var current_el = $(this).get(0);
$.ajax({
url: 'text.html',
success: function(data) {
$(current_el).append(data);
}
});
return false;
});
So it works fine but for some reason the click event on #container also fires when I click on the AJAX response span!?
According to jQuery documentation:
To stop further handlers from
executing after one bound using
.live(), the handler must return
false. Calling .stopPropagation() will
not accomplish this.
But unless I am mistaken, I am calling false? :(
Anyone help me out on this?
UPDATED:
So the only way I can get it to work is by updating my code to this:
$('#container').live('click', function() {
var current_el = $(this).get(0);
$.ajax({
url: 'text.html',
success: function(data) {
$(current_el).append(data);
}
});
});
$('#ajaxResponse').live('click', function(e) {
return false;
});
This seems a little messy though... anyone have a better solution?
Where is live part you mention in the title of the question ?
It is how the event model works.. If you click on element which does not handle the event, the event will travel up the DOM hierarchy until it finds an element that handles the click (and stops its propagation..). Otherwise you would not be able to put an image inside a <a> tag and click on it..
You can bind a canceling handler on the inner element assuming you have someway to target it..
$.ajax({
url: 'text.html',
success: function(data) {
$(current_el).append(data);
// assuming the returned data from ajax are wrapped in tags
$(current_el).children().click(function(){ return false;});
}
});
I think the return false is referring to something else in this case...
you should try calling stopPropagation() - this should stop the "click" function from propagating down to the ajaxResponse span....
One option that you may want to try is switching over to using live(). Essentially, the click event you setup is calling bind(), and the solution you referenced is using live() which is a variation on bind().
For example:
$('#container').live("click", function(e) {
var current_el = $(this).get(0);
$.ajax({
url: 'text.html',
success: function(data) {
$(current_el).append(data);
}
});
return false;
});
HTH

jQuery Submit Function Does Not Work (Inner Function)

I have a problem with this jQuery code. It doesn't work as expected:
$('#select_dropdown').change ( function(){
$('#form_to_submit').submit( function(event){
$.post("list.php", { name: "John", time: "2pm" },
function(data) {
alert("Data Loaded: " + data);
});
});
});
However, this works:
$('#select_dropdown').change ( function(){
$('#form_to_submit').submit();
});
I wonder why the internal function on submit doesn't work. When a user selects a value from a dropdown, the form must be submitted. The second set of codes work but if I add an inner function to submit, it doesn't.
Basically, I want to do some ajax call after the user select on the dropdown.
According to documentation ( http://api.jquery.com/submit/ ), submit() without parameters will submit your form, but if you include arguments it will bind the submit event to the form, but it wont submit it.
So, the code posted by #Chris Fulstow would be the right way of submitting the form, but as ajax is not synchronous, function will continue without waiting for the answer and then, the alert will not be shown.
You can make it synchronous, but you must use $.ajax instead of $.post, because $.post doesn't include an async option. Anyway, I'm providing a solution for your specific problem, but I'm guess there should be a better way for doing it.
$(function() {
$('#select_dropdown').change(function() {
$('#form_to_submit').submit();
});
$('#form_to_submit').submit(function(event) {
$.ajax(
url: "list.php",
data: { name: "John", time: "2pm" },
success: function(){
alert("Data Loaded: " + data);
},
async:false,
);
});
});
When you call with a callback argument submit( handler(eventObject) ) it will only attach an event handler. To trigger a form submit, call submit() with no arguments:
$(function() {
$('#select_dropdown').change(function() {
$('#form_to_submit').submit();
});
$('#form_to_submit').submit(function(event) {
$.post(
"list.php",
{ name: "John", time: "2pm" },
function(data) {
alert("Data Loaded: " + data);
}
);
});
});
The .submit call in your first example is binding a function to the submit event on the form. From the fine manual:
.submit( handler(eventObject) )
handler(eventObject) A function to execute each time the event is triggered.
You need to bind your submit handler:
$('#form_to_submit').submit(function(event){ /*...*/ })
somewhere else and call submit as in your second example.
So the problem here is that in the first case, you are binding an event handler to the element, and in the second you are triggering it. Let's look at the first case:
$('#form_to_submit').submit(function(evt){ ... });
You're essentially doing something like
document.getElementById('form_to_submit').addEventListener(
'submit',
function(evt){...},
false
);
The second case is you instructing the form to submit, which is why it works. If you wanted the handler to work with your custom code you would need both of them. First bind your event handler, then, onchange instruct the form to submit.
$('#form_to_submit').submit(function(evt){ ... });
$('#select_dropdown').change(function(){
$('#form_to_submit').submit();
});
Keep in mind though, that as other people have already said, if your action is set to go to another location, you may not see the results of the binded event handler so instead of explicitly stating a url for your action, you will have to use something to prevent the form from going anywhere like action="javascript:void(0)" or the like.
To make your code a bit cleaner, you could pull the ajax out of an unnamed function and put it in a named one and call it on change so it looks like this.
var fetchList = function(){
$.ajax(...);
};
$('#form_to_submit').submit(fetchList);
$('#select_dropdown').change(fetchList);
I haven't run this code, please excuse any silly syntax mistakes I've made. But this should get you some of the way there. Good luck! :)

Resources