Fionn
Fionn

Reputation: 11265

Programmatically instantiate components in Aurelia

Is it possible to programmatically create an component in aurelia and then somehow bind it to a tag of that type in the view. For example something like a simple tree view, see the comments in the HTML templates below.


tree-view.ts

import {TreeNode} from "./tree-node";

export class TreeView<T> {
    private _rootNodes: TreeNode<T>[] = [];

    get rootNodes(): TreeNode<T>[] {
        return this._rootNodes;
    }

    public addRootNode(node: TreeNode<T>) {
        this._rootNodes.push(node);
    }
}

tree-node.ts

export class TreeNode<T> {

    private _value: T;
    private _name: string;
    private _children: TreeNode<T>[] = [];

    get value(): T {
        return this._value;
    }

    get name(): string {
        return this._name;
    }

    get children(): TreeNode<T>[] {
        return this._children;
    }

    public addChild(child: TreeNode<T>): void {
        this._children.push(child);
    }

    constructor(name: string, value: T) {
        this._name = name;
        this._value = value;
    }
}

tree-view.html

<template>
    <!-- Something like this is the intend -->
    <tree-node repeat.for="node of rootNodes"></tree-node>
</template>

tree-node.html

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

    <div class='childNodes'>
        <!-- Something like this is the intend -->
        <tree-node repeat.for="node of children"></tree-node>
    </div>
</template>

Upvotes: 2

Views: 629

Answers (2)

Daryl Cober
Daryl Cober

Reputation: 27

What you are talking about is a core functionality of Aurelia. Please see http://aurelia.io/docs/fundamentals/components#creating-a-component

By creating a component you can now use that component in any html as <mycomponent></mycomponent>

Components can contain other components.

Upvotes: 1

Fabio
Fabio

Reputation: 11990

I couldn't do this using custom-element declaration. I don't know if there's a way to set the custom-element's view-model. You can use compose as a workaround.

Tree-view.html

<template>
    <require from="./tree-node"></require>

    <!-- Something like this is the intend -->
    <compose repeat.for="node of rootNodes" view="./tree-node.html" view-model.bind="node"></compose>
</template>

Tree-node.html

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

    <div class='childNodes' style="margin-left: 20px;">
        <!-- Something like this is the intend -->
        <compose repeat.for="node of children" view="./tree-node.html" view-model.bind="node"></compose>
    </div>
</template>

Running example https://gist.run/?id=95b8892918d7e5a7aadf0ac7eb28124d

Another solution (and better in my opinion) is exposing name and child as bindable properties:

export class TreeNode {
    @bindable value;
    @bindable name;
    @bindable children = [];
}

In this way, you would be able to do something like this:

<tree-node repeat.for="node of rootNodes" name.bind="node.name" value.bind="node.value" children.bind="node.children"></tree-node>

This is a little bit more verbose but faster. In the mean time, I'll see if there's a way to set the custom-element's view-model.

Upvotes: 2

Related Questions