jQuery toggle on click out - javascript

I have a series of spans (togglers) and a series of divs (toggled). I created a make_toggle function that receives the toggler and its corresponding toggled as arguments.
Everything seems to work kind of ok up to the point where I try to implement a "toggle on click out". What I've tried is to attach to the html click event a function that checks whether the target of the click is contained within the toggled element. On toggle "back", I would then detach the handler so I am only checking when I need.
var check_if_clickingout = function(e) {
if (!toggled[0].contains(e.target)) {
toggle();
}
};
See fiddle: https://jsfiddle.net/andinse/65o211nc/11/
It doesn't even seem to work anymore but when it used to, it was triggering many more times than necessary (which was the reason for me to come here ask for help).
What am I doing wrong? What is the most effective way to go about this kind of situation where I am giving functionality to a series of independent DOM elements?

Just putting this out here that this seems to do the same thing.
$("span").click(function() {
$(this).siblings("div").toggleClass("blue");
});
Maybe I am missing something more that I am not seeing in your example.
See more: http://api.jquery.com/toggleclass/

Related

Disable then Re-Enable onClick()

I have a website that I am creating and there are different divs each with their own content. All of them are hidden except the main one that shows up on the homepage. The transitions are pretty long, and I like it that way, but the problem is that if somebody spams the navbar buttons it opens up all those divs ontop of each other. So to prevent that I want to temporarily disable the onClick for an <a></a> element. Then enable it after the transition is done. Currently I am able to disable it, but cannot find a way to re-enable it.
function disable(){
$(".bar").unbind();
$(".bar").removeAttr("onClick");
}
I know how to call a function after a certain amount of time, but what is the "enable" equivalent to the code in this function?
The exact opposite would be to set the onClick back on the element.
$('.bar').attr('onClick', function() { alert('blah'); });
or with vanilla js
document.querySelector(".bar")
.setAttribute('onClick', function() {...});
However, this is difficult to manage for many elements with the same functionality. It would be easier to have this entirely managed with javascript (and jQuery in this case).
function clickEvent(event) {
var self = $(this);
// Unbind the event
self.off(clickEvent);
// Click logic here
// Rebind event
self.on('click', clickEvent);
}
$('.bar').on('click', clickEvent);
Instead of disabling the event on the DOM, you can just add an extra piece of logic to your dynamic divs:
$('#mydiv').click(function() {
if(!inTransition())
// DO A THING
else
// DON'T DO A THING
});
As a side note: If you're doing a lot of dynamic DOM manipulation, you may want to look into using a data binding framework such as Angular or Knockout. jQuery is nice for simple DOM manipulations, but it can quickly become messy and hard to maintain if you're doing something complex (which it sounds like you are).
As somewhat of an extension to nmg49's answer, I'd like to provide a solution that's a little more in depth.
Essentially what you'll want to do is create a flag to determine whether or not you are currently transitioning, and cancel the onClick if it is true (disabling it after the transition is complete).
var isTransitioning = false;
$('.bar').onClick(function(){
if(isTransitioning) return;
isTransitioning = true;
// DO TRANSITION
});
Once the transition is complete, you simply set isTransitioning to false (either in a callback, or at the end of your onClick function; which ever one applies to your code).
This will ensure that, no matter how many times they click the button, they will not be able to transition if they're already in transition.

Catch changes in dynamicly updated tables

I have a page that loads tables dynamically. I want to check if any of the tds contain a keyword, and depending on that change some CSS styling.
On first load everything works well, but when something changes in the table, my function doesn't get triggered.
Here is my code. The 1st block works well, but the 2nd doesn't?
$( document ).ready(function() {
$("tr td:contains('*')").each(function(){
$(this).parent("tr").css({ "background-color": "red" });
$(this).parent().children().css({ "background": "inherit" });
});
});
jQuery('body').on('change', '.content', function () {
$("tr td:contains('*')").each(function(){
$(this).parent("tr").css({ "background-color": "red" });
$(this).parent().children().css({ "background": "inherit" });
});
});
If I understand correctly, you're attempting to listen for changes in the table itself, meaning inner html changes, added rows, etc.
Unfortunately, the reason you're not seeing the change event firing is because that event only fires when the value of the element is changed; there is no such property for tables, rows and cells.
From jQuery's documentation on the change event, found here:
This event is limited to elements, boxes and
elements. For select boxes, checkboxes, and radio buttons,
the event is fired immediately when the user makes a selection with
the mouse, but for the other element types the event is deferred until
the element loses focus.
The reason why it works the first time is because, of course, you're not wrapping it in the change event; it is firing immediately when your on-ready function fires. Your selector works fine, of course, the table is simply never firing the event you're looking for.
I've not personally done this myself, but one solution found on SO can be seen here, which involves setting up a type of poller which constantly checks whether anything has changed. It also explains how you can then set up a custom event, which you can fire, thus further separating your code into manageable pieces.
Apparently they also discuss using jqGrid, which has a refresh event you may want to consider as well.
Hope that helps.
Edit
You might also be able to make use of the MutationObserver, whose documentation can be found here, and what looks like a pretty good example of its use on SO here. In the SO example, the poster indicates they tested it on browsers as far back as IE 7, however according to this, MutationObserver is not 100% compatible by itself (maybe he uses a polyfill), so make sure you test it properly.
Wrap the on change function with document.ready
$(function(){
/*code*/
});
Thanks everybody for your help, i found solution using custom build plugin that i found here:
jQuery watch div
It works like a charm for me!

jquery trigger hover on another element with same selector attributes

It sounds simple, and there's a solution involving altering CSS classes, but I was wondering if there's an elegant, on the fly solution to the following issue.
This is a similar question, but it creates "too much recursion" for my scenario.
So I have 2 buttons that both go to the next tab; one at the top of the content, one below. And I want them both to show the state of hover when I hover over either one of them. They have the same html code;
Next »
and following the other post, I've tried the solution;
$('a.step-next').on('mousenter mouseleave', function(e) {
$('a.step-next').not(this).trigger(e.type);
});
But my initial logic of using the not() is wrong; it'll just fire the event back and forward between each of the 2 elements.
Clearly, I can alter the CSS to add a new class and remove it on hover/not, which is the route I'll go down. But is there a trigger-only solution?
If i understand correctly you do not want the code-generated event to re-trigger the code..
If so, you can use the extraParameters of .trigger() method
$('a.step-next').on('mousenter mouseleave', function(e, fromCode) {
if (fromCode === undefined){
$('a.step-next').not(this).trigger(e.type, true);
}
});
Not sure what you want to achieve(html required) but this might be the solution you are looking for :
$('a.step-next').on('mousenter mouseleave', function(e) {
$(this).siblings('a.step-next').trigger(e.type);
});

how to prevent mutiple registration of a single event handler in jquery

I have a <div> box displaying search message and some radio button for recent message. There is link option for slide toggle.
When you click on that link it will show some input field and check box and radio button. And at the same time the text of link change to hide option. If you click on that it will hide all the input and checkbox option.
When I refreash the whole page its working properly but when that paticular box or part is refreashing then the box is hiding and imediately hides. If you refresh that portion n number of times the box is going on toggling continously. I think the problem is in registration of event handler. So please give me some solution.
CODE :
$(document).ready(function() {
$(".SideBar-blockheader1").click(function() {
e.preventDefault();
$(".SideBar-blockcontent1").slideToggle("fast");
});
$(".SideBar-optionheader").click(function() {
$(".SideBar-optioncontent").slideToggle("fast");
$(this).text($(this).text() == $("#hideopt").attr('value') ? $("#showopt").attr('value') : $("#hideopt").attr('value'));
});
$(".SideBar-optionheader").text($("#showopt").attr('value'));
$(".SideBar-optioncontent").hide();
});
jQuery has a method, called data() which can be used to extract the attached handler information of an HTML element. You can see if the element has already a click handler, and if it has, then stop re-attaching another handler to it.
if(typeof $('#id').data('events').click == 'object')
{
// A click handler is already attached
}
else
{
// No click handler; Attach one;
}
Although you haven't provided code, I suspect you are using .click(). For jQuery 1.7+ you should be using .on() in delegate mode (the element you bind to is an ancestor, not the clickable element itself) or .delegate() if pre jQ 1.7.
For example:
$('someAncestor').on('click', 'a.specialLink', function(event) {
event.preventDefault();
// the rest of your code for the click handler
})
"someAncestor" is any valid selector that is an ancestor of your link that will not be destroyed, rebuilt, or otherwise manipulated after the DOM is built. It doesn't have to be the direct ancestor.
[updated below after seeing code sample and comments]
There are a few things going on. First, .on() will only work if you're using jQuery 1.7+. Next, .on() can be invoked a few different ways (I wrote about it here: http://gregpettit.ca/2011/jquery-events-its-on/) and you need to be invoking it while delegating an ancestor listener, not simply as a substitute for click. Next, you haven't provided code for your attempted update, only for the original code; it's hard to tell what "didn't work" about trying to use .on(). Moving along, I'm not actually sure what this line is meant to do:
$(this).text($(this).text() == $("#hideopt")...etc...
I can't think of why you would want to try to treat a jQuery object as a variable. I'm not saying the code is wrong, I'm just saying I don't get it. Also, I hate ternary operators... which is part of the reason I don't get it. I much prefer readable conditionals. ;-)
Next, you're calling preventDefault() on "e" but you're not passing "e" into your functions. You might just be getting a JavaScript error, period. (e is undefined)
Then there's attr("value") which I believe should actually work. But why not use .val() if it is indeed a node that HAS a value attribute?
Finally, there is tonnes of room for caching your objects. Every time you see that an object is being used more than once, you can benefit (to varying degrees of performance and legibility) from caching it. I have not updated the code with any caching, though-- that's really something for a whole other "How can I best cache my objects?" question.
Anyhow... to solve the problem, you first have to choose a valid ancestor. This can be any ancestor that isn't destroyed during the process of loading in your new data. This could be anything, but the closest ancestor is the best. It might be a section wrapper, but if you're truly desperate it could be a page wrapper or even the body tag. If you bind to document, you're reproducing the deprecated .live() function, which I definitely recommend against. I have used a placeholder selector, ".section" but you need to figure out what an appropriate ancestor is on your page.
$(document).ready(function()
{
$(".section").on("click", ".SideBar-blockheader1", function(e)
{
e.preventDefault(); // probably not necessary if there's no default click behaviour
$(".SideBar-blockcontent1").slideToggle("fast");
});
$(".section").on("click", ".SideBar-optionheader", function(e)
{
e.preventDefault(); // probably not necessary if there's no default click behaviour
$(".SideBar-optioncontent").slideToggle("fast");
$(this).text($(this).text() == $("#hideopt").val() ?$("#showopt").val() : $("#hideopt").val());
});
$(".SideBar-optionheader").text($("#showopt").val());
$(".SideBar-optioncontent").hide();
});

Mouseover events in one object, and mouse out events on an object resulting of the first event

The title is a little bit messy, so let me try to explain in the actual question:
Suppose I have the following HTML setup.
<div id="userMenu">
<div id="userMenu-expanderLink">Mouseover here!</div>
<div id="userMenu-collapserLink">You can close the menu by mouse out.</div>
<div id="userMenu-expandedContent">Extra Content</div>
</div>
Now, userMenu and userMenu-expanderLink are shown by default. userMenu-expandedContent and userMenu-collapserLink are hidden by default.
What I am trying to do in jQuery is to slideDown the userMenu-expandedContentwhen a mouseover event occurs on userMenu-expander. All good there, this is my code:
$("#userMenu-expanderLink").mouseover(function() {
$("#userMenu-expandedContent").stop().slideDown(200);
$("#userMenu-expanderLink").hide();
$("#userMenu-collapserLink").show();
$("#userMenu").addClass("userMenu-expanded");
});
As you can see, I'm also hiding the expanderLink and showing the collapserLink; and also adding a class called userMenu-expanded to #userMenu. Until now, this code has no problems. Everything works well.
But now, I want that when the user has a mouseOut event on #userMenu.userMenu-expanded, effectively moving his mouse out of the #userMenu that is expanded, I want when that happens, the expandedContent is slideUp'd, the expander and collapser links swapped, and the class removed. I know how to do that, but handling the event seems to be a problem.
Putting $("#userMenu.userMenu-expanded")... directly alongside the code I have of course does not work, since a div with such id and such class is only generated if the menu has been expanded, and the div's class is removed once the menu is collapsed. I don't directly use a mouseover/mouseout event on one object because I want the collapsing to be triggered only when the user takes his mouse out of the menu, not the expander link.
So, here's my problem. How can I get such mouse out event? I have tried adding the event handler in the callback of .addClass, but no avail, it would basically permanently close that expanded menu (basically I can't ever expand it again until I reload the page).
How can this be done? I'm not very experienced with jQuery, so a detailed answer would be most appreciated. I'm more interested on how can this be done rather than just accomplishing it, I want to learn ^_^.
Thanks!
I have found a correct way to do this. This is my final implementation.
$(document).ready(function() {
// UserMenu Expander, which is also a form of drop down
$("#userMenu-expander").mouseenter(function() {
//alert("Usermenu expanding…");
$("#userMenu-expandedContent").slideDown(200, function() {
$("#userMenu").addClass("userMenu-expanded");
});
$("#userMenu-expanderLink").hide();
$("#userMenu-collapserLink").show();
});
$("#userMenu.userMenu-expanded").live('mouseleave', function() {
//alert("Usermenu de-expanding…");
$("#userMenu-expandedContent").slideUp(200);
$("#userMenu-expanderLink").show();
$("#userMenu-collapserLink").hide();
$("#userMenu").removeClass("userMenu-expanded");
});
});

Categories