Can Components or Custom Elements be instantiated dynamically in JavaScript?

Is it possible to instantiate Aurelia components/custom elements/custom attributes dynamically through JavaScript, or can it only be done through the templating system? Note that I’m not talking about defining these things (which I’d still do in a regular HTML file with the template tag), only instantiating them.

I ask because it would be really nice to be able to use custom elements (or even vanilla SVG elements with custom attributes) when rendering data with d3.

To insert elements to the DOM with d3, you typically do something like d3.select('svg').append('rect') similar to how you would dynamically compose a page in the pre-framework days of jQuery. I know this sort of behavior goes against everything Aurelia (and other modern, component-based frameworks) aims to solve, but it would be really nice to be able to populate the DOM with Aurelia components/custom elements/custom attributes via d3 in a JavaScript file as this sort of behavior (to my knowledge at least) cannot be done with the current HTML-based templating language that expects you to know the structure of your data a priori.

So being able to do something like d3.select('svg').append('my-custom-element') or d3.select('svg').append('rect').attr('my-custom-attribute', true) where my-custom-element and my-custom-attribute are regular Aurelia custom elements and attributes defined in their own HTML and JS files.

Can this be done, or is it simply too far outside of what Aurelia was designed to handle?

1 Like

That’s a rather advanced scenario. I think you can have d3 create and insert pure HTML elements and attributes (custom or built-in) and then call enhance() on the parent element.

Note:

In your template, add a ref to your svg (for example <svg ref=“myCanvas” …>…)
Then in your class, import { TemplatingEngine } from 'aurelia-framework'; and @inject(TemplatingEngine) to get the singleton instance, then in attached() hook, call templatingEngine.enhance({container: this.myCanvas}).

See https://aurelia.io/docs/fundamentals/app-configuration-and-startup#leveraging-progressive-enhancement

2 Likes

That’s really interesting, thanks! Had no idea this existed. It doesn’t work at all how I was imagining, but I think it’s exactly what I’m looking for.

Basically it would be nice to be able to “Aurelia-erize” each d3 data point svg element by attaching a view-model to it and to be able to use that for handling things like mouse events (for click or hover interactions) rather than having to spell all that behavior out in d3 itself.

1 Like

Enhance is exactly what you call Aurelia-ize.

1 Like

It certainly doesn’t go against what Aurelia aims to solve. As @khuongduybui already pointed out, the enhance api solves this problem, though enhance is more meant for server-centric (legacy) apps where Aurelia can’t be the “boss” of the page.
There are also different ways to programmatically compose views and view models. compose is another thing worth looking into.

I also created a plugin aurelia-dynamic-html a while ago. This is a custom element that you can pass raw html into and it will compile and render it for you the “regular” way. It’s essentially a convenience wrapper around the compiler api’s. I demonstrate this with a live demo, two side-by-side Monaco editors (one for html, one for js) that turn two pieces of raw text into a live Aurelia part. It’s Aurelia inside Aurelia :slight_smile: You can see the source code for that demo here

7 Likes