Heyyy Marco
Heyyy Marco

Reputation: 763

Javascript ResizeObserver is triggered unexpected

Why the ResizeObserver class always execute the handler at the first observe()?

Try execute the code below on Chrome' dev tool:

(new ResizeObserver(() => console.log('resize detected'))).observe($0)

You will see the log printed immediately after you apply it, even if you didn't do any size change.

I need the resize observer that only executes the handler on resize.
Is there any hack/options to tweak it?

let disableObserver = false;

const obs = new ResizeObserver(() => {
   if (!disableObserver) {
      console.log('resize detected');
   }
});

// the hack below doesn't work:
disableObserver = true;
obs.observe(someElement);
disableObserver = false;

Upvotes: 6

Views: 5134

Answers (2)

Balconsky
Balconsky

Reputation: 2244

I wrote Wrapper for build-in ResizeObserver which reacts only on sizeChanging and ignores hiding and displaying.

    class ResizeObserverWrapper {

    _lastWidth;
    _lastHeight;

    observe(htmlElement, onSizeChanged) {

        new ResizeObserver(entries => {
            if (entries != undefined && entries.length > 0) {
                const newWidth = entries[0].target.clientWidth;
                const newHeight = entries[0].target.clientHeight;


                if (newWidth != undefined && newWidth > 0
                    && newHeight != undefined && newHeight > 0
                ) {
                    let dimensionChanged = newWidth != this._lastWidth && this._lastWidth > 0
                        || newHeight != this._lastHeight  && this._lastHeight > 0 ;
                    this._lastHeight = newHeight;
                    this._lastWidth = newWidth;
                    if (dimensionChanged) {
                        onSizeChanged();
                    }
                }
            }
        }).observe(htmlElement);
    }
}

usage example:

new ResizeObserverWrapper().observe(yourRootElement.querySelector('.some-css-class'), () => console.log("It is resized"));

Upvotes: 1

Vitalii
Vitalii

Reputation: 2141

Tested in different browsers and the reported behaviour is consistent - observer callback is called when observer() is called.

I've checked the specification, it says:

  • Observation will fire when watched Element is inserted/removed from DOM.
  • Observation will fire when watched Element display gets set to none.
  • Observations do not fire for non-replaced inline Elements.
  • Observations will not be triggered by CSS transforms.
  • Observation will fire when observation starts if Element is being rendered, and Element’s size is not 0,0.

I guess initial call is because of Element being rendered.

Each element can be added to a Set to skip initial call. Something like this:

let entriesSeen = new Set(); // set of entries to skip initial resize call

const obs = new ResizeObserver((entries) => {
    for (let entry of entries) {
        if (!entriesSeen.has(entry.target)) {
            // do nothing during initial call
            // just mark element as seen
            entriesSeen.add(entry.target);
        } else {
            console.log('resize detected');
            console.log(entry.target);
        }
    }
});

obs.observe(someElement);

Upvotes: 7

Related Questions