Frontline Skirmishes, Part 5: ResizeObserver


Today I’d like to describe the solution to a problem I encountered a few months ago: the occasional faulty appearance of Angular in the browser.

At the top, the platform displays a tab bar with buttons, the number and width of which vary depending on the context. The data used to generate this menu are downloaded asynchronously while the page is loading. If the total width of the bar is greater than the width of the window, the bar will break into two tab bars, one below the other. Underneath, however, is the content of the current tab, which, in turn, requires information about the available height to be displayed properly. So this height must be calculated each time the browser window height or the height occupied by the tab bar changes. Previously, the height for the main tab was computed in ngOnInit, with the problem being that usually at this point the tab bar had not yet been fully generated. Sometimes its height changed a fraction of a second later, wreaking havoc in the browser.

The simplest solution to this type of error seems to be delaying the calculation of height with SetTimeout. However, the disadvantages of this approach outweigh its advantages. First of all, the extent of the delay must be chosen, which can be done by trial and error, but there would be no certainty whether the value selected this way would actually work in all conditions. So it is safer to keep checking the height of the tab bar until a satisfactory result is obtained, while applying constant or increasing intervals, although this pollutes the application with an additional loop in the code. Fortunately, there is a much sleeker solution.

ResizeObserver, as the name suggests, monitors the size of the selected html element and generates an event when a change is noticed. All you need to do is connect it to the tab bar and calculate the tab height using an event-triggered method rather than ngOnInit.

A good way to monitor and respond appropriately to any size change is to use ResizeObserver as shown in the example below, in the form of a directive:

The created directive is responsible for connecting ResizeObserver, emitting an event when the size changes, and correctly disconnecting ResizeObserver when the component is closed.

To ensure compatibility with older browsers (IE), it is advisable to use a polyfill which employs another interesting invention, MutationObserver, for monitoring changes in html elements in all popular browsers.

The described directive allows connection of ResizeObserver to any html element in a very simple way, such as below:

Then, all that remains to be done is to define the method which is to process the event, for example:

If you want to make changes to the graphical user interface (GUI) in response to the ResizeObserver object generated, use the ngZone.run() method to let Angular notice the change. The standard cycle of detecting changes in Angular does not include tracking of ResizeObserver events.

The object passed in the event generated by ResizeObserver has properties which describe the coordinates and dimensions of the observed element, grouped in a contentRect subobject.

Source code, npm

The source code and instructions for installation of a library with the above directive can be found here:

https://github.com/piotr-zysk/LabIntersectionObserver/tree/master/projects/pz-resize-observer


Piotr Zyśk

About Piotr Zyśk

Fullstack .Net/Angular developer in Atena since 2019. Previous 16 years spent on IT support for large contact center company, including development and maintenance of local infrastructure. After work I like to spend time on my hobbies, like photography, composing music on my PC or playing virtual racing games. You can also meet me biking in the nearby forests.

Leave a comment

Your email address will not be published. Required fields are marked *