Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
capraruioan

Throwing Cannot read property 'getBoundingClientRect' of null even after wrapping the call

Recommended Posts

The error keeps coming from Sentry from a user using windows xp and chrome v49.0.2623, and several users using windows 10 and Edge v18.17763 browser

 

I went and looked inside the scroll plugin and found that it had a method _unwrapElement or something like this that could return null if the element didn't existed.

 

So, I made a wrapper function that would check the element with the exact same function before calling TweenLite.to()

 

Here is the code

// gsap/ScrollToPlugin.js -> _unwrapElement
var _window = _gsScope;
function TweenChecker(value){
	if (typeof(value) === "string") {
		value = TweenLite.selector(value);
	}
	if (value.length && value !== _window && value[0] && value[0].style && !value.nodeType) {
		value = value[0];
	}
	return (value === _window || (value.nodeType && value.style)) ? value : null;
}

// wrapper to check if element exists before firing this
function scrollTo(target, duration, vars){
	var elem = TweenChecker(target);
	if(elem === null)
		return false;
	if(!elem)
		return false;
	TweenLite.to(target, duration, vars);
}

 

 

I have replaced all TweenLite.to calls with scrollTo calls, this is the only place that TweenLite is being fired from.

 

The error is reported at

./node_modules/gsap/ScrollToPlugin.js in _getOffset at line 51:1

 

50: _getOffset = function(element, container) {
51:    var rect = _unwrapElement(element).getBoundingClientRect(), <------------- this one

 

 

Right now I'm lost and ran out of ideas. I do not understand why it would cause errors in edge & old chrome because those are basic DOM functions that are being used under the hood...

 

Any ideas?

Link to comment
Share on other sites

It would help if you can show us what is going so we can try to reproduce the error.

 

My first guess would be that you are using a framework like React, Vue, Angular, etc, and not properly referencing the element i.e. you are using a string to select elements instead of using refs.

 

 

  • Like 1
Link to comment
Share on other sites

27 minutes ago, OSUblake said:

It would help if can show us what is going so we can reproduce the error.

 

My first guess would be that you are using a framework like React, Vue, Angular, etc, and not properly referencing the element i.e. you are using a string to select elements instead of using refs.

 

 

 

I am using Vue and all elements are referenced with ref

 

I only have 2 calls that involves referencing elements as target (the rest are target = window).

One of them is a sidebar that never gets hidden and has

//<div class="sidebar" @mouseleave="debouncedScrollTop()" @mouseenter="debouncedScrollTop.cancel()">
//	<div class="holder" ref="scrollElement" v-perfect-scroll="{ suppressScrollX: true }" v-on:ps-scroll-y="debouncedUpdateLeftBoxPositions">
//	</div>
//</div>

export default {
  methods: {
  	scrollTop(){
  		this.$scrollTo(this.$refs.scrollElement, 0.5, { scrollTo: 0 })
	}
  },
  computed: {
    debouncedScrollTop(){
		return debounce(() => this.scrollTop(), 1000)
	}
  }
}

 

the this.$scrollTo is the wrapper in the first post. I have no v-ifs in this sidebar, the element is always there.

 

the v-perfect-scroll is a directive that applies new PerfectScrollbar(target) -> this 3rd party does not replace the element, only applies some classes and some children elements

 

the second one is a modal component that is always in the DOM of the current component. The js method is this

export default {
	methods: {
    	scrollToTop(){
        	if(!this.$refs.thumbsHolder)
              return false
          
          	this.$scrollTo(this.$refs.thumbsHolder, 0.5, { scrollTo: 0 })
        }
    }
}

 

 

In both cases: the element is always in the DOM and is called only by its parent component, so it is not called before it was rendered

 

 

 

 

My initial thought was that the modal was causing problems when the route would change and the modal would disappear in the middle of the Tween.

But I've set a tween of 10 seconds and changed the view in the middle of it and it did not cause any problems

 

 

I really don't have anything more to show you guys... I've set a wrapper that explicitly checks the target element and it exists at the moment I fire TweenLite.to. The real component is more complicated and I cannot copy/paste it here. I've tried to remove unnecessary children from the template and chunks of js to be more readable.. But other than what I already posted, there is not much more relevant stuff to see

 

I've fallen back to jQuery animate for now to see if it generates similar error

Link to comment
Share on other sites

I'm at lost here. Maybe @GreenSock can chime in and see if anything sticks out.

 

Are you able to reproduce the error yourself, or are you just going off of some logs?

 

If line 51 is causing problems, then I would inspect what this returns: 

 

_unwrapElement(element)

 

And what this returns:

 

var elem = TweenChecker(target);

 

 

Link to comment
Share on other sites

1 minute ago, OSUblake said:

I'm at lost here. Maybe @GreenSock can chime in and see if anything sticks out.

 

Are you able to reproduce the error yourself, or are you just going off of some logs?

 

If line 51 is causing problems, then I would inspect what this returns: 

 


_unwrapElement(element)

 

And what this returns:

 


var elem = TweenChecker(target);

 

 

 

TweenChecker is a copy/paste of _unwrapElement that return either the element, or null

 

I could not reproduce. I'm working only based off error reporting 

Link to comment
Share on other sites

4 hours ago, capraruioan said:

TweenChecker is a copy/paste of _unwrapElement that return either the element, or null

 

I understand that. If you can verify that it's null at the time of the error, then the problem likely has nothing to do with with GSAP itself, and is probably further upstream in your codebase.

Link to comment
Share on other sites

1 minute ago, OSUblake said:

 

I understand that. If you can verify that it's null at the time of the error, then the problem likely has nothing to do with with GSAP itself, and is probably further upstream in your codebase.

 

oh, right.. I will check and will come back with results tomorrow most likely, but I highly doubt it because I've tried to set a 10seconds Tween and to delete the element in the middle of it and there was no error.. The last thing remains if the element is deleted somehow between TweenLite.to() and the _unwrapElement but I don't see how

Link to comment
Share on other sites

2 minutes ago, capraruioan said:

The last thing remains if the element is deleted somehow between TweenLite.to() and the _unwrapElement but I don't see how

 

Yeah, I don't see how anything could happen in there. Where something could go wrong is the time in between a debounced call.

Link to comment
Share on other sites

3 minutes ago, OSUblake said:

 

Yeah, I don't see how anything could happen in there. Where something could go wrong is the time in between a debounced call.

 

by debounce you mean a call that is placed inside a setTimeout, right? the only debounced call like this is in the sidebar, but that element is never deleted or hidden from the page

Link to comment
Share on other sites

12 minutes ago, capraruioan said:

by debounce you mean a call that is placed inside a setTimeout, right?

 

No, but are you using a setTimeout? That can cause problems with animations as it's not tied to the UI. If someone changes tab, the setTimeout will fire, but the animation might not.

 

But this piece of code is what I meant by doing debounced calls.

 

computed: {
  debouncedScrollTop(){
	return debounce(() => this.scrollTop(), 1000)
  }
}

 

Link to comment
Share on other sites

Just now, OSUblake said:

 

No, but are you using a setTimeout? That can cause problems with animations as it's not tied to the UI. If someone changes tab, the setTimeout will fire, but the animation might not.

 

But this piece of code is what I meant by doing debounced calls.

 


computed: {
  debouncedScrollTop(){
	return debounce(() => this.scrollTop(), 1000)
  }
}

 

 

yes, that one uses setTimeout behind the scenes, also that code is in the sidebar i was talking about

Link to comment
Share on other sites

Yeah, nothing is really sticking out to me, other than perhaps the element is getting removed from the DOM mid-tween and those browsers are choking on the getBoundingClientRect() call. Have you tried calling TweenLite.killTweensOf(yourElement) on unmount (or whenever it might be getting deleted)? I don't think anyone else has reported any issues like this, so it seems like a bit of an edge case that's super tough to diagnose blind :(

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×