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.
Related
When I scroll the div, basically nothing happens. The method slideIt gets fired once when the object is initiated and that is it. It is not listening to the scrolling event! any reason why would this happen?
function fixed_column_or_row(container_name){
this.container_div=$(container_name);
this.scrollable_div=this.container_div.find(".simplebar-content-wrapper");
this.fixed_row=this.container_div.find(".fixed-row")
this.fixed_column=this.container_div.find(".fixed-column")
//the issue in this line
this.scrollable_div.scroll(this.slideIt())
}
fixed_column_or_row.prototype.slideIt=function(){
var scrollTop = this.scrollable_div.scrollTop(),
scrollLeft = this.scrollable_div.scrollLeft();
console.log("scrollTop")
this.fixed_row.css({
"margin-left": -scrollLeft
});
this.fixed_column.css({
"margin-top": -scrollTop
});
}
A common JavaScript mistake is to type in a function call when what's wanted is a reference to a function (for setting up an event handler, usually, but there are other similar cases).
Thus
this.scrollable_div.scroll(this.slideIt());
will call the this.slideIt() function and pass the return value to the .scroll method, and that is clearly not what is desired. The () after this.slideIt is what causes that, so this.slideIt without () is necessary.
Now, with that done, the next problem will be that the relationship to this will be lost. There are various questions on Stackoverflow with long, thorough answers about how this works. Suffice to say here that what's necessary is to ensure that this is correctly set:
this.scrollable_div.scroll(this.slideIt.bind(this));
(There are other ways of doing it, but that should work.)
UPDATE turns out the code is actually working see my answer below
I'm having some troubles here. I thought I found my answer in the .one method, but apparently, .one means ONLY ONCE PER PAGE PER ANYTHING EVER which isn't exactly what I was going for. Here's what my intention was:
$("#someID").one('mouseover', function() {
//do some stuff
});
$("#someOtherID").one('mouseover', function() {
//do some stuff
});
My expectation was that once that first one fired, that mouseover event would no longer fire for THAT ELEMENT.
The problem with this is that once the first one fires, the second one will not fire either. So the .one method appears to be disabling ALL mouseover events for ALL elements after that first one fires.
I did not expect this, I expected the .one to only apply to that first element. Is this just a flaw in my understanding of the .one method or am I coding wrong?
If it's just a flaw in my understanding, could someone point me in the right direction to correct my code?
Thank you in advance!
This is embarassing, I hope I don't get dinged for this and blocked again from stackoverflow (the easiest thing ever to get blocked from and the hardest to get unblocked).
First, #CertainPerformance, thanks for taking the time to look at my question. My real code didn't have the two mistakes you mentioned, I updated my post to reflect the correct syntax.
I'll be honest, my code is working now, and I have no idea why. I suspect I've been dealing with some crazy caching issues which frustrates me because I'm using inMotionHosting which has really great reviews, and I have caching disabled in cPanel.
If anything, maybe this thread will benefit somebody searching "how to make event fire only once in javascript".
You could make the callback run once like this:
// Extend the function prototype
Function.prototype.once = function() {
// Variables
var func = this, // Current function
result;
// Returns the function
return function() {
// If function is set
if(func) {
// Executes the function
result = func.apply(this, arguments);
// Unset the function, so it will not be called again
func = null;
}
// (:
return result;
};
};
// Bind the event to the function you will use as a callback
$("#someID").on('mouseover', function() {
console.log('just once');
}.once());
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.
I am taking a web development class. Today the teacher gave us a piece of code that raised some questions that I haven't been able to satisfactorily solve through my own searching. The code in question was essentially this:
<script>
function selectmouse(e){
...
...
}
document.onmousedown = selectmouse;
</script>
My first question, is this a legitimate way of calling functions? Is this something that is done? I am of course familiar with the typical way of calling functions from HTML elements, for example
<body onmousedown="selectmouse(event)">
The code was supposed to be calling the function and passing it the event object for the onmousedown. After playing with the code for a while I found a few unusual things.
First, if I put parenthesis after the function call, like I am used to doing (i.e. selectmouse();), then the function resolved immediately upon loading the page, with a value of 'undefined' for the variable. This makes intuitive sense to me, because I assume the browser is treating it like a variable assignment and therefore calling the function as it parses the code, as it normally would to assign a variable.
However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to. It would call the function when the mouse was pressed in any part of the body, and it sent the event object as the variable for the function. But I can't figure out why. I can't find reference to anything similar to it online, and I've never seen anything like it before. Is this a legitimate way to do something like this? Or is this bad code that happens to be working for some reason and would probably cause problems in the future? Why is it working?
document.onmousedown = selectmouse; //note: never do this except in old browsers
However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to.
That's not weird. You are passing the reference of the function to the browser, not executing it.
For example, you have this function:
function callback(){
alert("clicked!");
}
document.body.onclick = callback;
You pass the reference to onclick and the browser will know what function to call when the event is triggered. But if you do it like this:
document.body.onclick = callback();
This will be evaluated into:
document.body.onclick = alert("clicked!");
//Note that this is simplified explanation to visualize what is happening.
//The returned value of alert() is not assigned to onclick.
//To be exact the returned value of callback() is the one that is being assigned.
//Similar to:
// ...onclick = (function(){ alert("clicked!"); })();
Then you will see an alert, and the browser will continue executing the rest of the code:
document.body.onclick = undefined;
<body onmousedown="selectmouse(event)"> <!-- Don't do this too -->
The parentheses are necessary because this code is not executed instantly. It is only executed when the event is triggered.
Anyway, you shouldn't attach events both using .onmousedown or onmousdown="...". There is a better way of doing it:
element.addEventListener("mousedown", callback, false);
Reason: If you use the onmousedown property, you can only attach one mousedown event. In most cases you would want to attach more than one.
Also attaching events inline might cause security problems (cross-site scripting), and that is exactly why Google decided to prohibit all developers from using them in developing Chrome apps/extensions.
This is legitimate code and is working as it should.
The way you are comfortable with is just a method we tried while the web was evolving, but at present we should better use the second way you showed, although its changed bit more to make you understand it in a better way using event bindings.
When you do
function selectmouse(e){
...
...
}
javascript will create a variable named selectmouse and save the function in that variable. So selectmouse is a variable of type function with the function body as its value.
document on the other hand can be related to class or specifically an object which is an instance. Each document and each HTML element or DOM node can have in it variables to store the functions to be called on user events like onmousedown.
so when doing
document.onmousedown = selectmouse;
we are inturn saying
when mousedown happens in document, the function named selectmouse
should be called
If you do
document.onmousedown = selectmouse();
it means
run the function selectmouse immediately and get the result, assign
the result to onmousedown event of the DOM Node document.
And if you ask why this is taken apart from the form
<body onmousedown="selectmouse(event)">
To answer in a simple way, HTML is Hyper Text Markup Language, its sole purpose is to represent formatted data, the quick evolution of web inturn made it deranged with behaviours like this and presentation code like inline css. So to make behaviour and presentation out of HTML and thus a better design we do this.
Please take time to take a look at how you can bind a function to an event which is the current tradeoff in doing this same thing.
For a detailed explanation please check the events sectio of ppk blog here
I think that is correct, because the function is being called within the script as if it were an object, to me is not the best way to do it, I would have like this (with jquery):
$(document).mousedown(function (event) {
// here the content of the function
});
<body onmousedown="selectmouse(event)">
In this example the browser evaluates the result of the expression selectmouse(event) and assigns it to the onmousedown property of the body, event is undefined and the selectmouse doesn't return anything so it's result is undefined.
It is equivalent of the following if it was inside a script tag
<script>
function selectmouse(e) {
}
document.body.onmousedown = selectmouse(event);
</script>
<body onmousedown="selectmouse">
When you remove the () you are assigning a function to the onmousedown property. Now the browser fires your callback method whenever the mousedown event is raised and it bubbles up to the body, passing the current event as the parameter you're declaring as "e". If another element also had an onmousedown event handler declared but it cancelled the event ( by calling event.cancelBubble = true ) the body's onmousedown handler will not be invoked.
<script>
function selectmouse(e) {
}
document.body.onmousedown = selectmouse;
</script>
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')