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/
Related
I have a custom icon element that is only displayed when its specific row in the table is hovered over, but when I scroll down without moving my mouse it doesn't update the hover and maintains the button on the screen and over my table's header. How can I make sure this doesn't happen?
export const StyleTr = styled.tr`
z-index: ${({ theme }) => theme.zIndex.userMenu};
&:hover {
background-color: ${({ theme, isData }) =>
isData ? theme.colors.primary.lighter : theme.colors.white};
div {
visibility: visible;
}
svg[icon] {
display: initial;
}
}
`;
I was just working on something similar to this for a web scraper recently.
Something like this should work:
function checkIfIconInViewport() {
// define current viewport (maximum browser compatability use both calls)
const viewportHeight =
window.innerHeight || document.documentElement.clientHeight;
//Get our Icon
let icon = document.getElementById('icon');
let iPos = icon.getBoundingClientRect();
//Show if any part of icon is visible:
if (viewportHeight - iPos.top > 0 && iPos.bottom > 0) {
icon.style.visibility = visibile;
}
else { icon.style.visibility = hidden; }
//Show only if all of icon is visible:
if (iPos.bottom > 0 && iPos.top >= 0) {
{
icon.style.visibility = visibile;
}
else { icon.style.visibility = hidden; }
//Add && iPos.bottom <= viewportHeight to the if check above for very large elements.
{
//Run function everytime that the window is scrolled.
document.addEventListener('scroll', checkIfIconInViewport);
Basically, every time a scroll event happens, we just check to see if the top & bottom of our element (the icon in your case) are within the bounds of the viewport.
Negative values, or values greater than the viewport's height mean that the respective portion of the element is outside the viewport's boundary.
Hopefully this helps! If you are dealing with a large quantity of objects, it may make sense to bundle the objects you are tracking together into an array and check each of them in a single function call to avoid saving function definitions for each individual object.
Edit: I just realized that I misunderstood your issue a bit. I think you can get by with just the bottom part of the code, and when a scroll event happens, set the icon's visibility to hidden. Assuming you want to hide it whenever the user scrolls?
Have you tried getting the scroll position of the DOM, then disabling (removing) the element once a certain scroll position is reached?
I have a <div> with overflow: scroll; applied, that I want to detect when it's being scrolled, and trigger just as it hits 5% of it's total height remaining.
JSBin - Currently I'm failing to trigger when it hits the bottom of the page.
<div style="height:50%;overflow:scroll;">
<b style="height:5000px;display:block;"></b>
</div>
$('div').on('scroll', function(){
if($(window).scrollTop() + $('div').height() == $('div').height()) {
console.log("bottom of page");
}
});
The window is not scrollable in your example, the div is. This results in the div being the element to look for when checking the scrollTop() function. Also, the summation here is greater than your b element (which you need to check for) and not equal. So changing the lines as follows the code executes as you've expected:
$('div').on('scroll', function(){
if($("div").scrollTop() + $('div').height() > $('b').height()) {
console.log("bottom of page");
}
});
In the fiddle you will see at the center of the page a DIV that contains text next to an img.
When I scroll down/up I need to effect with jquery/javascript only the div who's the closest to the navbar-below. all the divs as the same class so I effect them all-not what I need
For example:
what I am trying to achieve : when I scroll down,the closest div to the navbar(yellow bar) will be painted(the div) green,so if I scroll down and the navbar "collapse" with the div with will paint in green, and when he passes him and "disapper" it will go back to original color and the next div will paint in green. is it possible?
Here's the JS FIDDLE
When I referred to div I meant this section :
<div class="x" id="inside_center">
<div class="left_side" id="left_inside_center">sddsadasasdsadLorem </div>
<div class="right_side" id="right_inside_center"><img src="http://img-9gag-lol.9cache.com/photo/a7KwPAr_460s.jpg"></div>
</div>
EDIT:
UPDATED JSFIDDLE :
http://jsfiddle.net/nnkekjsy/3/
I added my jquery,as you can see it works only for the first one,and then stuck.. i need to "pass" it along the others div below him when the are getting to the same point. any ideas? :
$(document).ready(function() {
$(window).scroll(function() {
var scrollVal = $(this).scrollTop();
var navHeight = $("#div_menu").outerHeight();
if ( scrollVal > 55) {
$('#left_inside_center').css({'position':'fixed','top' :navHeight+'px'});
} else {
$('#left_inside_center').css({'position':'static','top':'auto'});
}
});
});
Have you tried use the first-of-type to select the top div, if i understand what your trying to do.
CSS3 selector :first-of-type with class name?
An other solution would be to check the position of the div and the nav bar and pick the closest one.
$(".left_side").each(function () {
//compare scroll with div
if(window.scrollTop() = $(this).position.top())
{
//do something
}
});
I know the position and the scroll won't be the same value but you can play with the condition to put some range.
Edit :
I think this is what you want. The navHeight and the height variable should be outside the window.scroll function as they never change :
$(window).scroll(function() {
var scrollVal = $(this).scrollTop();
var navHeight = $("#div_menu").outerHeight();
var height = parseInt($(".right_side").css("height").split("px")[0]);
$(".left_side").css({'position':'static','top':'auto'});
$(".left_side").filter(function( ) {
return $(this).position().top - 10 < scrollVal && $(this).position().top + height > scrollVal;
}).css({'position':'fixed','top' :navHeight+'px'});
});
Working fiddle :
http://jsfiddle.net/nnkekjsy/6/
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 need to know when my content overflows my div. If it does, I'll be placing in a link to open the page in a new window with all of the content.
Cheers,
DalexL
Using jQuery and Marquee Text When Text Overflows:
$('div').each(function(){
var $this = $(this);
if ($this.get(0).scrollHeight > $this.height()) {
$this.after('Read More');
}
});
http://jsfiddle.net/eF7jf/
none jQuery answer:
if( elements.scrollHeight > element.clientHeight )
alert('content-overflow')//not to be confused with stackoverflow
If you create a structure like this:
<div id="outer" style="overflow: auto">
<div id="inner">
content
</div>
</div>
then overflow happens when inner's width or height exceeds that of outer since outer assumes the dimensions of the viewport and inner assumes a minimal width and height necessary to display all of content.
You can mark outer as visibility: hidden to cause it to layout but not display.
If content includes position: fixed content then that portion will not be taken into account (and on CSS 2 will not even be clipped).
this a jquery plugin for fit text to width and height:
(function($) {
$.fn.fitText = function(options) {
options = $.extend({
width: 0,
height: 0
}, options);
$(this).each(function() {
var elem = $(this);
if (options.height > 0) {
while (elem.height() > options.height) {
elem.text(elem.text().substring(0, (elem.text().length - 4)) + 'YourLink');
}
}
if (options.width > 0) {
while (elem.width() > options.width) {
elem.text(elem.text().substring(0, (elem.text().length - 4)) + 'YourLink');
}
}
});
}
})(jQuery);