0
votes

Trying out Aurelia features, and I wanted to create a simple custom attribute, that injects content into element on which attribute is defined, based on the template associated with attribute. So far I had no luck by just creating view and view model for custom attribute, and annotating element with attribute. How does one render template associated with custom attribute. Any links or info would be appreciated.

Following Charleh's link I tried to implement it, and although view renders, it does not bind my items. Here is the code, maybe somebody can spot what is wrong

ctest.ts

import { inject, dynamicOptions, Container, customAttribute, bindable} from "aurelia-framework";
import {ViewEngine} from 'aurelia-templating';

@dynamicOptions
@customAttribute("my-test")
@inject(Element, Container, ViewEngine)
export class MyTestCustomAttribute { // extends Paging {

    constructor(private element: any,
        private container: Container,
        private viewEngine: ViewEngine) {

        this.element = element;
    }

    @bindable items = new Array<number>();

    @bindable totalItems: any;

    attached() {

        for (let i = 0; i < this.totalItems; i++) {
            this.items.push(i);
        }

        this.viewEngine.loadViewFactory('components/ctest/ctest.html').then(factory => {
            const childContainer = this.container.createChild();
            const view = factory.create(childContainer);
            view.bind(this);
        });
    }

    propertyChanged(name, newValue, oldValue) {
        switch (name) {
            case 'totalItems':
                alert("totalItems changed");
                break;
            case 'items':
                alert("items changed");
                break;
            default:
                break;
        }
    }
}

ctest.html

<template>
    hello from my-test
    <ul>
        <li repeat.for="item of items">
            ${item}
        </li>
    </ul>
</template>

and usage

tried also

<div my-test="totalItems.bind:5"></div>

No matter what, this.totalItems is always undefined.

Update

correct syntax for binding pascal case attribute names per convention is to use "-" so this is correct

<div my-test="total-items:5"></div>
1
Custom attributes need to manually manipulate the DOM since they don't hook into the tempting engine by default, but you can do that too. There's a write up on this in the latest Aurelia weeklyCharleh
jeremyg.net/entry/… here's the postCharleh
You could render the template using the template engine and then insert the result into the DOM as a child of the element it's attached toCharleh
@Charleh thanks for link. Do you have a link for how to do this in regards to your last comment? Coming from Angular and trying to learn Aurelia...epitka
maybe you forget to add <div my-test="total-items.bind:5"></div>.jmvtrinidad

1 Answers

0
votes

This is what I ended up doing and it seems to work fine so far

public attached(): void {

    this.viewEngine.loadViewFactory('components/pagination/PaginationCustomAttribute.html').then(factory => {

        const childContainer = this.container.createChild();
        const view = factory.create(childContainer);

        view.bind(this);

        this.totalPages = this.calculateTotalPages();
        this.updatePage();

        const vs = new ViewSlot(this.element, true);
        vs.add(view);
    });
}