I'm using jQuery but dealing with markup produced from JSF pages. A lot of the elements have onclick attributes provided by the JSF code (which isn't my realm).
Example:
<div onclick="[jsf js to submit form and go to next page]">submit</div>
I'm trying to add some client side validation with jQuery. I need something like this pseudo code:
$('div').click(function(e){
if(myValidation==true){
// do nothing and let the JS in the onlick attribute do its thing
} else {
$error.show();
// somehow stop the onclick attribute JS from firing
}
})
Is there a best-practice for handling this?
One thought I had was that on page load, grab the onclick attribute's value, delete the onclick attribute from the object, then...well, that's where I get lost. I could cache the JS as text in a data- attribute, but I'm not sure how to fire that off later.
Just use eval to run onclick attribute code in your jQuery click event if you want it. You need to remove onclick attribute
<div onclick="alert('hi');">submit</div>
-
$(document).ready(function() {
var divClick = $('#theDiv').attr('onclick');
$('#theDiv').removeAttr('onclick');
});
$('#theDiv').bind('click', function(e) {
if (myValidation == true) {
// do nothing and let the JS in the onclick attribute do its thing
eval(divClick);
} else {
$error.show();
// somehow stop the onclick attribute JS from firing
e.preventDefault();
}
});
Either return false or use:
e.stopPropagation()
or
e.preventDefault()
Depending on your needs.
EDIT
You can save original event:
var originalEvent = $('div').attr("onclick");
$('div').attr("onclick", false);
$('div').click(function(e) {
if (false) {
// do nothing and let the JS in the onlick attribute do its thing
eval(originalEvent);
}
else {
alert("error");
// somehow stop the onclick attribute JS from firing
}
});
take a look at this http://jsfiddle.net/j4jsU/
Change if(false) to if(true) to see what hepens when form is valid.
I like e.stopProgation() and e.preventDefault(), but if you do not prefer that strategy, you could also manually remove the onclick() attribute and manually call the function it was using upon successful validation.
Different strokes..
Why can't you do something like:
div=document.getElementById('test');
oldClick=div.onclick;
bol=false;
div.onclick=function(){
if(bol){
oldClick();
}
else {
alert('YOU SHALL NOT RUN INLINE JAVASCRIPT');
}
}
Related
I trying to run code to change div id,class,... in every click but I don't
know how this my js code :
<div class="up_vote_bt upvote_hide" title="Delete up vote" onclick="upvoteHide()" id="hideupvote"></div>
<script>
$(document).ready(function() {
$("#upvote").click(function() {
document.getElementById("upvote").setAttribute("class","up_vote_bt upvote_hide");
document.getElementById("upvote").setAttribute("title","delete up vote");
document.getElementById("upvote").setAttribute("onclick","hideupvote()");
document.getElementById("upvote").setAttribute("id","hideupvote");
});
});
</script>
<script>
$(document).ready(function() {
$("#hideupvote").click(function() {
document.getElementById("hideupvote").setAttribute("class","up_vote_bt");
document.getElementById("hideupvote").setAttribute("title","up vote");
document.getElementById("hideupvote").setAttribute("onclick","upvote()");
document.getElementById("hideupvote").setAttribute("id","upvote");
});
});
</script>
if you're using jQuery why not do this?
$(document).ready(function(){
$('#upvote').click(function(){
//$(this) for just this element
if($(this).hasClass('upvote_hide')){
$(this).attr('title','Up vote');
upvote();
}else{
$(this).attr('title','Delete up vote');
hideupvote();
}
$(this).toggleClass('upvote_hide')
});
});
toggleClass() will either add or remove upvote_hide if it doesn't exist or exists.
attr() will alter the attribute much like setAttribute()
For my example there is no need to alter the eventHandlers or in your case setting the attribute onClick to the function. I'ts all done in the jQuery event hander function. So your functions that you're passing to the onclick attribute are called within the function.
When you attach an event handler via jQuery using the
$("#upvote").click(function() { ... });
mechanism, jQuery will directly attach the handler to the elements in the query result set. This means that the handler will be there, whatever the ID changes to in the future.
What you can do is to attach a delegated handler to the document like this.
$(document).on("click", "#upvote", function() { ... });
$(document).on("click", "#hideupvote", function() { ... });
See this article for a deeper explanation
Also, setting the onclick attribute is meaningless in this case and you should remove those lines.
However, changin IDs of elements is not a good practice. An ID should mean a unique identifier for a DOM node, which is not expected to change. I would rather toggle classes here.
Note: jQuery is not an option.
I want to detect a change in the state of a checkbox, but the onChange event doesn't seem to fire when I do this:
document.getElementById('myCheckBox').addEventListener('change',function() {
console.log('Changed!');
});
document.getElementById('someLink').onClick = function() {
// toggle checkbox
document.getElementById('myCheckBox').checked = !document.getElementById('myCheckBox').checked;
};
When I click #someLink the change event is not fired. I could add another listener to #myLink, but then if I add other links that check the same box I have to add more listeners. I want one listener for a checkbox change event. Again, jQuery is not an option, I need vanilla JS.
EDIT: Sorry if I did not make this more clear, but I want to avoid adding complexity to each link that will check this box. So ideally (and maybe the answer is that this is impossible) I don't want to have to alter the link/click logic at all. I want to be able to change the .checked property anywhere in the code and have it be detected without additional logic at each change (if possible).
UPDATE:
Okay so there is apparently no way to do this nicely without altering the onClick logic, so (like some kind of animal) I ended up brute forcing the problem as follows:
function mySentinel() {
if(document.getElementById('myCheckBox').checked) {
console.log("I've been checked!");
return;
}
setTimeout("mySentinel()",100);
}
// then call this somewhere in the on document load section...
mySentinel();
You can add some sort of timeout if you want also:
function mySentinel(var i) {
if(document.getElementById('myCheckBox').checked) {
console.log("I've been checked!");
return;
}
if(i <= 0) {
console.log("Time out. Still not checked");
}
i--;
setTimeout("mySentinel("+i+")",100);
}
// then call this somewhere in the on document load section...
// 60 second timeout (some math can make the argument look nicer)
mySentinel(600);
That is correct, changing the value or checked state of an input programatically does not fire the event handlers.
You'll have to trigger the event as well with javascript
document.getElementById('myCheckBox').addEventListener('change',function() {
console.log('Changed!');
});
document.getElementById('someLink').onclick = function() {
var box = document.getElementById('myCheckBox')
box.checked = !box.checked;
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
box.dispatchEvent(evt);
} else {
box.fireEvent("onchange");
}
};
and note that's it's onclick (all lowercase)
FIDDLE
EDIT
I want to avoid adding complexity to each link that will check this box.
So ideally ... I don't want to have to alter the link/click logic at all.
I want to be able to change the .checked property anywhere in the code and have it be detected without additional logic at each change (if possible).
And that's not really possible, without using horrible hacks with intervals etc.
When the checked state is changed programatically the event handler isn't triggered at all, because that would really be a huge issue in most cases, and much harder to work around the opposite scenario, where you just trigger the event handler manually instead, and that is really the only way to do it.
Of course, you can make it a lot more convenient using classes and external function and such
document.getElementById('myCheckBox').addEventListener('change',function() {
console.log('Changed!');
});
var links = document.querySelectorAll('.someLinkClass');
for (var i = links.length; i--;) {
links[i].addEventListener('click', triggerChange, false);
}
function triggerChange() {
var box = document.getElementById('myCheckBox')
box.checked = !box.checked;
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
box.dispatchEvent(evt);
} else {
box.fireEvent("onchange");
}
};
and anytime you add a link, you just add that class
Change the checkbox
Change the checkbox again
Change the checkbox even more
etc.
If you want to add more links that will trigger the checkbox, create a class name for them and use getElementByClass('classname')
Use onclick in your html, not js. Example: <div onclick="doSomething()"></div>
Just use an if/else statement for the check/uncheck:
if(document.getElementById('myCheck').checked){document.getElementById("myCheck").checked = false;} else{document.getElementById("myCheck").checked = true;}
I think jQuery have a change event. And you don't use it in the good way.
Read this page: http://api.jquery.com/change/
and this: jQuery checkbox change and click event
When any change occurs in the checkbox, jQuery event function is called. And then you can write anything in this event function
You can invoke/trigger an event but its not as easy as it seems, especially when you have to deal with internet explorer.
The cleanest solution is to put your event into its own function, then call it where you need it.
function handleEvent(){
console.log('Changed!');
}
documentent.getElementById('myCheckBox').addEventListener('change',function() {
handleEvent()
});
document.getElementById('someLink').onClick = function() {
// toggle checkbox
document.getElementById('myCheckBox').checked = !document.getElementById('myCheckBox').checked;
handleEvent();
};
HTML:
<a href="#" class="button" onclick="sendDetails(\'Edu\')">
JS:
function sendDetails(type) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
names = $("#names" + type).val();
Input = encodeURIComponent($("#Input" + type).val());
....
The link jumps to top of page. I tried to use event.preventDefault() to stop jumping to top of page. However, it works only in Chrome and not in IE and Firefox. How can I solve it?
instead of "#" you can use javascript:; so there is no jumping, make sure to return false to disable the link-behavior
link
You can't only use the window.event to control an event. Try standardizing it like:
function sendDetails(e, type) {
var evt = window.event || e;
if (evt.preventDefault) {
evt.preventDefault();
} else {
evt.returnValue = false;
}
// ...
}
And your HTML would have to be:
ASDF
One other non-jQuery solution is to just modify your HTML to be:
ASDF
in which case you wouldn't have to use anything dealing with event in your sendDetails function. The return false; will prevent the default behavior automatically. But note - if any exceptions occur in your sendDetails function, the return false; won't execute and will allow the default behavior. That's why I like using preventDefault - you can call it immediately in the function to immediately stop the behavior, then do what you need.
At the same time, if you're using jQuery, try binding the click event like this:
$(document).ready(function () {
$(".button").on("click", function (e) {
e.preventDefault();
// Your sendDetails code (without the "event" stuff)
// OR call sendDetails (and remove the "event" stuff in the sendDetails function)
});
});
in which case your HTML would be:
ASDF
Although it would be a lot easier to target the specific elements that this applies to, instead of using the .button selector I provided. I'm sure the "button" class applies to more than just these targeted <a>, but maybe I'm wrong :)
Using jQuery is nice in this situation because it already standardizes the event object in a way that you can just use that e variable I included in the click callback. I'm sure it does a little more than just window.event || e, so I'd prefer/suggest using jQuery for handling events.
You are already using jQuery, just do it the jQuery way. jQuery wraps the event object and provides a normalized event object so you can just use the standard preventDefault, you don't need to fork depending on what the browser supports.
<button class="senddetail" data-type="edu">Education</button>
<button class="senddetail" data-type="com">Commercial</button>
<!-- why not just use a button instead of styling a link to look
like a button? If it does need to be a link for some reason
just change this back to an anchor tag, but keep the data
attributes and change the class to "button senddetail" -->
<script>
function sendDetails(type) {
// Assuming names and input are not globals you need to declare
// them or they will become implicit globals which can cause
// all sorts of strange errors if other code uses them too
var names, input;
names = $("#names" + type).val();
// you should only use capitalized variables for
// Constructor functions, it's a convention in JS
input = encodeURIComponent($("#Input" + type).val());
//....
}
// just calling $ with a function inside of the invocation
// is the same as using $(document).ready
$(function () {
// instead of using onClick, use jQuery to attach the
// click event in a less intrusive way
$('.senddetail').on('click', function (event) {
// no matter what browser this runs in jQuery will
// provide us a standard .preventDefault to use
event.preventDefault();
// jQuery sets 'this' to the DOM element that the event fired on,
// wrapping it in another jQuery object will allow us to use the
// .data method to grab the HMLM5 data attribute
var type = $(this).data('type');
sendDetails(type);
});
});
</script>
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.
I'm trying to stop the browser from following certain links, rather I want to unhide some Divs when they are clicked.
I'm having trouble just getting the links to not be followed though.
Here's what I have:
var titles = $('a.highlight');
jquery.each(titles, function(){
this.click(function(){
return false;
});
});
It seems like the click handler is not being assigned. What am I missing?
Try
this.click(function(e){ e.preventDefault(); }
Actually, it looks like you might need to use the jQuery constructor on this:
$(this).click(function(){ return false; }
You could also try using parameters on the each function instead of using this:
jQuery.each( titles, function(index, elem) { $(elem).click( function() { return false; } ) } );
Personally, I would just do titles.each( ... though. In that instance you can use this to bind the click handler. I am not sure off the top of my head what this binds to with jQuery.each
Or just calling click on titles:
titles.click( function() { return false; } )
That will bind click to every element in titles. You don't need to loop through them.
You can compress that jquery a bit:
$('a.highlight').click(function() { return false; });
You should also make sure that:
There are no other click handlers registered for those elements later on.
The code you have is attaching after the elements have loaded. If they're not completely loaded, they won't be found in the $('a.highlight') selector. The easiest way to do this is to put your code in a $(document).ready(function() { *** code here *** }); block.
Edit: As per other responses - the problem was that this represents a DOM object, while $(this) is a jquery object. To use the .click function to attach a handler, you need a jquery object.
In short, using this inside the each loop won't work with what you're trying to do. You'll need to get a jquery representation by using $(this) instead.