I'm working on a portfolio site for an iPhone developer. In this site the iPhone app icons will act as a toggle buttons for panels that describe the application. The panels animate over the main page content. To add to this, if a panel is open and another app icon is clicked the open panels will need to close and the next app will open. Currently the script I have works great for toggling a single panel, see here: http://cncpts.me/dev/
So how can change the current script so it accepts multiple ids or classes, without creating duplicate code?
Here is the jQuery that is driving the functionality for a single toggle action.
$(document).ready(function() {
$("li.panel_button").click(function(){
$("div#panel").animate({
height: "700px"
})
.animate({
height: "600px"
}, "slower");
$("div.panel_button").toggle('zoom'); return false
});
$("div#hide_button").click(function(){
$("div#panel").animate({
height: "0px"
}, "slower"); return false
});
});
Here is the HTML:
<div id="panel">
<div id="panel_contents"></div>
<img src="images/iphone.png" border="0" alt="iPhone Development">
<div class="panel_button" id="hide_button" style="display: none;">
<img src="images/collapse.png" alt="collapse" />
</div>
</div>
give the list items a rel attribute that points to the div you are trying to show/hide.
<li rel='#panel_1' class='panel_button'>
give all the div's a common class such as 'flyaway', do a hide on any div with the same class that is not currently hidden
$('.flyaway').not(':hidden').animate({ height: "0px"}, "slower");
and show the one you want
$("li.panel_button").click(function(){
$($(this).attr('rel')).animate({
height: "700px"
})
.animate({
height: "600px"
}, "slower");
$($(this).attr('rel')+" div.panel_button").toggle('zoom'); return false
});
Here is my solution:
// Plugtrade.com - jQuery Plugin :: Bounce //
// answer for http://stackoverflow.com/questions/5234732/jquery-multiple-panel-toggle
jQuery.fn.bounce = function (el, bounceheight) {
var thisdiv = this;
var owidth = thisdiv.width();
var oheight = thisdiv.height();
var trigger = $(el);
// what we want is to make a parent div and then
// get the child div's dimensions and copy it's position
// display, width and height //
// child then becomes an absolute element nested within the
// parent div.
thisdiv.wrap('<div class="bounceparent"></div>');
// let's make a hidden button
thisdiv.append('<input type=text class="bouncehide" style="display:none" />');
var thishidebtn = thisdiv.last();
var thisparent = thisdiv.parent();
thisparent.width(owidth);
thisparent.height(oheight+bounceheight);
thisparent.css('border', '1px solid #ccc');
thisparent.css('position', thisdiv.css('position'));
thisparent.css('overflow', 'hidden');
thisdiv.css('position', 'relative');
thisdiv.css('top', oheight+bounceheight);
thisdiv.css('height', '0');
var toggle = false;
thishidebtn.click(function() {
if(toggle)
{
toggle = false;
thisdiv.animate({ top: 0, height:oheight+bounceheight }).animate({ top: oheight+bounceheight, height:0 });
}
});
trigger.click(function() {
// some code //
if(!toggle)
{
// show
$('.bouncehide').click();
toggle = true;
thisdiv.animate({ top: 0, height:oheight+bounceheight }).animate({ top: bounceheight, height:oheight });
}
else
{
// hide
toggle = false;
thisdiv.animate({ top: 0, height:oheight+bounceheight }).animate({ top: oheight+bounceheight, height:0 });
}
});
// return original object so it can be chained
return thisdiv;
}; // END -> plugin :: bounce
... and here is how you use it:
$(function(){
$('#boinky').bounce('#toggle', 50);
$('#boinkyb').bounce('#toggleb', 50);
});
jsFiddle example:
http://jsfiddle.net/523NH/14/
hope this helps you.
Related
im creating custom toggle animation on the list of bank while onlick it will toggle down and toggle up. However my code is working but it doesn't show up like an animation form. it just close and down directly without sliding slowly. Kindly advise :
I wish to toggle down for 200 height and toggle up for 102 height
jQUERY :
$(document).ready(function(){
$(".moreBankingBtn").click(function(){
$('.bank_listSetUp').toggleClass('bank_listSetTall'); // Will add/remove class on each click
});
});
HTML :
<div name="bankDisplay2" class="bank_list_main">
<ul data-bind="foreach: thirdPayBank" class="bank_list bank_listSetUp">
<li data-bind="attr:{'data-key':key, 'data-code':bankcode}, css: memberModel.netbankCssClass($data), click: $root.netBankSelectBank" data-key="工商银行" data-code="ICBC" class="bank_2"></li>
<li data-bind="attr:{'data-key':key, 'data-code':bankcode}, css: memberModel.netbankCssClass($data), click: $root.netBankSelectBank" data-key="农业银行" data-code="ABC" class="bank_3"></li>
</ul>
</div>
CSS :
.bank_listSetUp {
height: 102px;
}
.bank_listSetTall {
height: 200px;
}
You can use JQuery UI and change your code to something like
$('.bank_listSetUp').toggleClass('bank_listSetTall',500);
Here 500 is the duration of animation.
I would also suggest you to have a look at sideToggle() function http://api.jquery.com/slidetoggle/
i found an solution for this ,
jQUERY :
$(document).ready(function(){
var open = false;
var bankListMain = $("#thirdPayForm .bank_list_main");
var ul = bankListMain.find("ul");
var button = bankListMain.find("span");
button.click(function () {
open = !open;
var height;
if (open) {
height = "200px";
button.addClass("bank_hide");
} else {
height = "102px";
button.removeClass("bank_hide");
}
TweenMax.to(ul, 0.5, { css: { height: height } });
});
});
NOTE : add tweenmax.js to make it work
try slideToggle()
$(document).ready(function(){
$(".moreBankingBtn").click(function(){
$('.bank_listSetUp').slideToggle();
});
})
It doesn't look like it's animating because you're not using the jquery animate function or the slide toggle function, although since you want to animate to two different heights you can't really use the slide functions, because I believe that's just to display and hide. Maybe try this:
$(document).ready(function(){
$(".moreBankingBtn").click(function(){
If ($('.bank_list').hasClass('bank_listSetUp')){
$('.bank_list').animate({
height: 200,
}, 'slow').promise().done(function(){
$('.bank_list').removeClass('bank_listSetUp').addClass('bank_listSetTall');
});
}
else {
$('.bank_list').animate({
height: 120,
}, 'slow').promise().done(function(){
$('.bank_list').addClass('bank_listSetUp').removeClass('bank_listSetTall');
}
});
});
Check my PLNKR, as you can see in plunker:
Menus are overflowing.
'moveLeft' and 'moveRight' button will shift menus by -/+ 1.
If you reach to first and last menu, corresponding 'moveLeft' and 'moveRight ' will be disabled.
Earlier for menucontainer class I was using overflow:hidden so menus were not oveflowing, but overflow:hidden was getting applied to child level menus also, they were cutting.
So finally I decided to remove overflow:hidden from menucontainer class.
So i thought of counting menus and making visible only required 3 menus and hiding all other. Things I am trying to achieve :
Let's assume currently 3 menus which are in middle are 444 555 666
At a time 3 menus will be visible, all others will be hidden.
clicking 'moveRight' will shift menus by +1, i.e. 555 666 777 will be visible and rest all will be hidden.
clicking on 'moveLeft' will shift menus by -1, i.e. 333 444 555 will be visible and rest all will be hidden.
Is this achievable with javascript? I am new to js any assitacne will be highly appreciate.
Note: My web page is very complex, plunker is just showing problem in simplest way.
Please dont suggest to give overflow:hidden
HTML Code
<div>
<input ng-click="myStyle={'margin-left': moveLeft()}" ng-show="menuItems > 3" ng-disabled="leftdisabled" class="left leftbtnposition" type="button" value="Move Left" />
<div class="menucontainer left">
<ul ng-style="myStyle">
<li ng-repeat="item in items"> {{item.name}}
</li>
</ul>
</div>
<input ng-click="myStyle={'margin-left': moveRight()}" ng-show="menuItems > 3" ng-disabled="rightdisabled" class="left rightbtnposition" type="button" value="Move Right" />
</div>
CSS
.menucontainer
{
width:300px;
margin-left:200px;
/* overflow:hidden;*/ not using this property now
}
.menucontainerhidden
{
width:300px;
margin-left:200px;
}
.leftbtnposition
{
position:absolute;
left:138px;
}
.rightbtnposition
{
position:absolute;
left:510px;
}
The best way I can think to do this with your current set up is to apply a class to the items that you want to be hidden based off what is currently in the selected 3 items.
I added a $scope.leftMost variable to monitor the index in $scope.items is on the left of the visible area.
Then added a boolean to each $scope.items element called isVisible.
In the html file we add an ng-class that toggles a class based on this boolean ng-class="{ hidden: !item.isVisible}"
Then based off the moveLeft and moveRight methods you have already defined we use the $scope.leftMost variable to toggle the isVisible boolean as needed.
A little CSS magic for the .hidden class thrown in as well.
.menucontainer .hidden{
opacity:0;
visibility:hidden;
}
PLUNKER
ADDITIONAL
Further to OP's comment, you can parse your returned data as it comes back into your service. For example:
.factory('MenuItems', ['$http', function ($http) {
var factory = {};
var addVisible = function(menuItems){
for(var x = 0; x < menuItems.videos.length; x++){
var menuItem = menuItems[x];
if(x < 3){
menuItem.isVisible = true;
}else{
menuItem.isVisible = false;
}
}
return menuItems;
}
factory.get = function () {
var path = '/menuItemUrl/';
return $http.get(path).then(function (resp) {
if(resp.data.length){
return addVisible(resp.data[0]);
}
});
};
return factory;
}])
Like this?
I modified the fiddle you posted in your comment(http://jsfiddle.net/j23LbLko/)
You can change the animation to whatever delay you want, it is currently set to 0.
JS
var myMargin = 112;
var numberOfVisibleItems = 3;
var numberOfItems = $('#menulist').children('li').length;
$('.left').click(function () {
if (parseInt($('#menulist').css('margin-left'), 10) >= -(myMargin * (numberOfItems - (numberOfVisibleItems + (numberOfVisibleItems - 2))))) {
$('#menulist').animate({
'marginLeft': "-=" + myMargin + "px" //moves left
}, 0, function () {
hideItems();
});
}
});
$('.right').click(function () {
if (parseInt($('#menulist').css('margin-left'), 10) >= 0) {
$('#menulist').css('margin-left', '0px!important');
} else {
$('#menulist').animate({
'marginLeft': "+=" + myMargin + "px" //moves right
}, 0, function () {
hideItems();
});
}
});
hideItems();
function hideItems() {
var currentMarginLeft = parseInt($('#menulist').css("margin-left"), 10);
var index = Math.abs(currentMarginLeft / myMargin);
$('#menulist').children('li').css("visibility", "hidden");
for (var i = 0; i < numberOfVisibleItems; i++) {
$('#menulist').children('li').eq(index + i).css("visibility", "visible");
}
}
EDIT (below)
Now just to let you know, both answers provided at the current time (my own and that of haxxxton) both have elements that are simply hidden from view. This means that when the items move left and right on the screen, your entire webpage's scrolling changes (left to right). This is because the elements still exist and are simply hidden from sight. Your best option would be to use the jsfiddle I included in my earlier comment (this one) and change the following values:
In the CSS: #outer { width:448px; } to #outer { width:336px; }
In the JS (in the left click event): if (parseInt($('#menulist').css('margin-left'), 10) >= -784) to if (parseInt($('#menulist').css('margin-left'), 10) >= -896)
JS
$('.left').click(function () {
if (parseInt($('#menulist').css('margin-left'), 10) >= -784) {
$('#menulist').animate({
'marginLeft': "-=112px" //moves left
});
}
});
$('.right').click(function () {
if (parseInt($('#menulist').css('margin-left'), 10) >= 0) {
$('#menulist').css('margin-left', '0px!important');
} else {
$('#menulist').animate({
'marginLeft': "+=112px" //moves right
});
}
});
I've found this little piece of code which fulfils my needs, but is there any way to make "target 1" be loaded defaultly? So "right" doesn't start as empty div, but with content from "target 1" already.
jQuery(function($) {
$('a.panel').click(function() {
var $target = $($(this).attr('href')),
$other = $target.siblings('.active');
if (!$target.hasClass('active')) {
$other.each(function(index, self) {
var $this = $(this);
$this.removeClass('active').animate({
left: $this.width()
}, 500);
});
$target.addClass('active').show().css({
left: -($target.width())
}).animate({
left: 0
}, 500);
}
});
});
http://jsfiddle.net/sg3s/rs2QK/
To have target1 be active be default, you need to give it an active class, and add display: block to it's style in the HTML
By not using javascript to set the target1 div to active the page doesn't need to load first before it appears in the right div. Meaning that if the page is heavy at all it won't flash white because it's waiting for the page to load.
<div class="panel active" id="target1" style="background:green; display:block;">Target 1</div>
Like this - http://jsfiddle.net/rs2QK/2291/
just a little addition
$('a[href=#target1]').click()
Demo
I have a 'sticky sidebar nav' that is positioned absolutely relative to the #sidebar div, so it follows the page down on the left hand side and is always available. To make this work I had to add a height to the sidebar, so I used some code to find the height of the container dynamically. This is the code i used:
<script type="text/javascript">
function matchColHeights(col1, col2) {
var col1Height = $(col1).height();
var col2Height = $(col2).height();
if (col1Height > col2Height) {
$(col1).height(col2Height);
} else {
$(col1).height(col2Height);
}
}
$(document).ready(function() {
matchColHeights('#sidebar', 'section#main-container');
})
</script>
Currently the #sidebar div sits inside the section called section#maincontainer. A very simplified version of the html is below.
<body>
<header>Header content</header>
<section id="main-container">
<div id="sidebar">
<ul>
This is the floated ul
<ul>
</div>
<div class="content">
This is where the content of the page sits
</div>
<div class="content2">
This is where the content of the page sits (because of the design there are often more than one divs floated right
<div>Within the content divs are potential expanding divs (accordions and tabs that change size)</div>
</div>
</section>
<footer>Footer content</footer>
</body>
So the problem I have is that there is expandable content (tabs and accordions) in the content area, and when the content expands, the jQuery does not update the height of the sidebar to the new height (this new height could be shorter or longer than the original height). I have tried adding the function to my .click() handler of the accordion (haven't yet tried with the tabs) but here is the code that is used to drop my accordion down:
<!--Content Accordion-->
<script type="text/javascript">
$(document).ready(function() {
$('div.content-accordion> div').hide();
$('div.content-accordion> h4').click(function() {
var $nextDiv = $(this).next();
var $visibleSiblings = $nextDiv.siblings('div:visible');
if ($visibleSiblings.length ) {
$visibleSiblings.slideUp('fast', function() {
$nextDiv.slideToggle('fast');
$matchColHeights('#sidebar', 'section#main-container');
});
} else {
$nextDiv.slideToggle('fast');
$matchColHeights('#sidebar', 'section#main-container');
}
});
});
</script>
As you can see I can add the $matchColHeights('#sidebar', 'section#main-container'); function into the click function and it doesn't refresh to the new height still. I have tried a few other possibilities with no luck.
Just to let everyone know i found a solution...Took alot of messing about but code is below.
I essentially on the click had to set sidebar height back to 0, and create a function that finds the new height of the section#main-container, and then applys that as a css height to the sidebar. This changed the height of the sidebar just fine, but then the sticky sidebar wasnt readjusting to the new height, so i just pasted the code that works my sticky sidebar (the code that starts with $("aside") into the function and it refreshes just fine. Thanks to those that helped.
<!--Content Accordian-->
<script type="text/javascript">
$(document).ready(function() {
$('div.content-accordian> div').hide();
$('div.content-accordian> h4').click(function() {
var $nextDiv = $(this).next();
var $visibleSiblings = $nextDiv.siblings('div:visible');
if ($visibleSiblings.length ) {
$visibleSiblings.slideUp('fast', function() {
$nextDiv.slideToggle('fast', function() {
// START CHANGE SIDEBAR HEIGHT
$("#sidebar").css({ height: 0});
newheight = $("section#main-container").height();
$("#sidebar").css({ height: newheight});
$("aside").stickySidebar({
timer: 500
, easing: "easeInOutQuint"
, constrain: true
});
});
// END CHANGE SIDEBAR HEIGHT
});
} else {
$nextDiv.slideToggle('fast', function() {
// START CHANGE SIDEBAR HEIGHT
$("#sidebar").css({ height: 0});
newheight = $("section#main-container").height();
$("#sidebar").css({ height: newheight});
$("aside").stickySidebar({
timer: 500
, easing: "easeInOutQuint"
, constrain: true
});
});
// END CHANGE SIDEBAR HEIGHT
}
});
});
</script>
I believe you could write
if (col1Height !== col2Height) {
$(col1).height(col2Height);
}
instead of
if (col1Height > col2Height) {
$(col1).height(col2Height);
} else {
$(col1).height(col2Height);
}
But that won't solve your problem.
You probably have to fire that matchColHeights() function from inside a callback like this:
if ($visibleSiblings.length ) {
$visibleSiblings.slideUp('fast', function() {
$nextDiv.slideToggle('fast', function() {
$matchColHeights('#sidebar', 'section#main-container');
});
});
} else {
$nextDiv.slideToggle('fast', function() {
$matchColHeights('#sidebar', 'section#main-container');
});
}
Let me know if it worked.
I have the following javascript that shows or hides a div when a link is clicked:
<script type="text/javascript">
$(document).ready(function(){
$('.show_hide').showHide({
speed: 500, // speed you want the toggle to happen
changeText: 0, // if you dont want the button text to change, set this to 0
showText: 'View',// the button text to show when a div is closed
hideText: 'Close' // the button text to show when a div is open
});
});
(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 () {
// this var stores which button you've clicked
var toggleClick = $(this);
// this reads the rel attribute of the button to determine which div id to toggle
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==1){
$(toggleDiv).is(":visible") ? toggleClick.text(options.hideText) : toggleClick.text(options.showText);
}
});
return false;
});
};
})(jQuery);
</script>
The problem is, I have two such divs, but I only want one to be displayed at a time. So, if someone clicks on the link to display div 2, and div 1 is already displayed, it should hide itself first before displaying div2.
Relevant HTML:
<div class="button">FAQs</div>
<div class="button">Contact</div>
<div id="faq" class="faq">FAQs here </div>
<div id="contact" class="faq">Contact form here </div>
I don't have any experience with JS/Jquery, but I tried adding this code, which didn't work:
var otherDiv;
if ($(this).attr('rel') == 'contact')
otherDiv = 'faq';
else
otherDiv = 'contact';
if ($(otherDiv).is(":visible"))
$(otherDiv).slideToggle(options.speed);
Most people use CSS classes as a place to store 'metadata'. When a div becomes visible, add a class to it like "toggledVisible" or whatever. When a new toggle is clicked, find all instances of "toggledVisible", hide them, and remove that class.
Alternatively, you always keep track of some sort of "currentlyVisible" object and toggle it.
Maybe jQuery ui accordion is an alternative?
HTML:
<div class="accordion">
<h3>FAQs</h3>
<div id="faq" class="faq">FAQs here</div>
<h3>Contact</h3>
<div id="contact" class="faq">Contact form here</div>
</div>
JS:
jQuery(document).ready(function() {
jQuery(".accordion").accordion();
});
Also see my jsfiddle.
=== UPDATE ===
JS:
jQuery(document).ready(function() {
jQuery(".accordion").accordion({
autoHeight: false
});
});
Also see my updated jsfiddle.
Try to add this row in your click() function
$('.faq').not(this).hide();
This will hide all shown divs except the one you clicked.