loading...
Cover image for Ember.js in-element feature

Ember.js in-element feature

shayanypn profile image shayan ・3 min read

In this article, I am going to talk about a new feature of Ember.js on portal rendering which comes in V 3.20. Also, I am going to build a simple sample application using this feature. For more, let’s stay tuned.

Single-page applications use to load and render their code under one root DOM element, which brings a limitation for the developers. Say you need to render an element into your application. Easy right? That element is mounted to the nearest DOM element and rendered inside of it as a result. But! What if we want to render that element outside of the div somewhere else? That could be tricky because it breaks the convention that a component needs to render as a new element and follow a parent-child hierarchy. The parent wants to go where its child goes.

In a library like React.js developers can use ReactDOM.createPortal(child, container) to achieve this goal. In the Ember.js framework, developers could use community addons like ember-wormhole or ember-elsewhere.

Ember.js recently released a new version 3.20 which introduces a new helper for this approach. It’s {{in-element}}.

{{#in-element this.myDestinationElement}}
  <div>Some content</div>
{{/in-element}}

To use the helper, pass in a DOM element to target (this.myDestinationElement in the example below) and a block to render:

This new public API behaves a little differently from the private API:

  • For the public API {{in-element}}, by default, the rendered content will replace all the content of the destination, effectively becoming its innerHTML. If you want it to be appended instead of replacing the content, you can pass in insertBefore=null.
  • In the private API {{-in-element}}, the rendered content was appended to any existing content in the destination. Developers should use the public API, {{in-element}}, and discontinue using {{-in-element}}.

ember.js in-element new feature

For using this helper, first, you need to update your ember to version 3.20. Try below command then

npm install -g ember-cli@3.20.0

And then you can create a new ember project and use this feature.

Note: By default, Ember renders the main application after all body elements, and appends the directory to <body>. So, if you suppose to render the outer element below your vendor resources file, it doesn’t work. As a result, if you suppose to render your outer elements, below your main application element, you should specify the rootElement of your Ember app located in PATH-TO-PROJECT/app/app.js and then you can add your outer element below that.

Sample Use-case

To create a simple use-case of this new feature let create a really simple sample.

ember.js in-element feature

So first of all update to new ember version

npm install -g ember-cli@3.20.0

then create a new ember project

ember new emberjs-in-element-demo

So, then let create our outer element. for that you should edit PROJECT/app/index.html file as below

...
  <body>
    {{content-for "body"}}
+    <div id="modal_root"></div>

    <script src="{{rootURL}}assets/vendor.js"></script>
    <script src="{{rootURL}}assets/emberjs-in-element-demo.js"></script>

    {{content-for "body-footer"}}
  </body>
...

Then let create our desire component, and name it as render-out

ember g component render-out
ember g component-class render-out

Then we should specify our destination element in the component.

// app/components/render-out.js
import Component from '@glimmer/component';

export default class RenderOutComponent extends Component {
  myDestinationElement = document.getElementById('modal_root')
}

and use the new helper

{{!-- app/components/render-out.hbs --}}
{{#if @renderOut }} 
  {{#in-element this.myDestinationElement}}
    {{yield}}
  {{/in-element}}
{{else}}
  {{yield}}
{{/if}}

To explain the above code, if a user passed the @renderOut property, then the passed children would render in the <div id="modal_root"></div> element, otherwise, it renders as before.
So you can use it as

{{!-- app/templates/application.hbs --}}
<RenderOut @renderOut=true>
  This content render inside of <div id="modal_root"></div>
</RenderOut>

You can check my sample code in this repository.

Resources

Join the discussion

I would love to get some feedback here.

Posted on by:

shayanypn profile

shayan

@shayanypn

A frontend Developer that Love to learn and experiment new things. I am keen to help so never be afraid to reach out :) There are always many things to learn ...

Discussion

pic
Editor guide