Angular Component Dynamic Resizing
Learning to work within Angular framework, I had to figure out how to get my content onscreen at the location and size I wanted. (Close enough, at least.) But that's just the start. What happens when the user resizes the window? That opens a separate can of worms. In my RGB332 color picker web app, the color picker is the only thing onscreen. This global scope meant I could listen to Window resize event, but listening to window-level event isn't necessarily going to work for solving a local element-level problem.
So how does an Angular component listen to an event? I found several approaches.
-
Renderer has a
listen()
method for attaching event listeners, with some examples listed on this StackOverflow thread titled Dynamically add event listener. These guys were talking about Angular 4, which is quite some time ago. -
EventManager has an
addEventListener()
method. Target for this method is typed to beHTMLElement
, more specific than Renderer'sany
.
It's not clear what tradeoffs are involved using Renderer versus EventManager. In both cases, we can listen to events on an object that's not necessarily our component. Perhaps some elements are valid for one API versus another? Perhaps there's a prioritization I need to worry about? If I only care about listening to events that apply to my own specific component, things can be slightly easier:
- @HostListener decorator allows us to attach a component method as the listener callback to an event on a component's host object. It's not as limited as it appears at first glance, as events like "window:resize" apparently propagates through the tree so our handler will fire even though it's not on the Window object.
In all of the above cases, we're listening on a global event (window.resize) to solve a local problem (react to my element's change in size.) I was glad to see that web standards evolved to give us a local tool for solving this local problem:
- ResizeObserver is not something supported by core Angular infrastructure. I could write the code to interact with it myself, but someone has written an Angular module for ResizeObserver. This is part of a larger "Web APIs for Angular" project with several other modules with similar goals: give an "Angular-y" way to leverage standardized APIs.
I tried this new shiny first, but my callback function didn't fire when I resized the window. I'm not sure if the problem was the API, the Angular module, my usage of it, or that my scenario not lining up with the intended use case. With so many unknowns, I backed off for now. Maybe I'll revisit this later.
Falling back to @HostListener, I could react to "window.resize" and that callback did fire when I resized the window. However, clientWidth/clientHeight
size information is unreliable and my Three.js object is not the right size to fill its parent <DIV>. I deduced that when "window:resize" fired, we have yet to run through full page layout.
With that setback, I fell back to an even cruder method: upon every call to my animation frame callback, I check the <DIV> clientWidth/clientHeight
and resize my Three.js renderer if it's different from existing values. This feels inelegant but it'll have to do until I have a better understanding of how ResizeObserver (or an alternative standardized local scope mechanism) works.
But that can wait, I have lots to learn with what I have on hand. Starting with RxJS and magnetometer.
Source code for this project is publicly available on GitHub