Prevent parent script from firing - javascript

I have a DotNetNuke website. Baked into the DNN code is the following script
<script type="text/javascript">
//<![CDATA[
function WebForm_OnSubmit() {
dnn.controls.submitComp.onsubmit();
return true;
}
//]]>
</script>
The problem is, I put a form on a page on my website that performs a search, and I wired up a jquery listener that says if the enter key is pushed, fire my button click event. The problem is, the parent script above ALSO fires that WebForm_OnSubmit() function, and whatever that onsubmit() function\return true does is causing my page to just refresh.
So, if there anything i can do so "override" or "prevent" that WebForm_OnSubmit() function from also triggering?
Edit 1: In response to the question "how is your listener setup":
I have a function called canISearch:
function canISearch() {
if (event.keyCode == 13) {
event.stopPropagation();
$("#btnSearch").click();
}
}
and I fire this function using my onkeydown attribute:
<input type="text" id="txtblah" onkeydown="canISearch()" />

If WebForm_OnSubmit is in the global space, you can overwrite it and create an exception for your case. Sometime after the original function is defined, redefine it. Maybe something like this:
(NOTE: updated to incorporate information from Samy's answer below)
(function () {
var originalFn = dnn.controls.submitComp.onsubmit;
dnn.controls.submitComp.onsubmit = function() {
if ([your element is in focus]) {
... do your thing ...
} else {
originalFn();
}
};
})()

You could either monkey patch the dnn code in order for the method to do nothing when your function is present on the page:
dnn.controls.submitComp.onsubmit = function() {/*doing nothing, ladida*/};
Which may be a bit harsh since your modification can have an impact on other behaviors. You can instead add a method that checks that your control has focus before routing the code accordingly. This is most likely the simplest hack.
You could also prevent the event from bubbling up, as Brennan suggests; it really depends how events are attached. If I remember correctly DNN can intrude on your events in so many ways this may not be easy to do.
Or you could create your own skin in order to control all the components that are pushed onto the page and prevent the auto submit from the wrapping form.

How is your listener set up? You should be able to stop propagation of the event to keep it from moving up the event hierarchy:
$(".element").keyup(function(e){
e.stopPropagation();
});

Related

pace.js: "start" event not triggered?

I can't seem to find a solution to this problem I posted in the comments of this question
… I'm using the pace.js plugin and I would love to load/show parts of my page immediately without having to wait for the preloader to load all content.
I thought of doing this by simply calling the start event and show the selector immediately.
However I can't seem to find the cause why my done event is fired, but start is not. I also tried with hide which is also fired, but stop or restart is not.
$(window).load(function(){
Pace.on('start', function() {
alert('start') // not fired
});
Pace.on('done', function() {
alert('done') // fired!
});
});
Any ideas?
Call Pace.start(), right after event bindings. You then will be able to get the start event.
You will need to call
Pace.restart();
if the current page has already loaded with pace progress.
You have to put
Pace.on('start', function() {
alert('start');
});
outside $(window).load....
After that it will get start status, You are calling These methods after documentation is loaded so start must be already triggred.
after registering script and css, on your htlm section add this script
<script type="text/javascript">
window.onbeforeunload = renderLoading;
function renderLoading() {
Pace.stop();
//Pace.start();
Pace.bar.render();
}

Prevent calling a function

I have two parts of scripts.
Part 1 :
$("mySelector").click(function() {
alert('you call me');
})
Part 2 :
$("mySelector").click(function() {
if(myCondition) {
//how can i prevent calling the first function from here ???
}
})
The whole problem, is that i have no access to part1. So i need to unbind the event allready specified in part 1, if myCondition is true, but otherwise i need to call the first function.
Thanks
UPDATE:
Thank you. I didn't know about stopImmediatePropagation(). But i feel, that there must be something like that :)
But actually in my case it doesn't work :(
Please have a look at my site
http://www.tours.am/en/outgoing/tours/%D5%80%D5%B6%D5%A4%D5%AF%D5%A1%D5%BD%D5%BF%D5%A1%D5%B6/Park-Hyatt-Goa/
Under the hotel description tab i have cloud carousel, when i click on not active image (not the front image), as you can see i'm consoling that i stopImmediatePropagation() there, but the event however calls :(
If your handler is registered first, then you can use event.stopImmediatePropagation like this:
$("mySelector").click(function(event) {
if(myCondition) {
event.stopImmediatePropagation();
}
})
Be aware that this will also stop event bubbling, so it will also prevent click handlers on parent elements from being invoked.
Update: If this does not work, then your handler is attached after the one you want to control. This is a problem that makes the solution much more difficult. I suggest seeing if you can bind "before the other guy", otherwise you will have to unbind the existing handler and then conditionally invoke it from within your own by retaining a reference to it. See jQuery find events handlers registered with an object.
No access:
$("#mySelector").click(function() {
alert('you call me');
})
Access:
var myCondition = true, //try false too
fFirstFunction = $("#mySelector").data("events").click[0].handler;
$("#mySelector").unbind("click");
$("#mySelector").click(function() {
if(myCondition) {
alert(myCondition);
} else {
$("#mySelector").click(fFirstFunction);
}
});
Look at this example
You can call
$('mySelector').unbind('click');
to get rid of all the click handlers. If your script is loaded after the other one (which appears to be the case), then that should do it. However note that it does unbind all "click" handlers, so make sure you call that before you add your own handler.
If you can't ensure your handler is attached first, try the following code:
var events = $('mySelector').data("events"); //all handlers bound to the element
var clickEvents = events ? events.click : null;//all click handlers bound to the element
$('mySelector').unbind('click'); //unbind all click handlers
//bind your handler
$("mySelector").click(function(e) {
if (myCondition) {
//do what you want
} else {
//call other handlers
if (clickEvents) {
for (var prop in clickEvents)
clickEvents[prop].call(this, e);
}
}
})
Update:
Above code is for jQuery 1.3.2
Above code is based on internal implementation of jQuery 1.3.2, so please check it carefully once you update jQuery.
return false;
-or-
event.preventDefault();

Enable/Disable events of DOM elements with JS / jQuery

I stuck here with a little problem I have put pretty much time in which is pretty bad compared to its functionality.
I have tags in my DOM, and I have been binding several events to them with jQuery..
var a = $('<a>').click(data, function() { ... })
Sometimes I would like to disable some of these elements, which means I add a CSS-Class 'disabled' to it and I'd like to remove all events, so no events are triggered at all anymore. I have created a class here called "Button" to solve that
var button = new Button(a)
button.disable()
I can remove all events from a jQuery object with $.unbind. But I would also like to have the opposite feature
button.enable()
which binds all events with all handlers back to the element
OR
maybe there is a feature in jQuery that actually nows how to do that?!
My Button Class looks something similar to this:
Button = function(obj) {
this.element = obj
this.events = null
this.enable = function() {
this.element.removeClass('disabled')
obj.data('events', this.events)
return this
}
this.disable = function() {
this.element.addClass('disabled')
this.events = obj.data('events')
return this
}
}
Any ideas? Especially this rebind functionality must be available after disable -> enable
var a = $('<a>').click(data, function() { ... })
I found these sources that did not work for me:
http://jquery-howto.blogspot.com/2008/12/how-to-disableenable-element-with.html
http://forum.jquery.com/topic/jquery-temporarily-disabling-events
-> I am not setting the events within the button class
Appreciate your help.
$("a").click(function(event) {
event.preventDefault();
event.stopPropagation();
return false;
});
Returning false is very important.
Or you could write your own enable and disable functions that do something like:
function enable(element, event, eventHandler) {
if(element.data()[event].eventHandler && !eventHandler) { //this is pseudo code to check for null and undefined, you should also perform type checking
element.bind(event, element.data()[event]);
}
else (!element.data()[event] && eventHandler) {
element.bind(event, element.data()[event]);
element.data({event: eventHandler}); //We save the event handler for future enable() calls
}
}
function disable(element, event) {
element.unbind().die();
}
This isn't perfect code, but I'm sure you get the basic idea. Restore the old event handler from the element DOM data when calling enable. The downside is that you will have to use enable() to add any event listener that may need to be disable() d. Otherwise the event handler won't get saved in the DOM data and can't be restored with enable() again. Currently, there's no foolproof way to get a list of all event listeners on an element; this would make the job much easier.
I would go on this with different approach:
<a id="link1">Test function</a>
<a id="link2">Disable/enable function</a>
<script type="text/javascript">
$(function() {
// this needs to be placed before function you want to control with disabled flag
$("#link1").click(function(event) {
console.log("Fired event 1");
if ($(this).hasClass('disabled')) {
event.stopImmediatePropagation();
}
});
$("#link1").click(function() {
console.log("Fired event 2");
});
$("#link2").click(function() {
$("#link1").toggleClass("disabled");
});
});
</script>
This may not be what you require, since it may effect also other functions binded into this event later. The alternative may be to modify the functions itself to be more like:
$("#link1").click(function(event) {
console.log("Fired event 1");
if ($(this).hasClass('disabled')) {
return;
}
// do something here
});
if that is an option.
Instead of adding event handler to each element separately, you should use event delegation. It would make much more manageable structure.
http://www.sitepoint.com/javascript-event-delegation-is-easier-than-you-think/
http://cherny.com/webdev/70/javascript-event-delegation-and-event-hanlders
http://brandonaaron.net/blog/2010/03/4/event-delegation-with-jquery
This why you can just check for class(es) on clicked element , and act accordingly. And you will be able even to re-eanble them , jsut by changing the classes of a tag.
P.S. read the links carefully, so that you can explain it to others later. Event delegation is a very important technique.
You could use an <input type="button"> and then use $("#buttonID").addAttr('disabled', 'disabled'); and $("#buttonID").removeAttr('disabled');. Disabling and enabling will be handled by the browser. You can still restyle it to look like an anchor, if you need that, by removing backgrounds and borders for the button. Be aware though, that some margins and padding might still bugger u in some browsers.

Is there a [universal] way to invoke a default action after calling event.preventDefault()?

This question is for the purposes of developing jQuery plugins and other self-contained JavaScript snippets that don't require modifying other script files for compatibility.
We all know that event.preventDefault() will prevent the default event so we can run a custom function. But what if we want to simply delay the default event before invoking it? I've seen various, case-specific ninja tricks and workarounds to re-invoke the default action, but like I said, my interest is in a universal way to re-trigger the default, and not deal with default triggers on a case-by-case basis.
$(submitButton).click(function (e) {
e.preventDefault();
// Do custom code here.
e.invokeDefault(); // Imaginary... :(
});
Even for something as simple as form submission, there seems to be no universal answer. The $(selector).closest("form").submit() workaround assumes that the default action is a standard form submission, and not something wacky like a __doPostBack() function in ASP.NET. To the end of invoking ASP.NET callbacks, this is the closest I've come to a universal, set-it-and-forget-it solution:
$(submitButton).click(function (e) {
e.preventDefault();
// Do custom code here.
var javascriptCommand = e.currentTarget.attributes.href.nodeValue;
evalLinkJs(javascriptCommand);
});
function evalLinkJs(link) {
// Eat it, Crockford. :)
eval(link.replace(/^javascript:/g, ""));
}
I suppose I could start writing special cases to handle normal links with a window.location redirect, but then we're opening a whole new can of worms--piling on more and more cases for default event invocation creates more problems than solutions.
So how about it? Who has the magic bullet that I've been searching for?
Don't call preventDefault() in the first place. Then the default action will happen after your event handler.
Take a look at this one:
You could try
if(!event.mySecretVariableName) {
event.preventDefault();
} else {
return; // do nothing, let the event go
}
// your handling code goes here
event.originalEvent.mySecretVariableName = "i handled it";
if (document.createEvent) {
this.dispatchEvent(event.originalEvent);
} else {
this.fireEvent(event.originalEvent.eventType, event.originalEvent);
}
Using this answer: How to trigger event in JavaScript? and the jQuery event reference: http://api.jquery.com/category/events/event-object/
Tag the event object you receive so if you receive it again you don't loop.
This should work. I've only tested in firefox though.
<html>
<head>
<script>
window.addEventListener("click",handleClick,false);
function handleClick(e){
if (e.useDefault != true){
alert("we're preventing");
e.preventDefault();
alert(e.screenX);
//Firing the regular action
var evt = document.createEvent("HTMLEvents");
evt.initEvent(e.type,e.bubbles,e.cancelable);
evt["useDefault"] = true;
//Add other "e" attributes like screenX, pageX, etc...
this.dispatchEvent(evt);
}
else{
alert("we're not preventing");
}
}
</script>
</head>
<body>
</body>
</html>
Of course, you'd have to copy over all the old event variables attributes too. I just didn't code that part, but it should be easy enough.
It's not possible like JamWaffles has already proven. Simple explanation why it's impossible: if you re-trigger the default action your event listener intercept again and you have an infinite loop.
And this
click(function (e) {
e.preventDefault();
// Do custom code here.
e.invokeDefault(); // Imaginary... :(
});
is the same like this (with your imaginary function).
click(function (e) {
// Do custom code here.
});
It seems that you want to manipulate the url of your clicked element. If you do it like this it just works fine. Example.
I needed to disable a button after click and then fire the default event, this is my solution
$(document).on('click', '.disabled-after-submit', function(event) {
event.preventDefault();
$(event.currentTarget).addClass('disabled');
$(event.currentTarget).removeClass('disabled-after-submit');
$(event.currentTarget).click();
$(event.currentTarget).prop('disabled', true);
});

W3.org validation stuck on one inline javascript attribute, how to fix it?

I have a website with the following code for a specific element:
<textarea id="textToTranslate" onfinishinput="dothis()" rows="5"></textarea>
onfinishinput waits for the user input and check if he is stopped. If he stop typing, the function dothis is called throught $('#waitUserInput').live() function.
The tricky part of my question is, how to change the above line to be completely jQuery.
The jQuery dat correspont to the dothis() function is the following:
// Detect if user input stops
$('#waitUserInput').live("keyup", function(e)
{
startTypingTimer($(e.target));
});
var typingTimeout;
function startTypingTimer(input_field)
{
if (typingTimeout != undefined)
clearTimeout(typingTimeout);
typingTimeout = setTimeout( function()
{
eval(input_field.attr("onfinishinput"));
}
, 250);
}
Javascript dothis() function:
function dothis(){
// Ajax call when called
{
Now, when I go to http://validator.w3.org, I have one error, and yes it is about the above code:
Attribute onfinishinput not allowed on element textarea at this point.
<textarea id="textToTranslate" onfinishinput="dothis()" rows="5"></textarea>
The question is, is it possible to turn the onfinishinput javascript attribute out of the textarea, but so that is is functioning the same?
I know it is a little complex, but I hope someone can help.
Why not just change:
eval(input_field.attr("onfinishinput"));
To:
dothis();
And then remove the 'onfinishinput' attribute from your textarea?
There is no such attribute called 'onfinishinput' for the TEXTAREA so the validator is correct. Including it does in fact violate the standard.
It appears that what you are trying to do is to be able to have a different handler for each TEXTAREA on a page so that you can take different actions. If that is the case, why not just have your jQuery call dothis() unconditionally and pass the control that fired the event as a parameter?
You could then put control-specific handling in your dothis() function based on the ID of the passed control.
How about binding the event differently and removing the attribute:
$('#textToTranslate').bind('onfinishinput', dothis');
You'd then need to trigger the event using jQuery's trigger (see http://api.jquery.com/bind/)

Categories

Resources