Building a performant real-time web app with Ember Fastboot and Phoenix (Part 6)

Contextual Components & Animating your UI with Liquid Fire

Mike North
PEEP Stack
7 min readMay 4, 2016

--

This article is part 6 in a series. You should first read the previous parts leading up to this, or it may not make much sense!

Part 1: The meeting of two well-aligned, opinionated frameworks
Part 2: Users and Authentication (API)
Part 2.1: Some small adjustments to your API
Part 3: Users and Authentication (UI)
Part 4: Logging in to our API & ember-simple-auth

Part 5: Building a CRUD resource
Part 6: Contextual Components & Animating your UI with liquid-fire
Part 7: Room UI and Messages

One advantage that single page apps have over “old school” server-side rendered web apps is that, because the user’s entire experience consists of a single page load, we have a lot more control over the experience of transitioning from screen to screen.

Liquid Fire, the Ember.js animation library, primarily maintained by core team member

, is a first class citizen in the Ember ecosystem. It’s very easy to use, and provides a high-level declarative API for animating transitions between views, and much more.

What do we want to animate?

When it comes to animation, a little goes a long way, and too much runs the risk of actually getting in the way of a good user experience rather than enhancing it. Let’s aim for a couple of enhancements, some of which are animation and some of which are not:

  • Add a Navbar for the auth pages, making it easy to navigate from the register page to the login page (hint: any child of the auth route)
  • Add a Navbar to the “Logged in experience” (hint: any child of the app route), with a “User” menu (i.e., the user’s email), and a dropdown containing a “Logout” button.
  • Navbars should make use of the SideNav materialize feature for mobile, and should have a fixed header that always stays on top.
  • Animated transitions between the login and register cards (side-to-side)
  • Animated transition as the user logs in (top-to-bottom sliding)

Logging out will remain un-animated, because ember-simple-auth does a restart of the UI to clear JS memory for security reasons

The Navbar Component

Requirements above indicate that we need two separate Navbars

whenever we see a repeated piece of UI, “Component” should jump into your mind.

In kind with our x-input, x-card and x-toast, let’s plan for an x-nav. These navs will have different content, so we need some sort of way to compose a navbar of various links. Let’s start with the syntax and appearance we’re looking for and work backwards

Appearance we’re looking for is something like this

Appearance we’re looking for from our x-nav component
Syntax we’re looking for from our x-nav component

And maybe something like this for the “logged in” navbar

Apparance we’re looking for from the navbar in the logged-in experience

From some markup like this

What we’ll be using here is the recently added contextual component feature and the hash helper, introduced in Ember v2.3.

Create three new components called x-nav, x-div, and nav-link using ember-cli

ember g component x-nav
ember g component x-div
ember g component nav-link

x-nav will be the top-level component for a navbar, x-div will be a fairly generic component that we’ll use for very simple DOM structure stuff, and nav-link will be a component representing a list item. Here’s the basic DOM structure we’re looking for

and here’s how we’re going to represent it in terms of our three components

One thing that we’ll have to be careful of, is that there’s some jQuery-plugin initialization code we have to run as soon as the whole nav is inserted in the DOM, and we need to make sure the data-activates attribute of the mobile collapse button is set properly. This can be done by sharing private state within these components, in a way that’s not seen by the outside world.

Let’s begin with x-div. There is literally nothing that you need to do in the template file, but open up ./app/components/x-div.js. We need this component to do one thing, and that’s inform a parent element of its ID.

app/components/x-div.js

Basically this means:

If a property called _parentComponent has been set, and the value of _parentComponent has something on it called _setupChildComponent, assume that it’s a function and invoke it, passing myself as an argument

I like this pattern because it’s very flexible, and leaves it up to the parent as to what needs to be done. On the receiving side of this (open up ./app/components/x-nav.js), we will need something like this

app/components/x-nav.js

so now, for a child that has the side-nav class on it, we store its elementId. This will be important when we need to initialize our side-nav.

The template of x-nav (open ./app/templates/components/x-nav.hbs) looks like this

app/templates/components/x-nav.hbs

Essentially we’re customizing two instances of x-div for our two ULs, and then also exporting our nav-link component so that users can compose them together freely. Now head over to ./app/components/nav-link.js and change the base class from Ember.Component to Ember.LinkComponent. You may be wondering why…

The styling that comes for free with materialize navs uses an “active” class on the LI (note not on the A tag contained within) to indicate the currently-selected nav item.

<li class=”active”>
<a>My menu item</a>
</li>

Ember’s link-to component also has an active class that is added automatically whenever the route that this link points to is the active route. We’re going to try to align these two concepts by using a nested {{link-to}}, the outer being a LI, and the inner being the standard A tag.

app/components/nav-link.js

And in the template, the inner {{link-to}} to the same route…

app/templates/components/nav-link.js

Note that there are things that {{link-to}} can do which our new component isn’t prepared to handle yet, but this will work for now.

Finally, let’s adjust the colors of our theme using SASS variables. Head over to your ./app/styles/app.scss and make the following change

make the primary color of our Materialize UI “deep orange”

You’ll need to make some small updates to your tests, and then they’ll pass

The last thing we’ll need is to add the jQuery plugin initialization stuff to ./app/components/x-nav.js — the didInsertElement hook is the right place for this kind of thing

app/components/x-nav.js

This is a great time to save your work, open up a PR, and merge into master once tests pass. If you want to compare your work to mine, here’s my merge commit:

One last thing I forgot to add is a small CSS tweak necessary to maintain expected stacking contexts, even when animating. Please add the following to your ./app/styles/app.scss

.liquid-container {
transform: none;
-webkit-transform: none;
}

Animations with Liquid Fire

First, install liquid fire via an ember-cli command

ember install liquid-fire

And create a new file ./app/transitions.js

touch app/transitions.js

This file is where you’ll define all of your route transition animations, declaratively. The first one we’ll want is a toLeft transition whenever we go from auth.login to auth.register, and a toRight if we go in the other direction. This is done as follows (in ./app/transitions.js)

app/transitions.js

One more step: head over to ./app/templates/auth.hbs and change the {{outlet}} to a {{liquid-outlet}}

a tiny change to app/templates/auth.hbs

You’re done. Super difficult, right? Go play with it

Now let’s animate the transition into the logged in state. This isn’t the same as clicking on a link, but because of liquid-fire’s deep integration with Ember, it’s basically the same change in another place. Head over to your ./app/templates/application.hbs and change your outlet to a liquid-outlet

small change to app/templates/application.hbs

and define a new transition in ./app/transitions.js

your complete app/transitions.js

Take a moment and think at how easy that was, and how difficult it would be using the other tools you’re aware of. This feeling you’re having is the high degree of productivity you’re achieving, thanks to using an opinionated web framework.

Logging in, animated!

Some adjustments to our Logged-in UI

One tweak that makes sense is to use the user’s email address instead of “Dropdown” in the navbar of the room list. It’s a small change, thanks to our flexible user-info component

a small change to app/templates/app.hbs

There, that’s much better

Now that we have a proper means of logging out via a navbar, we can get rid of the old “logout” button, and rearrange our UI a little bit to set the stage for what will come in the next article.

Some small UI changes, all done in app/templates/app/index.hbs

Because we have decoupled our actions from the DOM structure, making these changes is very straight forward

Some small changes to app/templates/app/index.hbs

We’re done with animation for now, so push your work up to GitHub. If you’d like to compare your code to mine, here are my changes

In the next part of this series we’ll start building the foundations for the concept of “Messages”, associated with a Room.

--

--