Search code examples
aurelia

Reference a slot inside the ViewModel of an Aurelia component


Let's say you have the following component:

export class Message {
    messageTxt: string = "";

    attached() {
       // reference the slot HTMLElement here somehow
    }
}

with the following template:

<template>
   <div>
      <slot name="trigger">
      </slot>

      <div>${messageTxt}</div>
   </div>
</template>

As the comment in the code implies, I'm wondering how to access the <slot> element in the ViewModel. I've tried adding a ref attribute to it but it's undefined.

I've also tried adding a parent to it, putting the ref on the parent and getting the slot HTMLElement by accessing the parent's direct child. It worked, but I'm wondering if there's a better solution.

Just to be clear, I need the element that's going to replace the <slot>.


Solution

  • If you know the name of the tag that is going to be in the <slot>, you can use the @child resolver. For example:

    Message's ViewModel

    import {child} from 'aurelia-framework';
    
    export class Element1 {
      @child('p') myP;
    
      attached() {
        console.log(this.myP);
      }
    }
    

    Message's View

    <template>
       <slot></slot>
    </template>
    

    Usage

    <element1>
       <p>test 1 2 3</p>
    </element1>
    

    Use @children for a collection of elements:

    Message's ViewModel

    import {children} from 'aurelia-framework';
    
    export class Element1 {
      @children('ps') myPs = [];
    
      attached() {
        console.log(this.myPs);
      }
    }
    

    Usage

    <element1>
       <p>test 1 2 3</p>
       <p>test 1 2 3</p>
       <p>test 1 2 3</p>
    </element1>
    

    If you don't know the name of the tag, you can inject the element and iterate over the children property. For instance:

    Message's View

    <template>
      <slot name="1"></slot>
      <slot name="2"></slot>
    </template>
    

    Message's ViewModel

    import {inject} from 'aurelia-framework';
    
    @inject(Element)
    export class Element1 {
    
      constructor(element) {
        this.element = element;
      }
    
      attached() {
        //iterate over this.element.children;
      }
    }
    

    Usage

    <template>
      <require from="./element1"></require>
    
      <element1>
        <p slot="1">sadfasdf</p>
        <p slot="2">asdfsadfasd</p>
      </element1>
    </template>