Adding a component to DOM element after render

I have a route, component, and template for displaying HTML content that is fetched from a database. The route fetches the HTML content, and the template renders the content. What I am attempting to do, is replace an element from the fetched HTML content with a component.

For example, if the fetched content is <p>Hello World</p> <div id='fancy-list'></div> , I would like to either replace the div with an ember component, or append a component to the div.

From what I gather, the replacing will happen in the ‘didInsertElement’ hook, but I have no idea how to create an instance of a component that can then be appended to a DOM element.

Does anyone have suggestions ?

This isn’t something you necessarily want to do, at least not fully dynamic component creation/invocation. Templates are statically compiled at build time and ideally will fully support static analysis soon (efforts like template strict mode and template imports are moving us in this direction).

It’s also kinda of a muddled separation of concerns, both the client and server are directly providing DOM content. Also depending on how this is all set up I think you could run into some security issues.

That said… you may be able to use something like ember-wormhole to do what you want. As long as you know exactly what component you want to render and exactly what the div/class you’re targeting is ahead of time you could try to render a wormhole with the desired component into the target div. I think this would keep everything statically analyzable and not require any dynamic component creation or invocation, just a wormhole that’s always there and only shows up when the target element appears.

2 Likes

Thank you.

It is definitely something I don’t want to do, but what I want, and what management wants me to implement, are 2 different things. :slight_smile:

Ha yeah I’ve been there :grin:

All you need is triple curlies:

{{{this.htmlContent}}}

Triple curlies opt out of Ember’s usual security protections which would prevent DOM Elements from appearing in strings. With triple curlies, you can render a string of arbitrary HTML.

But rendering an Ember component in the middle of that HTML?

Oh, I missed that part of the question. But yes, you can do that with either ember-wormhole or ember’s built in in-element.

There are a couple other alternatives too, depending on how much control you have over the server-delievered HTML and the performance requirements of your app.

You could use native web components so that <fancy-list></fancy-list> in the server-rendered HTML actually invokes your own code. This could be a nicer way to kick off the process of rendering your ember components in that spot (your implementation may still use in-element as glue, but it would make it easier to detect and render arbitrary numbers of custom elements in the HTML).

Alternatively, it is possible to load the template compiler into the browser and treat the HTML as templates that can contain component invocations, so the server could send <SomeComponent /> and that would actually render. If you only do this once or twice on a route, the cost of the compiling won’t be a big deal. The main downside is that the template compiler itself adds a lot of Javascript to your app, so boot times may be slower.

2 Likes