Higher Order and Pure Components in Ember

At my current job we use Ember(Press F to pay respects). Now I actually jumped on board the Ember train back in 2014 when it was fresh and new. It was okay back then, a little too strict on the MVC stuff, but the observer pattern was cool so I used it lightly at my work in the lab. Then React became a thing and I jumped on that train pretty hard in 2015 and left Ember in the dust. 2015–2017 was all React all the time(with some random Ruby on Rails in there when necessary). I started to get the hang of React and functional programming with Higher Order Components and Pure Components. Then our start-up petered out and I was looking for a new job. The small company I now work for is dedicated to sticking with Ember so I decided to make the best of it and try to implement some of the functional programming patterns in Ember. This article is dedicated to explaining and exploring how we’ve implemented the functional programming concepts of Higher Order Components and Pure Components in Ember.

The first thing I did was get our stuff up to ES6 and in the Ember eco-system that also meant using decorators — something I had never used but now think they are super keen. Also since I was coming from React land, I like to have my templates in the same file as my js code, so you’ll see me using the precompile hbs for that. Once all that was sorted out I started writing components and eventually settled on a pattern for pure components that looks something like this:

import Component from '@ember/component';
import hbs from 'htmlbars-inline-precompile';
import { action } from '@ember-decorators/object';
/**
* This class displays a clock.
* @prop {Function} toggleDisplay action to toggle 12/24 hour display
* @prop {Date} theTime the time the clock shows
* @prop {boolean} militaryFormat whether to display in 12/24 hour format
*/
export default class SimpleClock extends Component {
constructor() {
super();
}
  get elementId() {
return 'the-clock';
}
  /*
* Private method to call the closure action
*/
@action
_clickToggle(evt) {
this.get('toggleDisplay')();
}

@computed('theTime', 'militaryFormat')
get timeDisplay() {
const format24 = this.get('militaryFormat');
const the_time = this.get('theTime');
if(format24) {
//format goes here
} else {
//other format goes here
}
}
  get layout() {
return hbs `
<div id='the-time'>
{{timeDisplay}}
</div>
<a onClick={{action '_clickToggle'}}>{{formatText}}</a>
`;
}
}

I like to list the passed in properties at the top of the file in the class description(toggleDisplay, theTime and militaryFormat. Other than that its a pretty basic component. Things get more interesting when setting up the Higher Order Component(container) component:

import Component from '@ember/component';
import hbs from 'htmlbars-inline-precompile';
import { action } from '@ember-decorators/object';
import { service } from '@ember-decorators/service';
import { reads } from '@ember-decorators/object/computed';
/**
* This is a container component that contains functionality for settings
*/
export default class TimeContainer extends Component {
constructor() {
super();
this.militaryFormat = false;
}
  @service('time-service') time_service;
@reads('time_service.now') now;
  /**
* The method
* @param {String} setting_name [description]
* @param {String} value [description]
*/
@action
toggleDisplay() {
this.set('militaryFormat', !this.get('militaryFormat'));
}
  get layout() {
return hbs `
{{yield
(hash
theTime=now
militaryFormat=militaryFormat
toggleDisplay=(action 'toggleDisplay')
)
}}
`;
}
}

I thought about how to write a Higher Order Component for quite some time and this was the best I could come up with (for now). This component is basically just a yield with a hash so it can be used as a contextual component:

{{#containers/time-container as |t|}}
{{time-clock
theTime=t.theTime
militaryFormat=t.militaryFormat
toggleDisplay=(action t.toggleDisplay)
}}
{{/containers/time-container}}

I’m not exactly thrilled with having to write out each property of the contextual component I’m interested in(I would prefer the common pattern in React of using …props to pass things along, but I couldn’t figure out a good way to do that yet.

That’s all for this article, for now anyway. I’m working on getting a sample up on github but I haven’t had a chance to push all my code yet, so that’s coming I promise. Until then, good luck and let me know what your functional programming patterns in Ember look like!