I wrote an alternative to the jQuery Accordion, as that didn't offer multiple open section support (any idea why they opted to not include support for that? What's the history there?). I did some research on StackOverflow, as well on Google to see what other options others came up. I needed something that could be used on the fly on multiple elements.
After seeing several solutions and experimenting with them, in the end, I wrote my own version (based on Kevin's solution from http://forum.jquery.com/topic/accordion-multiple-sections-open-at-once , but heavily modified).
jsFiddle can be found here: http://jsfiddle.net/3jacu/1/
Inline Code:
$(document).ready(function(){
$.fn.togglepanels = function(){
return this.each(function(){
h4handler = $(this).find("h4");
$(h4handler).prepend('<div class="accordionarrow">▼</div>');
$(h4handler).click(function() {
$(h4handler).toggle(
function() {
barclicked = $(this);
$(barclicked).find(".accordionarrow").html('►');
$(barclicked).next().slideUp('slow');
window.console && console.log('Closed.');
return false;
},
function() {
barclicked = $(this);
$(barclicked).find(".accordionarrow").html('▼');
$(barclicked).next().slideDown('slow');
window.console && console.log('Open.');
return false;
}
);
});
});
};
$("#grouplist").togglepanels(); }
Oddly, the accordion arrow at the right side stopped working once I pasted it in jsFiddle, while it works in my local copy.
In any case, the issue is that toggling isn't working as expected, and when it does, it fires duplicate toggle events which result in it closing, opening, then ultimately closing the section and it won't open from that point on (it toggles open then closes back). That's assuming it works! At first, it won't work as it doesn't respond. I think there's a logic error somewhere I'm missing.
From what I wrote/see in the code, it searches the given handle for the corresponding tag (in this case, h4), pops the handle into a variable. It then adds the arrow to the h4 tag while applying the accordionarrow class (which floats it to the right). It then adds a click event to it, which will toggle (using jQuery's toggle function) between two functions when h4 is clicked.
I suspect the problem here is that I may be mistakenly assuming jQuery's toggle function will work fine for toggling between two functions, that I'll have to implement my own toggle code. Correct me if I'm wrong though!
I'm trying to write the code so it'll be as efficient as possible, so feedback on that also would be appreciated.
Thanks in advance for your time, assistance, and consideration!
You have the toggle binding (which is deprecated by the way) inside of the click binding, so a new event handler is getting attached every time you click the header.
As a random aside you should also fire events within the plugin (where you have the console lines would make sense) so that external code can react to state changes.
I believe your issue is the $(h4handler).click(function() { you have wrapped around the toggle listener. Essentially what this was doing was making so every click of the tab was adding the toggle listener, which was then also firing an event. Removing the click listener will have the behaviour you expect.
You forgot to paste the trailing characters ); to close the function call to jQuery function ready. Fixed: http://jsfiddle.net/LeZuse/3jacu/2/
UPDATE: I've just realised I did not really answer your question.
You are duplicating the .toggle functionality with binding another .click handler.
The doc about .toggle says:
Description: Bind two or more handlers to the matched elements, to be executed on alternate clicks.
Which means the click event is already built in.
NOTE: You should use local variables instead of global, so your plugin won't pollute the window object. Use the var keyword for this:
var h4handler = $(this).find("h4");
Related
I need to change behavior of jQuery library (date range picker), it have code like this:
box.find('.month').off("change").change(function(evt) {
dateChanged($(this));
});
box.find('.year').off("change").change(function(evt) {
dateChanged($(this));
});
Those are two select elements. It don't return false and functions inside handler don't access the event. But for some reason my events that use delegation doesn't work. They are ignored.
$picker.on('change', 'select', function() {
console.log('CHANGE');
});
The console log is not executing, but if I remove previous lines from the library, my event delegation code works fine.
NOTE: $picker is object in my code that is parent of box element. But I also have event added on $(document) that is also not working.
First time I see something like this. Adding event directly to element, prevents event propagation. Can someone explain what is happening here? Is this documented anywhere?
This happens in Firefox and Chrome.
If someone need simple example, I can create one. But thought that this is self explanatory.
EDIT: I've created a simple reproduction and it works fine. I have complex application with a lot of files (R Shiny Application), but I don't see any change events in dev tools. Are there any way of making the event not propagate? Maybe using event capturing. What should I search for in order to find the code that is preventing the events from propagating?
Still new to the forums, so I'll try my best to get across the problem. Basically I'm developing a mobile web app, and have several ontap functions for reloading the webpage after buttons clicked. Here is the code for two of my smaller onTap functions for demonstration purposes (so you don't have to sift through hundreds of lines of code). The licenses_button ontap function works perfectly fine, with no forms of errors whatsoever, but the back_button ontap function, and all other buttons that aren't created on the initial main page of the app won't act as button's and I have no idea why. Any advice? (I know the back_button has little to no content, I just removed a lot of it for debugging purposes and even this fails to work). Thanks for any advice!
$("#licenses_button").onTap(function(event){
$("#play_button").remove();
$("#banner").remove();
$("#licenses_button").remove();
$(".cloud").remove();
$(".cloudalternate").remove();
$("body").append("<div id='back_button'>Back</div");
});
$('#back_button').onTap(function(event) {
$('#back_button').remove();
});
$(selector).onTap(callback); attaches the handler to the selected elements at the moment it is called. Elements that are not yet created at this time cannot be selected (obviously since they do not exist yet) and thus, won't get the handler.
You need to attach the handler after you added an element.
For example:
$("#licenses_button").onTap(function(event){
$("#play_button").remove();
$("#banner").remove();
$("#licenses_button").remove();
$(".cloud").remove();
$(".cloudalternate").remove();
// Create the button.
var backButton = $("<div id='back_button'>Back</div");
// Append it to the body.
$("body").append(backButton);
// Attach the handler to the new button.
backButton.onTap(function(event) {
backButton.remove();
});
});
You mentioned the back_button and other buttons that aren't working are not created in the main page. Since these are created at a later time, you have to wait to set up the onTap event for those buttons AFTER you create the buttons. If you try to set the event handler up before they're created, they won't work.
Alright, so I'm making a Facebook-style chat. But that doesn't really matter.
See here:
http://jsfiddle.net/SkHme/7/
Nice and pretty, right? Well, there's a problem. Notice this line:
<div class="conversation EmperorCuzco" onclick="setActive('EmperorCuzco')">
See the onclick attribute? Well, it's not working. However, I have confirmed that the function itself DOES work. (if you run it just like that in the JavaScript, it runs like a dream) I have further confirmed that the function is not the problem by attempting to replace the onclick value with a simple alert('blah'), but that doesn't work either.
So, what's up? I'm guessing that something in my JavaScript is somehow disabling something, but I have absolutely no idea what it could be, nor how I could go about fixing it. I did some web searching, but couldn't find anything that helps.
What's going on?
Your setActive function is defined inside the scope of the $(document).ready handler. Move the function outside that function so that it is in the global scope.
Right now it looks like this:
$(document).ready(function()
{
// ...
function setActive(new_conversation)
{
// ...
}
});
Now change that to:
$(document).ready(function()
{
// ...
});
function setActive(new_conversation)
{
// ...
}
Really though, you should separate your content from your interactions and bind those event handlers in your script itself. Something like:
// Refers to the last clicked conversation *button*
// Initialize to empty jQuery object
var $active_conversation = $([]);
// Binding on #chat, targeting click events on .conversation_button children
$("#chat").on("click", ".conversation_button", function() {
// Hide currently active conversation
$active_conversation.hide();
$active_conversation.siblings('.conversation_button').removeClass("selected");
// Set as currently active conversation button
// Note: this refers to the clicked <div class="conversation_button">
var $this = $(this);
$active_conversation = $this.siblings('.conversation');
// Show this conversation
$active_conversation.show();
$this.removeClass("alert").addClass("selected");
});
Some advantages of this approach:
You don't need different classes for different conversations. By storing the actual conversation DOM element (as a jQuery object) in $active_conversation, the conversation can be identified without any extra processing.
You can add and remove whole list items with a conversation without assigning new event handlers. In the sample above, the event handler for all .conversation_button elements is defined at the level of #chat. For more about this binding mechanism, read up on .on (or .delegate for pre-1.7).
Here, have an updated fiddle! :-)
If all you say is really true (bad mistakes happen), the only thing that can make this is that an other event handler which takes your event before uses stopPropagation() or return false;
A quick check that can do is replace onclick with onmousedown or onmouseup, and see if you alert become visible.
I have a div that when the page is loaded is set to display:none;. I can open it up using this simple code:
$(".field-group-format-toggler").click(function()
{
$(".field-group-format-wrapper").css({'display':'block'});
});
Once it's opened, I'd like the user to be able to close it so I tried using the .is(':visible') function and then wrapping my original code in an if statment but this time using display:none;
if($('.field-group-format-wrapper').is(':visible')){
$(".field-group-format-toggler").click(function()
{
$(".field-group-format-wrapper").css({'display':'none'});
});
}
This does not seem to work though and I am not getting any syntax errors that I know of.
I also tried this:
if ($('.field-group-format-wrapper').is(':visible'))
$(".field-group-format-toggler").click(function () {
$(".field-group-format-wrapper").css({'display':'none'});
});
... but that did not work either.
You can just use the toggle function:
$(".field-group-format-toggler").click(function()
{
$(".field-group-format-wrapper").toggle();
});
This will show the '.field-group-format-wrapper' elements if they are currently hidden and hide them if they're currently visible.
FYI the reason your code snippet in your question wasn't working is because you're only checking the visibility of the elements on dom ready, rather than on each click - so the event handler to show the elements will never be attached.
I guess your function is only being called on page load at which time all divs are hidden.
Why not check the visibility in the click event handler?
$('.field-group-format-toggler').click(function(){
var $wrapper = $('.field-group-format-wrapper'); //Maybe $(this).parent()?
if($wrapper.is(':visible'))
$wrapper.hide();
else
$wrapper.show();
As already mentioned, you can use the toggle function to achieve what you want.
To add a bit of extra information, when attaching events like you're doing, you're actually using a subscription model.
Registering an event puts it in a queue of events subscribed to that handler. In this case, when you add the second event to change the CSS, you're adding an event, not overwriting the first one.
Whilst thing isn't actually causing your problem, it's worth being aware of.
It seems that this code:
$(function(){
$('.show_hide_login').toggle(
function (){
alert('show');
$("div#fullpage").show();
$("div#loginbox").show();
},
function (){
alert('hide');
$("div#loginbox").hide();
$("div#fullpage").hide();
}
); });
Any idea on why it would be running twice when I click on either link (two, one is a div and one is an anchor)?
How many elements do you have with the .show_hide_login class? I'll guess you have two of those. In which case, $('.show_hide_login') result contains two elements, and toggle() is executed for each of them.
This isn't an answer to your question, but you could clean up your code a bit like so:
$(function() {
$('.show_hide_login').toggle(
function() {
alert('show');
$("#loginbox,#fullpage").show();
}, function() {
alert('hide');
$("#loginbox,#fullpage").hide();
});
});
As to your actual problem, I suspect Nick's guessed the culprit. Check out this demo to see the result of binding the same event twice: http://jsfiddle.net/9jPLv/
In addition to adding an alert prior to the binding of the toggle event, you could add in an unbind() and see if that solves the problem, like so:
$('.show_hide_login').unbind().toggle(
If that solves it, the toggle binding is definitely being run twice, so you'd just have to figure out why.
my answer is just a kind of checkpoint,i had the same issue but for different reason. I did include the script file in base page as well as child page. this resulted in toggle running twice if you have this problem check that the script is added only once.
It might be the same issue i was having.
so if you got an element with a script tag in it - then you move that containing element or wrap it with another tag in jquery - then the ready function in jquery is executed again - thus binding a second toggle function to your element.
as suggested $('.show_hide_login').unbind().toggle( is a workaround that does work, but better to try moving your javascript code to the head or bottom of the page.