$("#div1, #div2").fadeIn('500',function(){
{
console.log('Test');
}
});
Fiddle here: http://jsfiddle.net/y97h9/
The above code will print 'Test' two times in the console. How can I make it print only one time. Is it possible?
Sure, you can use jQuery promise to solve multiple callbacks problem:
$("#div1, #div2").fadeIn('500').promise().done(function()
{
console.log('Test');
});
The .promise() method returns a dynamically generated Promise that is
resolved once all actions of a certain type bound to the collection,
queued or not, have ended
Working Demo
The callback will run once for every matched element. You can always set a flag to see if it's been run already though:
var hasRun = false;
$("#div1, #div2").fadeIn('500', function() {
if (hasRun) return;
console.log('Test');
hasRun = true;
});
Use a boolean flag to prevent console.log('Test'); from being called twice.
var isCalled = false;
$("#div1, #div2").fadeIn('500',function(){
if(!isCalled) {
isCalled = true;
console.log('Test');
}
});
Related
I'm tryng to do some jQuery stuff when both instagramLoadError and imagesLoaded functions have been loaded.
For this I'm using if(instagramLoadError() && imagesLoaded()){}) but it's not working as expected.
I'm just starting with JS but I read something about "scope" saying that I can't target my instagramLoadError and imagesLoaded functions since it's not within the same scope. For this reason or another I'm still getting the "x function is not defined" error.
What should I do in this case?
$(document).ready(function(){
(function(){
new InstagramFeed({
'on_error': function instagramLoadError(){
return true;
}
});
})();
});
$(document).ready(function(){
$('#myDiv').imagesLoaded(function(){
return true;
});
});
$(document).ready(function(){
if(instagramLoadError() && imagesLoaded()){
// do some stuff if both instagramLoadError and imagesLoaded functions have been executed
}
});
Try like this:
$(document).ready(function() {
var isInstagramLoadError = false;
var isImagesLoaded = false;
(function() {
new InstagramFeed({
'on_error': function() {
isInstagramLoadError = true;
checkBoth();
}
});
})();
$('#myDiv').imagesLoaded(function() {
isImagesLoaded = true;
checkBoth();
});
function checkBoth() {
if (isInstagramLoadError && isImagesLoaded) {
// do some stuff if both instagramLoadError and imagesLoaded functions have been executed
};
};
});
The issue is that you are dealing with asynchronous callback functions. Each function will run when something happens (Instagram load error or images loaded) and the order of the two cannot be guaranteed. So to deal with this, have each function update a variable and then call a common function checkBoth() to check the variables.
you can use Promise.all method. which will wait for all promise to complete
$(document).ready(function(){
function Instagram(){
new InstagramFeed({
'on_error': function instagramLoadError(){
return true;
}
function images(){
$('#myDiv').imagesLoaded(function(){
return true;
}
Promise.all([Instagram(),images()]).then(res=>{
if(res[0] && res[1]){
// do some code
}
})
})
Promise. all will wait for functions to complete and store the data returning in an array.
I'm trying to wait the browser with browser.wait with a custom ExpectedCondition like this
The FunctionReturningANumber returns only a number and the numberToCheck is the number to check the number for.
var conditionFn = function () {
return functionReturningANumber(param) === numberToCheck;
};
var condition = EC.and(conditionFn);
browser.wait(condition, 50000);
But if I execute this, I get the error: fn(...).then is not a function which basically says, that it expects an promise. I have looked up the documentation about ExpectedConditions, and the example for a custom one is like this:
// You can define your own expected condition, which is a function that
// takes no parameter and evaluates to a promise of a boolean.
var urlChanged = function() {
return browser.getCurrentUrl().then(function(url) {
return url === 'http://www.angularjs.org';
});
};
And I do not see how here a promise is created. I only see, that a boolean is returned, and the documentation says evaluates to a promise of a boolean which confuses me even more.
This above is for waiting a response from an API, this is caused, because the test triggers a backend process, which protractor then needs to wait for. If there is any better way of doing this, I would greatly appreciate a better way.
I am using protractor 3.1.1.
Any help really apprectiated.
Edit:
I found a way to solve this, for some reason the logical solution by #alecxe didn't work, even if it makes sense:
var numberFound = 0;
var done = false;
var check = function () {
numberFound = functionReturnungANumber(param);
if (numberFound != numberToCheck) {
setTimeout(check, 4000);
} else {
done = true;
}
};
check();
return done;
If I add this to the function and retrieve the return value in the test, which calls this function, and add a browser.wait(function () {
return done;
}); there it works.
It's not beautiful, but for some reason, its the only thing working.... for me at least.
It's just that you don't need to wrap your Expected Condition function into EC.and:
browser.wait(conditionFn, 5000);
Try this one.
browser.wait(conditionFn () {
return url === 'http://www.angularjs.org';
}, 8000);
My current code is this and what I'm trying to is see if I could get a return value after the key up is done.
$("#confirm").keyup(function(event){
event.preventDefault();
ajax_pass_check();
});
so I would end up with something like this because my ajax_pass_check(); function returns true/false.
$("#confirm").keyup(function(event){
event.preventDefault();
return ajax_pass_check();
});
I would like to see if I could do that, and try something like
var one = $("#confirm").keyup(function(event){
event.preventDefault();
return ajax_pass_check();
});
I'm new to javascript and I've looked on google for awhile and I haven't found what I needed so I thought I'd ask. However when I did try that, I didn't get the expected result I was hoping for. Since var one remained false, when it should have been true after the function ajax_pass_check();
~edit: I took advice one of you guys (thanks for all the replies!) I still can't figure out why my var one variable false even though I set it to true in the keyup function.
$(document).ready(function(){
var one = false;
$("#confirm").keyup(function(event){
event.preventDefault();
one = ajax_pass_check();
//one = true; //even if I do that it doesn't work.
});
if(one == true)
{
$('input[type="submit"]').removeAttr('disabled');
}
else
{
$('input[type="submit"]').attr('disabled','disabled');
}
});
Instead of returning a value, you should consider using global scope for the variable, and set its desired value inside your function:
var wasSuccessful = false;
$("#confirm").keyup(function(event){
event.preventDefault();
your_function();
});
function yourfunction() {
if your awesome code worked { wasSuccessful = true; }
else { wasSuccessful = false; }
}
No, but you could call another function to use the result of ajax_pass_check. For example,
$("#confirm").keyup(function(event){
event.preventDefault();
doSomethingElse(ajax_pass_check());
});
function doSomethingElse(keyUpOk) { // Do something ... }
Assuming (based on your function names) you are using this to do some form of validation this will allow you to display or clear an error message.
The reason you cant do
var one = $("#confirm").keyup(function(event){
event.preventDefault();
return ajax_pass_check();
});
is because the key up function is just binding you function to the event, so this code will have already been executed when the key is released. You will probably want to call a function so that something is done with the result of the keyup event handler after the keyup event is fired, not when you function is bound to the event.
Try this instead
$(document).ready(function(){
var one = false;
$("#confirm").keyup(function(event){
event.preventDefault();
one = ajax_pass_check();
//one = true; //even if I do that it doesn't work.
if(one == true)
{
$('input[type="submit"]').removeAttr('disabled');
}
else
{
$('input[type="submit"]').attr('disabled','disabled');
}
});
});
The Answer is: No
The jQuery Function keyup doesnt return a special value, only the jQuery Object see the API(at the top), since it is used only to bind functions.
Depence on what you want to achieve, one of the solutions, mentioned by the others could solve your issue.
I need to have some functionality in my web app where a specific action occurs when the user clicks and holds on an element. Think of it like the long press on Android.
I have my div:
<div id="myDiv"
onmousedown="press()"
onmouseup="cancel()"
onmouseout="cancel()"
onmousemove="cancel()">Long Click Me</div>
and my javascript:
var down = false;
function press()
{
down = true;
setTimeout(function() { action(); }, 1500);
}
function cancel()
{
down = false; // this doesn't happen when user moves off div while holding mouse down!
}
function action()
{
if (!down)
return; // if the flag is FALSE then do nothing.
alert("Success!");
down = false;
}
This works as long as all I do is press and hold on the element. I have the onmouseout and onmousemove events to call cancel() because I want the user to have the option to change their mind and move the mouse off the element before action() starts.
Unfortunately, it seems that my code does not do this.
In fact, if the use clicks down for a moment, moves the mouse off the div and releases before the 1.5 sec then action() won't bail out as expected.
Edit: Thanks for your input everyone but it turns out I'm just a little bit special and didn't see that I forgot a capital letter in my HTML in my onmouseout. The sample code I gave above should work exactly as expected.
Of course action() is still called. You didn't actually cancel the setTimeout() function. I would suspect that maybe in your real code, you have a scoping issue and maybe aren't testing the same version of the done variable that you think you are.
A better way than using the down flag would be to keep track of the return value from setTimeout() and actually cancel the timer in the cancel() function. Then, action() will never fire when you don't want it to. I think it's also technically a more correct behavior when you mouseout to cancel any chance of the timer firing.
Also, there is no such thing as:
bool down = false;
in javascript. It would have to be:
var down = false;
I would recommend this code:
var downTimer = null;
function down()
{
cancel();
downTimer = setTimeout(function() { action(); }, 1500);
}
function cancel()
{
if (downTimer)
{
clearTimeout(downTimer);
downTimer = null;
}
}
function action()
{
downTimer = null;
alert("Success!");
}
You also need to clear the timeout in your cancel function - otherwise it will still fire - as you initiated it in the down function.
so..
bool down = false;
//your timeout var
var t;
function down()
{
down = true;
t = setTimeout(function() { action(); }, 1500);
}
function cancel()
{
down = false;
clearTimeout(t);
}
function action()
{
if (!down)
return;
alert("Success!");
down = false;
}
There are several things wrong with your code as I see it.
First
bool down = false;
is not valid JavaScript. It should be
var down = false;
Then you have two variables called down: the boolean value and the function. The function will overwrite the variable, until as such time that you execute one of the statements that sets down to true or false.
As others have said: once set, the deferred function will continue to be executed 1.5 seconds later, unless you cancel the timeout. But then again it doesn't matter, since you do check to see if the mouse button is down before doing anything.
So I'd say rename the boolean variable to isMouseDown or something and try again.
to cancel the timeout in the cancel() function, use
var mytimer = null;
function ondown(){mytimer = setTimeOut('action()', 1500;)}
function cancel(){clearTimeout(mytimer);}
function action(){mytimer=null; alert('success!');}
also note that you used down first as a variable end then as a function... Calling if(!down) will always return false because down refers to a function.
The following confirmDialog function is called midway through another jquery function. When this confirmDialog returns true the other function is supposed to continue... but it doesn't. The reason for this seems to be that the entire confirmDialog function has already executed (returning false) by the time the continue button gets clicked. How can I delay it returning anything until after the buttons have been clicked?
(Or, if I'm completely on the wrong track, what is the problem and how do I fix it?)
function confirmDialog(message) {
....
$('input#continue', conf_dialog).click(function() {
$(this).unbind();
$('p',conf_dialog).fadeOut().text('Are you really sure you want to '+message).fadeIn();
$(this).click(function() {
$(conf_dialog).remove();
return true;
});
});
$('input#cancel', conf_dialog).click(function() {
$(conf_dialog).remove();
return false;
});
}
Im' not sure you can.
AFAIK only built-in function like confirm, alert or prompt can be blocking while asking for an answer.
The general workaround is to refactor your code to use callbacks (or use the built-in functions). So that would mean splitting your caller function in two, and executing the second part when the input is obtained.
In confirmDialog, you're setting up event handlers, that will execute when events are fired, not when confirmDialog is run. Another issue, is that you return true or false inside the event function, so that won't apply to the outer function confirmDialong.
The part that relies on the button presses would need to be re-factored. Perhaps put it in another function, and call it from the click handlers:
var afterConfirm = function(bool) {
if(bool) {
//continue clicked
} else {
//cancel clicked
}
//do for both cases here
}
//inside confirmDialog input#continue
$(this).click(function() {
$(conf_dialog).remove();
afterConfirm(true);
});
You may want to look into using Deferred objects. Here are two links that explain them.
http://www.sitepen.com/blog/2009/03/31/queued-demystifying-deferreds/
http://api.dojotoolkit.org/jsdoc/1.3/dojo.Deferred
Using a Deferred you could take your calling function:
function doSomething () {
// this functions does something before calling confirmDialog
if (confirmDialog) {
// handle ok
} else {
// handle cancel
}
// just to be difficult lets have more code here
}
and refactor it to something like this:
function doSomethingRefactored() {
// this functions does something before calling confirmDialog
var handleCancel = function() { /* handle cancel */};
var handleOk = function() { /* handle ok */};
var doAfter = function() { /* just to be difficult lets have more code here */};
var d = new dojo.deferred();
d.addBoth(handleOk, handleCancel);
d.addCallback(doAfter);
confirmDialog(message, d);
return d;
}
ConfirmDialog would have to be
updated to call d.callback() or
d.errback() instead of returning true
or false
if the function that calls
doSomething needs to wait for
doSomething to finish it can add its
own functions to the callback chain
Hope this helps... it will make a lot more sense after reading the sitepen article.
function callingFunction() {
$('a').click(function() {
confirmDialog('are you sure?', dialogConfirmed);
// the rest of the function is in dialogConfirmed so doesnt
// get run unless the confirm button is pressed
})
}
function dialogConfirmed() {
// put the rest of your function here
}
function confirmDialog(message, callback) {
...
$('input#continue', conf_dialog).click(function() {
callback()
$(conf_dialog).remove();
return false;
}),
$('input#cancel', conf_dialog).click(function() {
$(conf_dialog).remove();
return false;
})
...
}
You could add a timeout before the next function is called
http://www.w3schools.com/htmldom/met_win_settimeout.asp