Run function when a statement becomes true - javascript

I have boolean variables that change after the user performs an action.
I would like a function to run when this happens.
Currently I have this:
setInterval( function() {
if(window.username && window.password) {
[...]
}
}, 50);
This is not ideal and causes some problems by repeating things inside the if statement.
Instead of checking every 50ms, I would like it to check continuously. Is this possible?

There isn't any "immediately" correct answer at this point, however there are methods you can use to work around the issue.
A solution for most browsers (and IE6+) is available that uses the onpropertychange event and the newer spec defineProperty. The slight catch is that you'll need to make your variable a dom object.
Full details:
http://johndyer.name/native-browser-get-set-properties-in-javascript/
Also, look into ... https://github.com/melanke/Watch.JS for a non-dom answer.

Related

"Run if I haven't been called in x seconds" in JavaScript

Suppose I have a callback firing perpetually as the result of some event; i.e. Someone's moving a mouse.
I'd like to run a cleanup action if the callback hasn't fired in x seconds; i.e. If they haven't moved the mouse in 2 seconds, fire.
I think I could probably fix something up with setTimeout, but I'm wondering if any standard libraries have a function for this? Sort of a 'dead-mans-switch', seems like it would be common enough to have a standard method. If not I'm making one. Anyone?
De-bouncing may be a technique that will help.
It is essentially a method of wrapping a function so that you have control over when the wrapped function will execute, regardless of how often the debounced version is called.
This is most commonly used for events, like window resize. Then you can only execute your handler once the user has finished resizing the window rather then whilst they are resizing it.
There is also throttling, this is similar but has important differences.
Throttled functions will execute once every n time rather than a debounced version which will executed after it hasn't be called for n time.
underscore and lodash have implementations of de-bouncing and throttling.
However they it is quite easy to achieve and you don't really need a large library if its not already being used.
I think you're on the right track about setTimeout. As per your wonder, I am not aware of a module that would do it. And due to the intrusive nature of this process, it makes sense.
You could do this tho:
var yourmodule; //assuming you're using a module to store your app code; the object should obviously exist before continuing
yourmodule.cleanupSequenceId = -1;
function yourEventCallback() {
if (yourmodule.cleanupSequenceId !== -1) clearTimeout(yourmodule.cleanupSequenceId);
//function logic
//cleanup:
yourmodule.cleanupSequenceId = setTimeout(cleanupMethod, 2000);
}
After stumbling upon this (very old) question, and reading many others like it, I found a solution that works for me so I wanted to share it.
You define a "Debounce" function like this:
var debounce_timeout // Global debouncer timer, so all calls target this specific timeout.
function debounce(func, delay = 2000) {
clearTimeout(debounce_timeout)
debounce_timeout = setTimeout(() => {
func()
}, delay)
}
Now if you wish to debounce some function, you do:
debounce(myFunction)
Debouncing essentially means, that when your function is called, we observe for 'delay' duration, if any other calls to the function is made. If another call is made, we reset our observing time.

How can I turn this javascript into a function? Is it already a function? A few very basic questions about js structure

I am learning javascript, and am trying to adjust the following:
$('#myform').change(function() {
if ($('#sv_I4b').attr('checked')||$('#sv_I4c').attr('checked')){
$('#sv_I5').removeClass('hidden');
} else {
$('#sv_I5').addClass('hidden');
}
});
To be a a function with a name that I can call on different events, such as page load etc.
I don't yet fully understand each element, but I know that:
if ($('#sv_I4b').attr('checked')||$('#sv_I4c').attr('checked')){
$('#sv_I5').removeClass('hidden');
} else {
$('#sv_I5').addClass('hidden');
}
is the core "logic" of the function: if (condition) {then this} else {that}
and more or less understand what is happening there. Which leaves the bounding javascript (is there better terminology than that?):
$('#myform').change(function() {...});
My Questions (are the following true etc):
The dollar I think denotes that it is jQuery
The id my form obviously
pertains the script to events within that form (namespace?)
.change seems to be, a trigger that listens to ... any change taking place
within #myform? so every time a change happens within #myform this
runs? That seems inefficient
function() I don't yet understand what
an anonymous or empty function does, just defines what is contained
in {} as a function?
My goal: to be able to have something like
function myfunction()
{
if ($('#sv_I4b').attr('checked')||$('#sv_I4c').attr('checked')){
$('#sv_I5').removeClass('hidden');
} else {
$('#sv_I5').addClass('hidden');
}
}
and then
$(function() {myfunction});
so I can call that function on page load, but I don't wan't to loose the functionality the .change syntax is providing me (that it changes as the user interacts with the elements on the page also.
Apologies for the general and cumbersome levels of ignorance
You guessed how to define the function correctly — that is,
function myfunction()
{
if ($('#sv_I4b').attr('checked')||$('#sv_I4c').attr('checked')){
$('#sv_I5').removeClass('hidden');
} else {
$('#sv_I5').addClass('hidden');
}
}
works just fine. However, this:
$(function() {myfunction});
Should be written as:
$(myfunction); // Run on page load.
$('#myform').change(myfunction); // ...and also run it when the form changes.
However, that second line won't actually work until the page has loaded unless the form exists at the time the script runs, so you may want to change it to this:
$(function() { // On page load, run this anonymous function:
myfunction(); // Run the function now (where now, at this point, is page load).
$('#myform').change(myfunction); // ...as well as when the form changes.
});
$ is shorthand notation for jQuery, and essentially namespaces any functions to the jQuery framework.
my_form is a DOM selector. $('#my_form') wraps the matched DOM element up as a jQuery object, adding all sorts of useful methods and properties.
.change() is an event listener which, as you guessed, watches for change events on that jQuery object. It is a little inefficient - take a look .on() instead.
the most useful behaviour an anonymous function (closure) is to create private scope, something that javascript doesn't otherwise provide.

Run function only if event default is/isn't prevented

Is there a way to run a function only if event.preventDefault() is called on an event (by another unknown function). This is for a jQuery plugin, so I don't have any knowledge of what other parts of the page might be doing. I've tried this:
Event.test = Event.preventDefault;
Event.preventDefault = function () {
alert('Success');
this.test();
}
but it doesn't work... just behaves as normal, with no errors.
Conversely, I want the opposite too... to call a function only if event.preventDefault() isn't called. In effect, to add a function to the default action for an event. Any ideas? Is all this at all possible?
Edit: Based on the comment, I've got a solution to the first problem: http://jsfiddle.net/nathan/VAePB/9/. It works in Chrome (alerts function preventDefault() { [native code] }, but IE alerts undefined. So IE won't let me define Event.prototype.test, but it will let me redefine Event.prototype.preventDefault. Weird. I'm sure I can come up with a solution to the the second problem based on this one if I can just get it to work in IE.
I'm not sure I've understand. Can't you just use event.isDefaultPrevented() like this
For the first problem, try something like this:
oldPreventDefault = Event.prototype.preventDefault;
Event.prototype.preventDefault = function() {
//do stuff
oldPreventDefault.call(this);
}
I don't know if that will work, but it might be worth a shot.
For the second problem, I would try something similar to live event handling. Put a listener on a parent element (i.e. body or a top-level div). If you can get your hook into preventDefault as noted before, you can use that to set a flag. If the event bubbles up to that element and your flag isn't set, do your extended behavior. Though this won't work with all events, since not all events bubble. Another way to tackle this problem might be to delay execution until the current stack has finished using setTimeout(0,...) and then checking the flag.

jQuery temporary unbinding events

Maybe I'm totally missing something about even handling in jQuery, but here's my problem.
Let's assume there are some event binding, like
$(element).bind("mousemove", somefunc);
Now, I'd like to introduce a new mousemove binding that doesn't override the previous one, but temporarily exclude (unbind) it. In other words, when I bind my function, I must be sure that no other functions will ever execute for that event, until I restore them.
I'm looking for something like:
$(element).bind("mousemove", somefunc);
// Somefunc is used regularly
var savedBinding = $(element).getCurrentBinding("mousemove");
$(element).unbind("mousemove").bind("mousemove", myfunc);
// Use myfunc instead
$(element).unbind("mousemove", myfunc).bind("mousemove", savedBindings);
Of course, the somefunc is not under my control, or this would be useless :)
Is my understanding that is possible to bind multiple functions to the same event, and that the execution of those functions can't be pre-determined.
I'm aware of stopping event propagation and immediate event propagation, but I'm thinking that they are useless in my case, as the execution order can't be determined (but maybe I'm getting these wrong).
How can I do that?
EDIT: I need to highlight this: I need that the previously installed handler (somefunc) isn't executed. I am NOT defining that handler, it may be or may be not present, but its installed by a third-party user.
EDIT2: Ok, this is not feasible right now, I think I'm needing the eventListenerList, which is not implemented in most browsers yet. http://www.w3.org/TR/2002/WD-DOM-Level-3-Events-20020208/changes.html
Another way could be to use custom events, something along these lines:
var flag = 0;
$(element).bind("mousemove", function() {
if(flag) {
$(this).trigger("supermousemove");
} else {
$(this).trigger("magicmousemove");
}
}).bind("supermousemove", function() {
// do something super
}).bind("magicmousemove", function() {
// do something magical
});
$("#foo").click(function() {
flag = flag == 1 ? 0 : 1; // simple switch
});
Highly annoying demo here: http://jsfiddle.net/SkFvW/
Good if the event is bound to multiple elements:
$('.foo').click(function() {
if ( ! $(this).hasClass('flag')) {
do something
}
});
(add class 'flag' to sort of unbind, add it to 'bind')

Halt JavaScript execution without locking up the browser

Are you able to halt JavaScript execution without locking up the browser? The way you would normally halt execution is to do an infinite while()-loop, but in the case of FireFox, it locks up the browser until the loop has ended.
What's your take on this?
I am trying to override window.confirm() to implement my own dialog using HTML. I am doing this so I don't have to change existing code (it's a pretty big code-base).
I need to be able to halt execution to allow user-input; to in turn return a boolean like the standard confirm function does:
if (confirm("..."))
{
// user pressed "OK"
}
else
{
// user pressed "Cancel"
}
Update
To my knowledge; this cannot be done using setTimeout() or setInterval() since these functions execute the code thats given to them asynchronously.
confirm() prompt() and alert() are special functions--they call out of the JavaScript sandbox into the browser, and the browser suspends JavaScript execution. You can't do the same thing, since you need to build your functionality into JavaScript.
I don't think there's a great way to drop in a replacement without doing some restructuring along the lines of:
myconfirmfunction(function() {
/* OK callback */
}, function() {
/* cancel callback */
});
Either use callbacks or make your code Firefox-only. In Firefox with support for JavaScript 1.7 and higher, you can use the yield statement to simulate your desired effect. I have created a library for this purpose called async.js. The standard library for async.js includes a confirm method, which can be used as such:
if (yield to.confirm("...")) {
// user pressed OK
} else {
// user pressed Cancel
}
You cannot stop the event thread in JavaScript, so instead you have to work around the problem, usually by using callback functions. These are functions that are run at a later time, but can be passed around like any other object in JavaScript. You might be familiar with them from AJAX programming. So, for example:
doSomeThing();
var result = confirm("some importart question");
doSomeThingElse(result);
Would be converted into:
doSomeThing();
customConfirm("some importart question", function(result){
doSomeThingElse(result);
});
where customConfirm now takes a question and passes the result to the function it takes as an argument. If you implement a DOM dialog with a button, then connect an event listener to the OK and CANCEL buttons, and call the callback function when the user clicks on one of them.
There is an extension to the JavaScript language called StratifiedJS. It runs in every browser, and it allows you to do just that: halting one line of JavaScript code without freezing the browser.
You can enable Stratified JavaScript e.g. by including Oni Apollo ( http://onilabs.com/docs ) in your webpage like:
<script src="http://code.onilabs.com/latest/oni-apollo.js"></script>
<script type="text/sjs"> your StratifiedJS code here </script>
Your code would look like this:
var dom = require("dom");
displayYourHtmlDialog();
waitfor {
dom.waitforEvent("okbutton", "click");
// do something when the user pressed OK
}
or {
dom.waitforEvent("cancelbutton", "click");
}
hideYourHtmlDialog();
// go on with your application
the way you normally halt execution should hardly ever be an infinite while loop.
break up your work into parts, that you call with SetTimeout
change this:
DoSomeWork();
Wait(1000);
var a = DoSomeMoreWork();
Wait(1000);
DoEvenMoreWork(a);
to this:
DoSomeWork();
setTimeout(function() {
var a = DoSomeMoreWork();
setTimeout(function() {
DoEvenMoreWork(a);
}, 1000);
}, 1000);
I don't think there's any way to reasonably re-create the functionality of confirm() or prompt() in your own JavaScript. They're "special" in the sense of being implemented as calls into the native browser library. You can't really do a modal dialog of that sort in JavaScript.
I have seen various UI libraries that simulate the effect by putting an element on top of the page, that looks & acts like a modal dialog, but those are implemented using async callbacks.
You will have to modify the existing library, rather than replacing window.confirm.
I tried using tight looping for this. I needed to slow down a native event (which AFAIK is the only use case for a synchronous wait that can't be re-architected asynchronously). There are lots of example loops out there that claim not to lock up the browser; but none of them worked for me (the browser didn't lock up, but they prevented it from doing the thing I was waiting for in the first place), so I abandoned the idea.
Next I tried this - storing and replaying the event, which seems to be impossible cross-browser too. However depending on the event and how flexible you need to be, you can get close.
In the end I gave up, and feel much better for it; I found a way to make my code work without having to slow down the native event at all.

Categories

Resources