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
});
}
});
Related
Hello I customized a Bootstrap navbar with 2 rows (the upper part is just logo and social links and the down part are navigation links). I am trying to hide the upper part when scrolling but I can't find a way to do it smoothly. I think the code below is the best solution I found, but for now the eventlistener on transitionend doesn't work and the class 'hidden' is never added.
var scrollpos = window.scrollY;
var header = document.getElementById("header-up-section");
function add_class_on_scroll() {
header.classList.add('visuallyhidden');
header.addEventListener('transitionend', function(e) {
header.classList.add('hidden');
}, {
capture: false,
once: true,
passive: false
});
}
function remove_class_on_scroll() {
header.classList.remove('hidden');
setTimeout(function () {
header.classList.remove('visuallyhidden');
}, 20);
}
window.addEventListener('scroll', function(){
scrollpos = window.scrollY;
if(scrollpos > 20){
add_class_on_scroll();
}
else {
remove_class_on_scroll();
}
console.log(scrollpos);
});
*/and CSS :
#header-up-section.visuallyhidden {
opacity: 0;
}
#header-up-section.hidden {
display: none !important;
}
The header-up-section turns invisible but the div is not hidden. Any idea to help?
Finally no need for JS to do this. Just need 2 bootstrap navbars and add to the second one (which is a pseudo 'down part' of a two rows navbar) the bootstrap class 'sticky-top'. It does the job perfectly ;)
I need to fake a toggle switch with an input range.
The idea is to create a short range, with just 2 values, min and max. the css button will match one end of the range. So far you click on it, the div containing the range will move a bit bringing the other end of the ranger under your mouse.
I have this function, which applies on all input ranges on the page. But i need to apply it only on some classes, not all. But i can't find the right syntax and it doesn't work.
The Javascript:
$('input[type="range"]').on('change', function() {
$('div#launcher01').css('margin-top', parseInt($(this).val() ) > 0 ? parseInt($(this).val() ) + 'px' : '0px');
});
CSS:
.fakbl input {
height: 50px;
width: 50px;
HTML:
<div id="launcher01">
<div class="fakbl">
<input type="range" id="launch01" name="launch01" min="0" max="50" step="50"" />
</div>
</div>
Fiddle
Since you are already using jQuery, you can phrase your widget-maker as a jQuery plugin as follows :
$.fn.rangeButton = function(containerSelector) {
return this.each(function() {
var $self = $(this);
$self.on('change', function() {
$self.closest(containerSelector).css('margin-left', ($self.val()/3) > 0 ? ($self.val()/3) + 'px' : '0px');
}).trigger('change'); // trigger 'change' immediately to initialize everything.
});
};
Now, invoke the widget on each of your ranges, and pass a selector for the appropriate container :
$('#launcher01 input[type="range"]').rangeButton('#launcher01');
$('#launcher02 input[type="range"]').rangeButton('#launcher02');
Demo
Alternatively, by giving all containers the same class, you can invoke all your widgets with a single command :
$('.myClass input[type="range"]').rangeButton('.myClass');
Demo
May I ask a refinement please?
I completed the fake button. As you can see in this FIDDLE
(the white box will disappear, I added some opacity to it just to show that the button is working)
The red box (now green due to my buggy code part) is in the background and I would need it to change color depending on the status. I tried this but it doesn't work.
Here the code:
$.fn.rangeButton = function(containerSelector) {
return this.each(function() {
var $self = $(this);
$self.on('change', function() {
$self.closest(containerSelector).css('margin-left', ($self.val()/3) > 0 ? ($self.val()/3) + 'px' : '0px');
// this part is not working, if you remove this part, the button works flawlessy
if ($self = 100) {
document.getElementById("fakbuttonsfondo01").style.backgroundColor="rgb(0, 191, 1)";
} else {
document.getElementById("fakbuttonsfondo01").style.backgroundColor="rgb(0, 0, 255)";
}
// end of buggy code
}).trigger('change'); // trigger 'change' immediately to initialize everything.
});
};
$('#launcher01 input[type="range"]').rangeButton('#launcher01');
$('#launcher02 input[type="range"]').rangeButton('#launcher02');
Thanks:)
Im creating a fixed header where on load, the logo is flat white. On scroll, it changes to the full color logo.
However, when scrolling back to the top, it stays the same colored logo instead of going back to white.
Here's the code (and a pen)
$(function() {
$(window).scroll(function() {
var navlogo = $('.nav-logo-before');
var scroll = $(window).scrollTop();
if (scroll >= 1) {
navlogo.removeClass('.nav-logo-before').addClass('nav-logo-after');
} else {
navlogo.removeClass('.nav-logo-after').addClass('nav-logo-before');
}
});
});
http://codepen.io/bradpaulp/pen/gmXOjG
There's a couple of things here:
1) You start with a .nav-logo-before class but when the logo becomes black you remove that class and then try to get the same element using a class selector that doesn't exist anymore
2) removeClass('.nav-logo-before') is different than removeClass('nev-logo-before), notice the "." in the first selector.
3) You get the element using the $('.selector')in every scroll event, this can be a performance issue, it's better to cache them on page load and then use the element stored in memory
4) It's not a good practice to listen to scroll events as this can be too performance demanding, it's usually better to use the requestAnimationFrame and then check if the scroll position has changed. Using the scroll event it could happen that you scroll up really fast and the scroll event doesn't happen at 0, so your logo won't change. With requestAnimationFrame this can't happen
$(function() {
var navlogo = $('.nav-logo');
var $window = $(window);
var oldScroll = 0;
function loop() {
var scroll = $window.scrollTop();
if (oldScroll != scroll) {
oldScroll = scroll;
if (scroll >= 1) {
navlogo.removeClass('nav-logo-before').addClass('nav-logo-after');
} else {
navlogo.removeClass('nav-logo-after').addClass('nav-logo-before');
}
}
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
});
body {
background-color: rgba(0,0,0,.2);
}
.space {
padding: 300px;
}
.nav-logo-before {
content: url(https://image.ibb.co/kYANyv/logo_test_before.png)
}
.nav-logo-after {
content: url(https://image.ibb.co/jYzFJv/logo_test_after.png)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<img class="nav-logo nav-logo-before">
</div>
<div class="space">
</div>
Dont need to add the dot . in front of the class name in removeClass and addClass:
Use this:
navlogo.removeClass('nav-logo-before')
Secondly, you are removing the class that you are using to get the element in the first place.
I have an updated codepen, see if this suits your needs: http://codepen.io/anon/pen/ZeaYRO
You are removing the class nav-logo-before, so the second time the function runs, it can't find any element with nav-logo-before.
Just give a second class to your navlogo element and use that on line 3.
Like this:
var navlogo = $('.second-class');
working example:
http://codepen.io/anon/pen/ryYajx
You are getting the navlogo variable using
var navlogo = $('.nav-logo-before');
but then you change the class to be 'nav-logo-after', so next time the function gets called you won't be able to select the logo using jquery as it won't have the '.nav-logo-before'class anymore.
You could add an id to the logo and use that to select it, for example.
Apart from that, removeClass('.nav-logo-before') should be removeClass('nav-logo-before') without the dot before the class name.
The problem is that you removes nav-logo-before and then you want to select element with such class but it doesn't exist.
I've rafactored you code to avert it.
Another problem is that you uses dot in removeClass('.before') while it should be removeClass('before') - without dot
$(function() {
var navlogo = $('.nav-logo');
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 1) {
navlogo.removeClass('before').addClass('after');
} else {
navlogo.removeClass('after').addClass('before');
}
});
});
body {
background-color: rgba(0,0,0,.2);
}
.space {
padding: 300px;
}
.before {
content: url(https://image.ibb.co/kYANyv/logo_test_before.png)
}
.after {
content: url(https://image.ibb.co/jYzFJv/logo_test_after.png)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<img class="nav-logo before">
</div>
<div class="space">
</div>
I have ember app.In which I have icon in navbar which when clicked show a dropdown with notification.I have set the max-height of dropdown as 390px.Now I want to determine when the user has reached the bottom to the dropdown so that I can make an ajax call to the server for more data.
html
<div class="ps-content">
.....notification content.....
</div>
css
.ps-container{
max-height: 390px;
position: relative;
}
js
didInsertElement: function(){
$('.ps-content').on('scroll', $.proxy(this.didScroll, this));
},
willDestroyElement: function(){
$('.ps-content').off('scroll', $.proxy(this.didScroll, this));
},
didScroll: function(){
if (this.isScrolledToBottom()) {
this.sendAction('loadMore');
}
},
// we check if we are at the bottom of the page
isScrolledToBottom: function(){
var distanceToViewportTop = WHAT SHOULD I AM DO HERE ?
var viewPortTop = $('.ps-content').scrollTop();
if (viewPortTop === 0) {
return false;
}
return (viewPortTop - distanceToViewportTop === 0);
},
when I do $('.ps-content').height it is giving 390px.How to get the whole content height render into the dropdown ?
In the "viewPortTop" I am getting how much user has scrolled.But I am not able to figure out what should I do "distanceToViewportTop" So that When user reaches at bottom there difference is zero.I can't use documnet height and window height as it takes the whole page height.For Whole page it is documnet - window height to get the bottom page.What should I do for div ?
There are some properties/methods you can use:
$().scrollTop()//how much has been scrolled
$().innerHeight()// inner height of the element
DOMElement.scrollHeight//
height of the content of the element
So you can take the sum of the first two properties, and when it equals to the last property, you've reached the end:
jQuery(function($) {
$('#flux').on('scroll', function() {
if($(this).scrollTop() + $(this).innerHeight() >= $(this) [0].scrollHeight) {
alert('end reached');
}
})
});
http://jsfiddle.net/doktormolle/w7X9N/
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.