Binding to Element Size
Basic implementation
import { bindable, BindingMode, customAttribute } from 'aurelia';
@customAttribute({
name: 'rectsize',
hasDynamicOptions: true
})
export class RectSize {
public static inject = [INode];
@bindable({ mode: BindingMode.fromView })
public value!: ResizeObserverSize;
@bindable()
public boxSize!: 'border-box' | 'content-box';
private observer!: ResizeObserver;
constructor(
private readonly element: HTMLElement
) {
}
public binding(): void {
let observer = this.observer;
if (observer === void 0) {
observer = this.observer = this.createObserver();
}
observer.observe(this.element, { box: 'border-box' });
}
public unbinding(): void {
this.observer.disconnect();
this.observer = (void 0)!;
}
private createObserver(): ResizeObserver {
return new ResizeObserver((entries) => {
this.handleResize(entries[0]);
});
}
/**
* @internal
*/
private handleResize(entry: ResizeObserverEntry): void {
this.value = this.boxSize === 'content-box' ? entry.contentBoxSize : entry.borderBoxSize;
}
}
Working with polyfill
As ResizeObserver
is still new and experimental API, it's not widely supported in all browsers. Fortunately there are a few polyfills available. For example:
older spec, with only
contentRect
: https://github.com/que-etc/resize-observer-polyfillnewer spec, with supports for box model options: https://github.com/juggle/resize-observer
To make the attribute work seamlessly with any polyfill users want to choose, we can adjust the way we get the ResizeObserver
constructor, as shown in the following example:
export class RectSize {
+ /**
+ * Allow user to ponyfill Resize observer via this static field
+ */
+ public static ResizeObserver: ResizeObserver;
+ private createObserver(): ResizeObserver {
+ const ResizeObserverCtor = this.getResizeObserver();
- return new ResizeObserver((entries) => {
+ return new ResizeObserverCtor((entries) => {
+ this.handleResize(entries[0]);
+ });
+ }
+ private getResizeObserver(): ResizeObserver {
+ return RectSize.ResizeObserver || window.ResizeObserver;
+ }
And now, our user can switch to any polyfill as the following example:
import { RectSize } from './some-path'
import { ResizeObserver } from 'some-resize-observer-polyfill'
RectSize.ResizeObserver = ResizeObserver;
Example usage
For the above implementation, the usage would be:
<form rectsize.bind="formSize">
...
</form>
or
<form rectsize="value.bind: formSize; box-model: content-box;">
...
</form>
Special note:
For the polyfill at https://github.com/que-etc/resize-observer-polyfill , you cannot use box-model
for observation option, as it follows an older spec of ResizeObserver
. Though it is a mature polyfill, and works well so if you want to use it, slightly modify the above implementation:
private handleResize(entry: ResizeObserverEntry): void {
- this.value = this.boxSize === 'content-box' ? entry.contentBoxSize : entry.borderBoxSize;
+ this.value = entry.contentRect;
}
Last updated
Was this helpful?