My problem is better explained in code:
//This code is triggered before ajax ObBegin. But I need f1 to return a boolean to either cancel or continue the event.
f1();
function f1(){
$.modalWindow.Open(); //This is an async method, this is where my problem lies.
//I need to freeze here and wait on a return value from one of the events below.
}
//In the modal window:
//An event which waits for the click event
$('.cancelBtn').click(function(){
//How do I send false back to f1?
closeModalWindow();
});
$('.yesBtn').click(function(){
//How do I send true back to f1?
closeModalWindow();
});
So basically what happens is this:
openModalWindow() opens a modal window that waits on a button click.
I want to pass the value back to f1 and return it.
Is there a way to fix this?
Use jQuery's Deferred objects. There's a good tutorial on it here, but you haven't actually shown enough of your own code for me to demonstrate how to wire it up with $.Deferred.
Here's a very basic demo of how to do this: http://jsfiddle.net/mattball/fNQ8J/. Basically, you have to pass callbacks around for asynchronous execution.
function openModalWindow(callback) {
if (typeof callback !== 'function') callback = $.noop;
$("#dialog-confirm").show().dialog({
resizable: false,
modal: true,
buttons: {
Yes: function() {
$(this).dialog("close");
callback(true);
},
No: function() {
$(this).dialog("close");
callback(false);
}
}
});
}
function f1() {
return $.Deferred(function(dfd) {
openModalWindow(dfd.resolve);
}).promise();
}
$('#clickme').click(function() {
f1().then(function(result) {
alert('f1 async returned: ' + result);
});
});
There's no good way to do this, no. You'll have to refactor f1 so it can deal with asynchronicity.
f1() should be implemented as a callback for someAsyncFunc():
function someAsyncFunc(callback) {
// open your modal window
$(".theBtm").click(function() {
// do your stuff
if (typeof(callback) === "function") {
callback(theValueYouWantToPass);
}
});
}
Called something like this:
someAsyncFunc(function(value) { f1(value); });
Related
Please check out my diagram, and the pseudo-code below. I'm trying to figure out how to pass a function between two event listeners.
Basically, I want to execute some code if "Availability" is less than 0, OR when a user clicks "confirm" in a bootstrap dialog. If the Availability is greater than 0, you'll get the special bootstrap dialog.
I'm trying to avoid writing the same code twice. I'm also trying to avoid using trigger $("#btnConfirm").trigger("click", fn1); --- my assumption is that there is a sexier way, like a callback, or something...
So.... how do I get the code I want to execute into the other 'button click' event listener --OR-- how do I return "btnConfirm" back to the event listener that called the dialog?
$("#Select").on("change", function(e) {
fn1 = function() {
//stuff I want to do
};
//a check that must be passed
currAvail = $("#Availability").val();
if (currAvail > 0) {
//show a message, "Are you sure you want to make the thing?"
//if YES, execute fn1()
//fn1() needs to be available to btnConfirm click listener
// use trigger("click", fn1) ????
} else {
//execute the code
fn1();
};
});
$("#btnConfirm").on("click", function(e, param1) {
//Ok, well, they said YES...
//so I need to execute fn1();
});
Since the requirement is to call fn1() in both cases, you can separate the logic out into a method and call when it is needed
function fn1() {
//code to execute on no goes here
}
$("#Select").on("change", function(e) {
let currAvail = $("#Availability").val();
if (currAvail > 0) {
//show modal window
} else {
//execute the code
fn1();
};
});
$("#btnConfirm").on("click", function(e, param1) {
fn1()
});
Why not just move the function definition to outside the change callback?
$("#Select").on("change", function(e) {
//a check that must be passed
currAvail = $("#Availability").val();
if (currAvail > 0) {
//show a message, "Are you sure you want to make the thing?"
//if YES, execute fn1()
//fn1() needs to be available to btnConfirm click listener
// use trigger("click", fn1) ????
} else {
//execute the code
fn1();
};
});
$("#btnConfirm").on("click", function(e, param1) {
//Ok, well, they said YES...
//so I need to execute fn1();
});
// Function move to here.
function fn1() {
//stuff I want to do
};
I have the following function that creates a dialog and is using jQuery deferred to wait for the user response:
function myPageUnsaved() {
var defer = $.Deferred();
$('<div></div>')
.html('You have unsaved changes. Leave this page and lose your changes?')
.dialog({
autoOpen: true,
modal: true,
title: 'Confirmation',
buttons: {
"No": function () {
defer.resolve("false");
$(this).dialog("close");
},
"Yes": function () {
defer.resolve("true");
$(this).dialog("close");
}
},
close: function () {
$(this).dialog('destroy').remove();
}
});
return defer.promise();
}
I call the function within the js below:
// function to check for user changes prior to navigating to a new page
function checkPageChange() {
if (pageChanges == true) {
myPageUnsaved().then(function (answer) {
// if user answered no, stay on the page
if(answer == 'false') {
return false;
// else the user answered yes, so leave the page
} else {
return true;
}
});
} else {
return true;
}
}
I am running jQuery 1.11.
The dialog is presented to the user, but immediately is removed. What am I missing?
The pattern used seems correct, my initial answer was incorrect. .promise is a method of deferred and all member methods can be seen here. http://api.jquery.com/category/deferred-object/
Example of the code provided by original poster which seems to work in jsfiddle
https://jsfiddle.net/n7ewqfc0/
Initial answer - incorrect asumptions
Have you tried just returning the defer as opposed to defer.promise(); That doesn't seem right to me.
Looking at the spec for Deferred there is no reference to the promise method.
https://api.jquery.com/jquery.deferred/
Obviously I have hugely simplified your code to provide a resolving Promise but the principles are the same. You must return the promise object i.e. Deferred to be able to use the promise based callbacks .then etc.
function myPageUnsaved() {
var defer = $.Deferred();
setTimeout(function(){
defer.resolve('hey back from inside the promise')
}, 2000)
return defer;
}
var p = myPageUnsaved()
p.then(function(response){
console.log(response)
})
I thought this is something easy to do but I dont find anything helping me out of this.
I have a function
(function($){
myFunction = function(e){
e.preventDefault();
// do stuff
// load ajax content
// animate and show
}
$('.button').on( 'click', myFunction);
})(jQuery);
now this works but I need to know, wait untill everything is done if someone presses many .buttons in a short time cause there are a few elements with class button
I've tried with promise()
$('.button').on( 'click', function(){
$.when( myFunction() ).done(function() {
alert('finished')
});
});
but that gives me an error e is undefined and
$('.button').on( 'click', myFunction).promise().done(function() {
alert('finisehd');
});
anyone knowing what I'm doing wrong and how I could do it to get it to work?
The most common solution would be to set a variable inside the click handler when myFunction is called and check its state with every call of the click handler.
This could be done somewhere along the lines of this:
(function($){
var wait = false;
myFunction = function(e){
e.preventDefault();
if (wait) {
return;
}
wait = true;
// ...
wait = false;
}
$('.button').on( 'click', myFunction);
})(jQuery);
Your function myFunction expects one argument, when you call myFunction() the argument is missing.
Not tested but it should works:
$('.button').on( 'click', function(e){
$.when( myFunction(e) ).done(function() {
alert('finished')
});
});
In addition to not passing in the e variable. You're using $.when incorrectly.
If you want to have the done function called after myFunction finishes its ajax call. You'll need to return a promise from myFunction.
function myFunction(e) {
return $.Deferred(function(deferred) {
doAjax(function(content) { // callback
deferred.resolve(content);
});
});
}
Now when you do
// inside event handler
$.when(myFunction(e)).done(function(content) {
// whoo!
});
I have 2 functions. First contains Jquery-UI dialog and called from the Second function. Something like :
function First() {
$('div').dialog({
buttons: {
"Ok": function () { /* code */
}
}
});
}
function Second() {
First();
/* rest of this function code is depend upon the "Ok button"
function code */
}
Now my problem is that after calling function First the execution of script doesn't wait for dialog's Ok button press. Whats should i do, so that only after pressing the Ok button, the control return from the function First?
Move from the function Second the part after calling First into a 2nd function (here called SecondOkHandler). Call First with a new parameter (this callback function) and in the function First on 'ok' call this:
function First(okCallback) {
$('div').dialog({
buttons : {
"Ok" : okCallback
}
});
}
function Second () {
First(SecondOkHandler);
}
function SecondOkHandler() {
/* rest of this function code is depend upon the "Ok button" function code */
}
Also see this example.
=== UPDATE ===
To make it more complex, here a link to an example with more callbacks.
This is because you have given a parenthesis First() this will make a call to that function as soon as the parser encounter that line.
You can make use of the one of the 2 Javascript methods of calling the function apply or call. By using this your function will not execute as soon it is encounter.
Check out this reference http://odetocode.com/blogs/scott/archive/2007/07/05/function-apply-and-function-call-in-javascript.aspx
Try using this and let me know if it is not working.
function First(waitTillOk) {
$('div').dialog({
buttons: {
"Ok": function () {
/* code */
if(typeof waitTillOk == "function"){
waitTillOk();
}
}
}
});
}
function Second() {
var waitTillOk = function(){
/* rest of this function code is depend upon the "Ok button"
function code */
}
First(waitTilOk);
}
I'm creating a plugin that replaces alerts/confirms for a project and I was curious if there was a way to make it like a real confirm where you can do:
if(confirm('Yes or no?')){alert('You agreed!');}
Right now I could do with a call back using this syntax:
$.alert('yes or no',{type:'confirm'});
But i want to be able to do:
if($.alert('yes or no',{type:'confirm'})){/*some action on true*/}
Here is what I have so far and look for the all CAPS comments in the click event (remember, this is still in development, so the HTML and stuff is still a little icky):
(function($) {
$.alert = function(message,options) {
defaults = {
type:'alert',
callback:function(){}
}
options = $.extend({},defaults,options);
if(options.type == 'confirm'){
$('<div style="display:none" class="alerthiddenoverlay"></div><div style="display:none" class="customalertbox"><div><img src="http://cdn.iconfinder.net/data/icons/basicset/tick_48.png"><p>'+message+'</p><br class="clear"><span><a class="cancel" href="#cancel">Cancel</a><a class="ok" href="#ok">OK</a></span><br class="clear"></div></div>').prependTo('body');
}
else{
$('<div style="display:none" class="alerthiddenoverlay"></div><div style="display:none" class="customalertbox"><div><img src="http://cdn.iconfinder.net/data/icons/basicset/warning_48.png"><p>'+message+'</p><br class="clear"><span><a class="ok" href="#ok">OK</a></span><br class="clear"></div></div>').prependTo('body');
}
$alertboxclass=$('.customalertbox');
$alerthiddenoverlay=$('.alerthiddenoverlay');
$alertboxclass.find('a').click(function(event){
event.preventDefault();
var the_return = false;
if($(this).attr('href') == '#ok'){
var the_return = true;
}
$alertboxclass.fadeOut(250,function(){$alerthiddenoverlay.delay(250).fadeOut(250,function(){$(this).remove();options.callback.call(this,the_return);});$(this).remove()});
});
$alertboxclass.css({
top:$(window).height()/2-$alertboxclass.height()/2,
left:$(window).width()/2-$alertboxclass.width()/2
});
$alerthiddenoverlay.css({height:$(window).height()+'px',width:'100%',position:'fixed',zIndex:'9998'}).fadeIn(250,function(){$alertboxclass.delay(250).fadeIn()});
}
})(jQuery);
I think passing a callback method in as a parameter to the $.alert function is going to be the easiest option. If that's a deal-breaker though, I might look at the .queue() method for chaining the events.
http://api.jquery.com/queue/
I saw a nice confirm() overwrite to a modal window as an example of jqModal
Here is the code sample. I'm sure you can adapt it to your need...
/* Overriding Javascript's Confirm Dialog */
// NOTE; A callback must be passed. It is executed on "cotinue".
// This differs from the standard confirm() function, which returns
// only true or false!
// If the callback is a string, it will be considered a "URL", and
// followed.
// If the callback is a function, it will be executed.
function confirm(msg,callback) {
$('#confirm')
.jqmShow()
.find('p.jqmConfirmMsg')
.html(msg)
.end()
.find(':submit:visible')
.click(function(){
if(this.value == 'yes')
(typeof callback == 'string') ?
window.location.href = callback :
callback();
$('#confirm').jqmHide();
});
}
$().ready(function() {
$('#confirm').jqm({overlay: 88, modal: true, trigger: false});
// trigger a confirm whenever links of class alert are pressed.
$('a.confirm').click(function() {
confirm('About to visit: '+this.href+' !',this.href);
return false;
});
});