I'm trying to toggle between divs so that when an tag is clicked a div will show.
When another a tag is clicked, the div will replace the div shown.
This is what I did.
HTML:
a<br>
b<br>
c<br>
d<br>
<div id="slidingDiv">a</div>
<div id="slidingDiv_2">a</div>
<div id="slidingDiv_3">a</div>
<div id="slidingDiv_4">a</div>
JQUERY:
function ($) {
$.fn.showHide = function (options) {
//default vars for the plugin
var defaults = {
speed: 1000,
easing: '',
changeText: 0,
showText: 'Show',
hideText: 'Hide'
};
var options = $.extend(defaults, options);
$(this).click(function () {
var toggleDiv;
var $divA = $('#slidingDiv'),
$divB = $('#slidingDiv_2'),
$divC = $('#slidingDiv_3'),
$divD = $('#slidingDiv_4'),
$divE = $('#slidingDiv_5'),
$divF = $('#slidingDiv_6'),
$divG = $('#slidingDiv_7'),
$divH = $('#slidingDiv_8'),
$divI = $('#slidingDiv_9');
if( $divA.is( ':visible' ) ){
$divA.hide();
}
if( $divB.is( ':visible' ) ){
$divB.hide();
}
if( $divC.is( ':visible' ) ){
$divC.hide();
}
if( $divD.is( ':visible' ) ){
$divD.hide();
}
if( $divE.is( ':visible' ) ){
$divE.hide();
}
if( $divF.is( ':visible' ) ){
$divF.hide();
}
if( $divG.is( ':visible' ) ){
$divG.hide();
}
if( $divH.is( ':visible' ) ){
$divH.hide();
}
if( $divI.is( ':visible' ) ){
$divI.hide();
}
// this reads the rel attribute of the button to determine which div id to toggle
toggleDiv = $(this).attr('rel');
$('.toggleDiv').slideUp(options.speed, options.easing);
// this var stores which button you've clicked
var toggleClick = $(this);
var toggleDiv = $(this).attr('rel');
// here we toggle show/hide the correct div at the right speed and using which easing effect
$(toggleDiv).slideToggle(options.speed, options.easing, function() {
// this only fires once the animation is completed
// if(options.changeText==0){
//$(toggleDiv).is(":visible") ? toggleClick.text(options.hideText) : toggleClick.text(options.showText);
//}
});
return false;
});
};
})(jQuery);
This currently works, but I know that this can be done better instead of using the if statement.
Thanks
Here we go: http://jsfiddle.net/fqK36/5/
Your whole function becomes:
$.fn.showHide = function (options) {
//default vars for the plugin
var defaults = {
speed: 1000,
easing: '',
changeText: 0,
showText: 'Show',
hideText: 'Hide',
slideDiv: '.slide-div'
};
var options = $.extend(defaults, options);
return this.each(function () {
$(this).click(function () {
$(options.slideDiv).hide();
// this var stores which button you've clicked
var toggleClick = $(this),
toggleDiv = $(this).data('slide-id');
// here we toggle show/hide the correct div at the right speed and using which easing effect
$(toggleDiv).slideToggle(options.speed, options.easing, function () {
// this only fires once the animation is completed
// if(options.changeText==0){
//$(toggleDiv).is(":visible") ? toggleClick.text(options.hideText) : toggleClick.text(options.showText);
//}
});
});
});
};
Then you can use it like this:
$('a').showHide({'slideDiv' : '.slide-div'});
The slideDiv option can be a custom selector you're using can the divs you wish to slide.
All slides are assigned a class which means you can hide them all at once. Then you can show the targeted div by getting the clicked link's data-slide-id attribute.
Generally, I do this by creating a hidden class. When you go to switch to a new div, you can do something like this:
$(this).click(function(){
$(this).removeClass('hidden')
$('div:not(#' + $(this).attr('id') + ')').addClass('hidden')
});
This uses the not selector to find everything but your current item. Sans animation, this is the simple way to do it. You can also grab whatever is not hidden by using $('div:not(.hidden)') and then run your toggle on everything in that selector.
$(this).click(function(){
if($(this).hasClass('hidden'){
$(this).show()
$(this).removeClass('hidden')
}
$('div:not(#' + $(this).attr('id') + ') :not(.hidden.)')
.hide().addClass('hidden')
});
Might help clean things up a bit.
Related
I created a small jQuery plugin that shows and hides a div when the user clicks on the button .show and the button .hide, respectively. I want to pass a function as a plugin option to do some specific processing for onhide. But the onhide function executes as many times as the show and hide buttons are clicked.
Here is the jsfiddle.
When you click show/hide buttons more then once then the alert will show the same number of times.
I think it should alert only once for the hide button.
$.fn.showhide = function(options){
var popup = this;
defaultOptions = {
onHide : function() { },
onShow : function() { }
};
var Options = $.extend({},defaultOptions, options);
this.each(function() {
$(this).on('click',function(e){
var id = $(this).data('id');
$('#'+id).show();
$('.hide').on('click',function(){
var id = $(this).data('id');
$('#'+id).hide();
if (Options.onHide.call() === false) {
return;
}
});
});
});
}
$('.show').showhide({
onHide :function() {
alert('hide');
}
}
);
It's because you're implementing your onHide method inside a loop.
Move this bit:
$('.hide').on('click',function(){
var id = $(this).data('id');
$('#'+id).hide();
if (Options.onHide.call() === false) {
return;
}
});
to right before your closing bracket of your method and everything works fine!
Edit: Fiddle here: https://jsfiddle.net/ka9gw09t/10/
Just replace
$('.hide').on('click',function(){
To
$('.hide').one('click',function(){
Explanation:
With your code, each time the user clicks on .show you attach one more delegation .click to the button. one will do it just once.
$.fn.showhide = function(options){
var popup = this;
defaultOptions = {
onHide : function() { },
onShow : function() { }
};
var Options = $.extend({},defaultOptions, options);
this.each(function() {
$(this).on('click',function(e){
var id = $(this).data('id');
$('#'+id).show();
$('.hide').unbind('click').one('click',function(){
var id = $(this).data('id');
$('#'+id).hide();
if (Options.onHide.call() === false) {
return;
}
});
});
});
};
$('.show').showhide({
onHide :function() {
alert('hide');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="show" data-id="123">
Show
</button>
<button class="hide" data-id="123">
Hide
</button>
<div class="showhide" id="123" style="display:none;">
This is div with id 123
</div>
Update
I was added unbind('click') before the one to unbind the older listeners.
I am trying to use the same button to trigger an ajax call to add a database entry if it is clicked and then trigger a different ajax call to remove the entry it is clicked again.
I have tried using toggleClass and although the button class does change and it's appearance changes accordingly the function still thinks it has the old class name.
$(document).ready(function() {
$(".selected").on("click", function() {
$(this).text(function (i, oldText) {
return $.trim(oldText) == 'Use Image' ? 'Selected' : 'Use Image';
});
$(this).toggleClass('selected selected_btn');
});
$(".selected").on("click", function() {
alert('selected');
});
$(".selected_btn").on("click", function() {
alert('de selected');
});
});
With the present code the alert is always 'selected'.
$(document).ready(function() {
$(".selected_btn").on("click", function() {
$(this).text(function (i, oldText) {
return $.trim(oldText) == 'Use Image' ? 'Selected' : 'Use Image';
});
$(this).toggleClass('selected');
if($(this).hasClass("selected"))
alert("Selected")
else
alert("de-Selected")
});
});
here is a fiddle:
http://fiddle.jshell.net/prollygeek/3LLN2/
Here is a simple and readable example on how to do this:
$(document).ready(function() {
$('.select-img').on('click', function(){
var $el = $(this);
var isSelected = $el.attr('data-selected');
if( isSelected != 'true' ){
firstFn();
$el.html('Use Image').attr('data-selected', true)
}else{
secondFn();
$el.html('Select').attr('data-selected', false)
}
})
var firstFn = function(){
alert('first thing to do');
}
var secondFn = function(){
alert('second thing to do');
}
})
Demo
Use *Class functions:
hasClass
removeClass
addClass
Working code:
$("a").on("click", function() {
if($(this).hasClass("bob")) {
// do delete
alert("delete");
$(this).removeClass("bob");
} else {
// do insert
alert("insert");
$(this).addClass("bob");
}
});
Demo
$(".selected").on("click", function() {
alert('selected');
});
Overrides the event you put on the beginning of the document.ready, I think.
(might not be true, but I think it is)
How to extend a jQuery plugin?
currently I am using multiopen accordion plugin.
I need to add new feature like once the expand/collapse is finished I need to callback a function as like change event in jquery ui accordion plugin.
How to add this feature in this plugin.
you dont need the accordion widget for that. you can do this with a few lines of jQuery.
html:
<h3 class="header"> Title 1 </h3>
<div class="content"> Content 1 </div>
<h3 class="header"> Title 2 </h3>
<div class="content"> Content 2 </div>
javascrpt/jQuery:
( function( $ ){ // closure to make sure jQuery = $
$( function(){ // on document load
$( ".header" ).click( function( e ){ // select headers and set onClick event handler
// here you can maybe add a class to an opened header like this
$( this ).toggleClass( "open" );
$( this ).next().toggle( "slow", function(){ // toggle visibility
// what you write here will be executed after the animation
// "this" will refer to the hidden/revealed div element
// if you want to call a function depending on if the
// panel was opened or closed try this
if ( $( this ).is( ":visible" ) ) {
tabOpened( e, this );
} else {
tabClosed( e, this );
}
})
}).next().hide()
})
})(jQuery)
and the whole thing working on jsfiddle
http://jsfiddle.net/qpqL9/
You can easily call your function in the callback functions of the animation done on the tabs.
Slight changes in jquery.multi-accordion-1.5.3.js
$div.slideDown('fast', function(){
$div.addClass(options._classes.divActive);
//function to be called after expanding the tabs.
});
$div.slideUp('fast', function(){
$div.removeClass(options._classes.divActive);
//function to be called after collapsing the tabs
});
$.extend($.ui.multiAccordion, {
// private helper method that used to show tabs
_showTab: function($this) {
var $span = $this.children('span.ui-icon');
var $div = $this.next();
var options = this.options;
$this.removeClass('ui-state-default ui-corner-all').addClass('ui-state-active ui-corner-top');
$span.removeClass('ui-icon-triangle-1-e').addClass('ui-icon-triangle-1-s');
// MODIIFICATION
bindThis = this;
var ui = {
tab: $this,
content: $this.next('div')
}
$div.slideDown('fast', function(){
$div.addClass(options._classes.divActive);
// MODIFICATION
bindThis._trigger('tabShownComplete');
});
this._trigger('tabShown', null, ui);
},
// private helper method that used to show tabs
_hideTab: function($this) {
var $span = $this.children('span.ui-icon');
var $div = $this.next();
var options = this.options;
$this.removeClass('ui-state-active ui-corner-top').addClass('ui-state-default ui-corner-all');
$span.removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e');
// MODIIFICATION
bindThis = this;
var ui = {
tab: $this,
content: $this.next('div')
}
$div.slideUp('fast', function(){
$div.removeClass(options._classes.divActive);
// MODIFICATION
bindThis._trigger('tabHiddenComplete', null, ui);
});
this._trigger('tabHidden', null, ui);
}
});
https://gist.github.com/4342758
Have you try the tabHidden and tabShown methods?
// when tab is shown, ui here hold the same as in click event above
tabShown: function(event, ui) {}
// when tab is hidden, ui here hold the same as in click event above
tabHidden: function(event, ui) {}
I have a jQuery plugin that uses namespacing (methods) and also has options, with defaults, that can be overridden on initialization.
I'm wondering what the best way to define and use options is with this plugin in the namespaces.
I was originally using a $.fn.dropIt.settings within the wrapper function to define the settings, but then switched to defining them inside of the init method. This is very limiting in terms of scope however..
Here is the relevant code in my plugin
(function($, window, document, undefined){
var methods = {
init: function(options)
{
var settings = $.extend({
trigger: "hover",
animation: 'slide', /* none, slide, fade, grow */
easing: 'swing', /* swing, linear, bounce */
speedIn: 400,
speedOut: 400,
delayIn: 0,
delayOut: 0,
initCallback: function(){},
showCallback: function(){},
hideCallback: function(){}
}, options);
$(this).each(function(index, ele){
$ele = $(ele);
$ele.addClass('dropit');
//Attach event handlers to each list-item
$('li', $ele).dropIt('attach', settings);
//If list is displayed veritcally, add extra left padding to all sub-menus
if($(ele).hasClass('vertical'))
{
$('li', $ele).find('ul').addClass('nested sub-menu');
} else {
$('li ul', $ele).addClass('nested').find('ul').addClass('sub-menu');
}
});
//Call custom callback
settings.initCallback.call();
//Return jQuery collection of lists
return $(this);
},
attach: ...
_trigger: ...
_hide: ...
}
};
$.fn.dropIt = function(method){
//Variables and Options
var $this = $(this);
// Method calling logic
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.dropIt' );
}
};
})(jQuery, window, document);
After reading the jQuery Plugins/Authoring page, I structured by plugin basically like this:
(function ($) {
var defaults = {
// set default options
}
// internal functions
var methods = {
// plugin methods
}
$.fn.pluginName = function (method) {
}
})(jQuery);
And, like you have, $.extend the defaults within the init method, but I like to keep the defaults declared separately, personally, for clarity. It's been working well for me.
I always set the settings object as a global var to the plugin scope, like this:
(function($, window, document, undefined){
var settings; //NOTE THIS LINE
var methods = {
init: function(options)
{
settings = $.extend({ //AND THIS LINE
trigger: "hover",
animation: 'slide', /* none, slide, fade, grow */
easing: 'swing', /* swing, linear, bounce */
speedIn: 400,
speedOut: 400,
delayIn: 0,
delayOut: 0,
initCallback: function(){},
showCallback: function(){},
hideCallback: function(){}
}, options);
$(this).each(function(index, ele){
$ele = $(ele);
$ele.addClass('dropit');
//Attach event handlers to each list-item
$('li', $ele).dropIt('attach', settings);
//If list is displayed veritcally, add extra left padding to all sub-menus
if($(ele).hasClass('vertical'))
{
$('li', $ele).find('ul').addClass('nested sub-menu');
} else {
$('li ul', $ele).addClass('nested').find('ul').addClass('sub-menu');
}
});
//Call custom callback
settings.initCallback.call();
//Return jQuery collection of lists
return $(this);
},
attach: ...
_trigger: ...
_hide: ...
}
};
$.fn.dropIt = function(method){
//Variables and Options
var $this = $(this);
// Method calling logic
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.dropIt' );
}
};
})(jQuery, window, document);
EDIT:
You can also do $(this).data('youPlugInName', settings), then if you want to change it latter you can retrieve this from data('yourPlugInName'), and update whatever property you want.
I have a + icon and a - icon. When someone clicks the + icon a box appears and the icon changes to a - icon. If they click again the box disappears and the icon changes to a + icon.
Here is the code I tried but its not working...
$("#box").toggle(function(e){
$("#icon").attr ("src","/images/icon_expand.png")
},
function(e) {
$("#icon").attr("src","/images/icon_retract.png")
}
);
Any ideas?
Thank you!
The .toggle() function attaches click handlers to the element, not event handlers for then an element is toggled visible, it should be attached to #icon, like this:
$("#icon").toggle(function(){
$("#box").hide();
this.src = "/images/icon_expand.png";
}, function() {
$("#box").show();
this.src = "/images/icon_retract.png";
});
$.togle () toggles the visibility of the matched element(s). So you are using it completely wrong.
You'll have to do something like this:
$( '#icon' ).click ( function () {
var $this = $( this );
var $box = $( '#box' );
$box.toggle ();
if ( $box.is ( ':visible' ) === true ) {
$this.attr ( "src", "/images/icon_retract.png" );
} else {
$this.attr ( "src", "/images/icon_expand.png" );
}
} );
i think, there will be a correction in Nick code and then it will work fine.
you have to first show the box and on second click you have to hide it, if is it so,
then try this
$("#icon").toggle(function(){
$("#box").show();
this.src = "/images/icon_expand.png";
}, function() {
$("#box").hide();
this.src = "/images/icon_retract.png";
});