getBoundingClientRect in each: undefined is not a function - javascript

So I am trying to call some functions when fullscreen sections are in the viewport. Let's say I have 7 sections, then I want something to happen when a certain section is inside the viewport (I have a function that snaps the sections into the viewport so there can never be multiple sections in the viewport, but I am trying to find out which section is visible in the viewport).
Here is a fiddle: http://jsfiddle.net/h7Hb7/2/
function isInViewport() {
$("section").each(function () {
var $this = $(this),
wHeight = $(window).height(),
rect = $this.getBoundingClientRect(); // Error in console
// Borrowed from http://stackoverflow.com/a/7557433/5628
if (rect.top >= 0 && rect.bottom <= wHeight) {
console.log($this.attr("id") + "in viewport");
}
});
}
$(window).scroll(function () {
// Other functions are called inside the setTimeout function, can't remove
clearTimeout($.data(this, "scrollTimer"));
$.data(this, "scrollTimer", setTimeout(function () {
isInViewport();
}, 1200));
});
I don't know where to start looking but I am guessing it's to do with the each function. Is it the each function that poses a problem? It can't be a CSS issue, because the problem occurs on scroll when the CSS has already loaded.

You could stick with jQuery and use the array [] notation ie:
var myClient = $(currentGrid)[0].getBoundingClientRect();
alert(myClient.top)

jQuery object doesn't have getBoundingClientRect method, you should get the HTMLElement object and then call the method or:
this.getBoundingClientRect();
As a suggestion, if using a plugin is an option, you can consider using the jquery.inview plugin.

You can pass event through function and use
e.target.getBoundingClientRect() function. It will Work

Related

can't change z index with javascript

I'm trying to change the Z index of an image according to the scroll position,currently in chrome (but it should be working on all broswers).
anyway, it's not working on chrome, unless I get into inspection mode and I don't understand why it's only working in inspection mode?
this is the script:
$( window ).scroll(function() {
var scrollTop = $(window).scrollTop();
if ($(this).scrollTop()>700) {
document.getElementById("back-ground-image").style.zIndex = "-9";
console.log("-9");
} else {
document.getElementById("back-ground-image").style.zIndex = "-19";
console.log("-19");
}
});
Problem
What you need is $(document) not $(window).
By default, you scroll the $(document), not the $(window).
However, when you open your Chrome DevTools, the $(window) is not being scrolled which is why your code works.
To fix the issue, change $(window).scroll() to $(document).scroll() and $(window).scrollTop() to $(document).scrollTop()
Improvements
1. Use jQuery functions
Also, if you're already using jQuery, why not use jQuery selectors and .css():
$("#back-ground-image").css('zIndex', '-9')
instead of
document.getElementById("back-ground-image").style.zIndex = "-9";
2. Use DRY code
(Don't Repeat Yourself)
If you follow recommendation #1, why not set $("#back-ground-image") to a variable instead of repeating it twice.
$(document).scroll(function() {
var scrollTop = $(document).scrollTop(),
$bkImg = $("#back-ground-image");
if ($(this).scrollTop() > 700) {
$bkImg.css('zIndex', '-9');
console.log("-9");
} else {
$bkImg.css('zIndex', '-19');
console.log("-19");
}
});
Otherwise, you could use:
$(document).scroll(function() {
var scrollTop = $(document).scrollTop(),
background = document.getElementById("back-ground-image");
if ($(this).scrollTop()>700) {
background.style.zIndex = "-9";
console.log("-9");
} else {
background.style.zIndex = "-19";
console.log("-19");
}
});

Run function() if appear in viewport ? jquery-viewport-checker

I use anime-js for create an animation. But, It is far in the page. I would like to launch my animation function when the section in which the item to be animated appears on the screen.
I tried a plugin that I like to use (jquery viewportchecker) but it does not seem to do that.
Can you help me ?
Thank you
I found a solution. The problem with your method is that the function repeats itself to infinity.
I create a little function for check if element is visible. With that, no plugin needed.
function checkVisible( elm, evale ) {
var evale;
evale = evale || "object visible";
var viewportHeight = $(window).height(), // Viewport Height
scrolltop = $(window).scrollTop(), // Scroll Top
y = $(elm).offset().top,
elementHeight = $(elm).height();
if (evale == "object visible") return ((y < (viewportHeight + scrolltop)) && (y > (scrolltop - elementHeight)));
if (evale == "above") return ((y < (viewportHeight + scrolltop)));
}
I also created a variable var counter = 0;. And as soon as the function is called, I increment by 1.
$(window).on('scroll',function() {
if (counter == 0){
if (checkVisible($('.frontend'))) {
// Your function here
}
}
}
At the first time the function will be called, counter will be 1, and thus, the function will not repeat. Thank you for your help !
jQuery.appear
This plugin implements custom appear/disappear events which are fired when an element became visible/invisible in the browser viewport.
https://github.com/morr/jquery.appear
$('someselector').on('appear', function(event, $all_appeared_elements) {
// this element is now inside browser viewport
});
$('someselector').on('disappear', function(event, $all_disappeared_elements) {
// this element is now outside browser viewport
});
Also this plugin provides custom jQuery filter for manual checking element appearance.
$('someselector').is(':appeared')
Have you tried using JQuery's on load method?
Something like
$(document).on('load', '.exampleClass', function() { //do stuff } )

Creating a HTML/JS "plugin" in ES6 - how to refresh DOM nodes

I am currently in the process of learning ES6. I'm trying to create a carousel which I would usually have written as a JQuery plugin but now instead writing it as an ES6 module so that it can be added to a page's JS using the import keyword.
As the carousel has slides which are absolutely positioned on top of each other, a calculation is done within the JS to determine the tallest carousel slide height and then apply this height to the carousel's UL element.
The module grabs several elements from the DOM within the constructor such as the containing DIV of all carousel elements, the UL of the carousel slides, etc.
class Carousel {
// set up instance variables
constructor (options) {
this.element = options.element;
this.carousel = options.element.querySelectorAll('ul');
this.carouselSlides = this.carousel[0].children;
this.carouselHeight = 0;
}
resize () {
console.log(this.carouselSlides);
//Get tallest slide
Array.prototype.map.call( this.carouselSlides, ( slide ) => {
this.carouselHeight = (slide.offsetHeight > this.carouselHeight) ? slide.offsetHeight : this.carouselHeight;
});
//Set the height of the carousel to the height of its tallest slide
this.carousel[0].style.height = this.carouselHeight+'px';
}
// initial set up
setup () {
this.resize();
window.onresize = this.resize;
}
}
module.exports = Carousel;
As this height will need to be adjusted as the browser width gets smaller I have tried to call the function which does this calculation on window.onresize.
However this does not work. I believe it is because the dom nodes that were assigned to variables in the constructor are cached at their current widths and heights and so the resize function does not use their new values in its calculation.
How can I adjust my code to prevent this caching issue?
Below is a simplified Codepen of my code so far. (I had to add the Carousel module code in with the main script just for Codepen):
http://codepen.io/decodedcreative/pen/vXzGpE/
Thanks
You're problem is related to the context of this. When you assign the callback to the window.resize event, the this is changed to the window:
window.onresize = this.resize;
When the callback is called, this.carouselSlides is undefined because the window doesn't have this property (look at the console to see the errors).
To prevent this problem, bind the callback to the original this (the class instance):
window.onresize = this.resize.bind(this);
You can see it in this codepen.
It turns out there were a couple of issues with my code. Thanks to Ori Drori's help I got to the bottom of them. Here is the fixed code:
class Carousel {
// set up instance variables
constructor (options) {
this.element = options.element;
this.carousel = options.element.querySelectorAll('ul');
this.carouselSlides = this.carousel[0].children;
this.carouselHeight = 0;
}
resize () {
//Get tallest slide
Array.prototype.map.call( this.carouselSlides, ( slide ) => {
this.carouselHeight = (slide.offsetHeight > this.carouselHeight) ? slide.offsetHeight : this.carouselHeight;
});
//Set the height of the carousel to the height of its tallest slide
this.carousel[0].style.height = this.carouselHeight+'px';
//Reset the height of the carousel to zero
this.carouselHeight = 0;
}
// initial set up
setup () {
this.resize();
window.addEventListener("resize", this.resize.bind(this));
}
}
Hopefully this helps someone!

scroll anchor show/hide

was working on a anchor point that triggers a divs visibility. There's no problems if I run it with Jquery 1.3.2 library but when I try with 1.7.1 it's not recognized. any ideas?
$(function() {
var a = function() {
var windowtop = $(window).scrollTop();
var d = $("#anchor").offset({scroll:false}).top;
var c= $("#flyout");
if (windowtop > d) {
c.css({visibility:"visible"});
} else {
if (windowtop <= d) {
c.css({visibility:"hidden"});
}
}
};
$(window).scroll(a);a()
});
});
d seems to always return undefined.
I suspect your code breaks because of the {scroll:false} object your are passing as an argument to offset(). Removing it might solve your problem.
Check the jQuery().offset() API;
jQuery(elem).offset()returns an object containing the element's top and left coordinates. Can be used as jQuery(elem).offset().top;.
jQuery(elem).offset({top:20, left:20}); sets the new top and left coordinates for the element.

how to get the final size of the element in javascript based animation

In our page,we often use the javascript based animation to make the element move/resize,most of them use the setTimeout or setInterval to change the position or size of the element:
For example:
function open() {
var w=parseInt(foo.style.width);
if(w>=200) clearTimeout(t);
else{
foo.style.width = +1+'px';
t=setTimeout(open,20); // call doMove in 20msec
}
}
function init() {
foo = document.getElementById('dv'); // get the "foo" object
foo.style.width = '0px'; // set its initial position to 0px
open(); // start animating
}
The above code want to show the div#foo slowly,but as you see,I set the maxwidth of the div to 200px to stop the animation.
But how about if the real size of the content div should more than 200?
That's to say I can not get the final width of the element.
What is the general solution?
Here is the live exmple:
Use the modified code as shown below. It will continue expanding until the element has reached its full width.
function open() { //See comment at OP
var w = foo.offsetWidht; // offsetWidht NOT style.width
var realWidth = foo.scrollWidth;
if(w < 200 || w < realWidth) {
foo.style.width = +1+'px';
setTimeout(open, 20); // call doMove in 20msec
}
}
Also, you don't need clearTimeout, since no timeout has been set when the function is called again.
Use one of the various methods of computing styles. Google "JavaScript compute width" and there will be lots of results. Try the property offsetWidth first. I can't quite remember its compatibility table but it definitely works in Chrome, Safari, and IE8/9.

Categories