1

I have an application that is closely tied to the DOM. I need to keep track of the size and position of the elements that represent the objects behind them.

myViewModel.js

export class MyViewModel {

    // my root view model has important properties 
    // that all other functions and objects need to use
    constructor() {
        this.importantProperty = 'veryimportant';
        this.things = [];
    }

    // i create things in the view model that are
    // represented in the dom
    createThing() {
        this.things.push({
            isAThing: true
        });
    }

    // i do things with things in the view model 
    // that depend strongly on the root view model
    doSomethingWithThing(thing, property) {
        thing[property] = `${this.importantProperty}${property}`;
    }

    // but i need to know all about the dom representation
    // of the things in the view model
    doAnotherThingWithThing(thing) {
        console.log(`the height of the thing is ${thing.height}`);
    }

    lookAndSeeWhatSizeThisThingIs(element, thing) {
        thing.height = element.clientHeight;
        thing.width = element.clientWidth;
        console.assert('That was easy!');
    }
}

myViewModel.html

<template>

    <!-- these things can change in size and shape, and I have
        no idea what they will be until runtime
    <div repeat.for="thing of things"

        <!-- so ideally I'd like to call something like this -->
        composed.delegate="lookAndSeeWhatSizeThisThingIs($element, thing)">

        <img src="img/${$index}.png" />
    </div>

</div>

Is there a way to do this today?

Matthew James Davis
  • 12,134
  • 7
  • 61
  • 90

1 Answers1

1

Since a CustomAttribute has access to the composition lifecycle, we can create a CustomAttribute that triggers an event on the element that fires in the attached() callback.

import {autoinject} from 'aurelia-framework';

@inject(Element)
export class AttachableCustomAttribute {

    constructor(element) {
        this.element = element;
    }

    attached() {
      this.element.dispatchEvent(
          new CustomEvent('attached'));
    }
}

And use it just like any other event binding, with the exception that it does not bubble, and thus we must use trigger instead of delegate.

<div repeat.for="thing of things"
    attached.trigger="lookAndSeeWhatSizeThisThingIs($event, thing)" attachable>
    <img src="img/${$index}.png" />
</div>
Matthew James Davis
  • 12,134
  • 7
  • 61
  • 90