From {{Classic}} style to <AngleBracket /> components in EmberJS

William Bautista
Smart Pension Technology
4 min readMar 1, 2019

Here at Smart Pension, we are constantly evolving. We are a very successful Fintech company, not just in the UK, but globally too. That is why we are always looking to adapt and move to the best practices within the Ember community. One thing that came to our attention was the fact that, yes we try to keep aligned with the LTS Ember version, but we are missing some of the power it can provide us with. One specific case was that we were not using <AngleBracket/> components within our apps.

Once we realised the need for this within the business and understood the benefits of this migration, we established some rules to follow. This was important as we currently have five different client apps and one common app, where we share many components across in our monolith repo. The rules were:

  • The migration will be done one single app at a time
  • Only components belonging to the current app in the migration process will be moved
  • Once all apps have been migrated, we’ll move the common components in one single migration as it affects all other five clients.

By following these steps we reduced potential bugs or errors. Alongside these rules, our QA team could do a small regression test each time we did a migration, rather than a large one if we had decided to go down the route of migrating everything in one go. 🌋

Bearing in mind that by the time we started this change we were using Ember version 3.3 and that <AngleBracket/> is only built in Ember 3.4 onward, we had to do some research to see if there was some sort of polyfill available to us, instead of doing a whole upgrade first. Thankfully, and this is one of the best things about Ember community, the core team had already produced one polyfill which was back compatible.

Robert Jackson created ember-angle-bracket-invocation-polyfill which supported Ember 2.12, 2.16, 2.18, 3.1, 3.2 and 3.3 😎

ember i ember-angle-bracket-invocation-polyfill

The most awesome thing about this polyfill was the fact that it needed zero configuration, apart from the fact that ember-cli-htmlbars-inline-precompile was at least version 1.0.3 in our repo. Other than that, we were ready to start doing our first migration. The next step was to find some sort of codemod which alleviated the burden of renaming files and adjusting component calls inside our hbs, but sadly there was none available. After hours of research, the reason was that manipulating hbs itself is not easy, especially because a component can use inline or block style which makes the dynamic process a bit complex.

Photo by Matthew Henry on Unsplash

After that, we decided to start working on the transition manually. 👨‍💻

These are some examples of how our code looked after that.

Self-closing syntax

// Before
{{error-page-content}}

// After
<ErrorPageContent />

Block syntax

// Before
{{headers/nav-masterhead
authManager=authManager
invalidateSession=(action 'invalidateSession')
isDesktopView=isDesktopView
isTabletView=isTabletView
}}
// After
<HeadersNavMasterhead
@authManager={{authManager}}
@invalidateSession={{action 'invalidateSession'}}
@isDesktopView={{isDesktopView}}
@isTabletView={{isTabletView}}"
/>

Passing HTML attributes with ...attributes

Either if you have a template only or hbs-js component, you can pass HTML attributes thanks to …attributes, this will allow you to modify your component in a neat way without to add extra logic to get the same result.

// Component introduction-title.hbs
<div class="title" ...attributes>
<h1>{{@title}}</h1>
</div>
// Calling component
<IntroductionTitle
@title='Angle bracket components'
class='my-class'
data-test='my-data-selector'
/>

In this way, you can add HTML attributes to your component that will be added to your DOM thanks to Ember magic, the result will be:

<div data-test="my-data-selector" class="title my-class">
<h1>Angle bracket components</h1>
</div>

Bear in mind that if you append …attributes at the beginning of your div, you will append your component attributes at the beginning of your div.

// Component introduction-title.hbs
<div ...attributes class="title">
<h1>{{@title}}</h1>
</div>

// Calling component
<IntroductionTitle
@title='Angle bracket components'
class='my-class'
data-test='my-data-selector'
/>
// HTML
<div data-test="my-data-selector" class="my-class title">
<h1>Angle bracket components</h1>
</div>

Conclusions

By not having nested components as they are not supported on <AngleBrackect/> we could have a far clear picture of our existing ones. Also, we could identify and 🔥 some other unused ones, resulting in a more clean repo.

  • We renamed some components to reflect what they were for, as some of the community patterns suggested.
  • Now we could identify in a clearer way which attributes were inherent to each component itself and what other bits were pure HTML attributes.
  • Proper {{helpers}} were now easier to identify from actual components when going through our code.

--

--