Search code examples
aureliacustom-elementselectors-api

How to reference specific elements in Aurelia custom element's <slot>?


I want to create a custom fieldset in Aurelia and I need to set the style (width) of label elements within the "slot" tag (see example usage below). How can I access these elements? What I have so far is

<template>
  <require from="./ib-fieldset.css"></require>
  <fieldset style.bind="style">
    <legend>${title}</legend>
    <slot></slot>
  </fieldset>
</template>

and

import {bindable} from 'aurelia-framework';
import * as $ from 'jquery';

export class IbFieldset {
  @bindable title: string;
  @bindable top: number;
  @bindable left: number;
  @bindable labelWidth: number;

  style: string;

  attached() {
    this.title = ` ${this.title} `;
    this.style = `position: absolute; top: ${this.top}px; left: ${this.left}px;`;
  }
}

I use it like that:

  <ib-fieldset title="Address" top="100" left="200" labelWidth="100">
    <label for="firstName">First name:</label>
    <input id="firstName" type="text">

    <label for="lastName">Last name:</label>
    <input id="lastName" type="text">
  </ib-fieldset><br>

I tried with jquery but I don't know how to select elements within the fieldset component only (not the whole page which can contain other fieldsets).


Solution

  • Like most situations in Aurelia, there is no need for jQuery.

    GistRun: https://gist.run/?id=aa1e8239736e0de11f73116966af9ac9

    fieldset.html

    <template>
      <fieldset style="position: absolute; top: ${top}px; left: ${left}px;">
        <legend>${title}</legend>
        <slot ref="slotElement"></slot>
      </fieldset>
    </template>
    

    fieldset.js

    import {bindable} from 'aurelia-framework';
    
    export class IbFieldset {
      @bindable title: string;
      @bindable top: number;
      @bindable left: number;
      @bindable labelWidth: number;
    
      attached() {
        this.title = ` ${this.title} `;
    
        let labels = this.slotElement.querySelectorAll('label');
    
        for (let label of Array.from(labels)) {
            label.setAttribute('width', `${labelWidth}px`);
        }
      }
    }
    

    consumer.html

    <require from="./fieldset"></require>
    
    <ib-fieldset title="Address" top="100" left="200" label-width="100">
      <label for="firstName">First name:</label>
      <input id="firstName" type="text"/>
    
      <label for="lastName">Last name:</label>
      <input id="lastName" type="text"/>
    </ib-fieldset><br>
    

    To inject the element:

    import {inject} from ‘aurelia-framework’;
    
    @inject(Element)
    export class IbFieldset {
        constructor(element) {
            this.element = element;
        }
    
        attached() {
            let labels = this.element.querySelectorAll('label');
            ……
        }