General Assembly WDI, Week 11

Ember!

Week 11 of Web Development Immersive was all about Ember (the JavaScript framework, not the IOT coffee mug or the surprisingly tasty “toasted chai cider”).

Day 49

Important things to know about Ember:

  • Ember is an open source JS framework. It’s mostly used to build web apps, but it can be used for mobile or desktop apps (e.g., Apple Music).
  • Like Ruby on Rails, Ember is an opinionated framework that follows “convention over configuration.” It provides a lot of built-in structure and help, as long as you follow patterns. In exchange, you get to spend less time setting things up and piecing them together. (The downside: if you want or need to break conventions for some reason, you have a lot more work ahead of you than if you were using a less opinionated framework like Backbone or a library like React.)
  • Ember handles client-side routing (which makes me very happy, as I established in last week’s post). Routes in Ember parse a URL, connect a router to a template, and load any necessary data into that template via a related model. Routes can also redirect (for example, if a guest user tries to access a route that’s only available to authenticated users) and handle actions that involve altering data or transitioning to a new route.
  • Ember writes most AJAX calls for you, if you follow convention. Ember is a fan of JSON API, but you can customize an Adapters to tell Ember how your API is formatted and how to interact with it. Adapters handle the relationship between your data and how you store that data (on the back end, in Ember’s cache, and in test fixtures).
  • Ember caches data on the client side, which makes your apps faster. Ember also allows you to change data on the client side without persisting it to the server (which creates something called “dirty attributes”).
  • Ember binds data, meaning (briefly) that updating a piece of information will update all persistently related information—we’ll talk about this more soon, but the gist is that Ember 2 uses one-way data binding: data is bound down (from a model associated with a route down through templates/components), and actions affecting that data move up (from a component up through to the template to a route and the related model). This is a change from Ember 1, which used two-way data binding, in which changes made in the view are automatically updated at the model level. With large, complex applications, this can slow things down and cause unintended consequences that can be hard to track down and debug.
  • Ember 1 used views and controllers; Ember 2 has shifted toward components. Components have templates (not unlike views) and contain properties and methods associated with specific UI. You can invoke a component from a template associated with a route or from another component. Components don’t have access to the broader scope of a route—their scope is defined explicitly at the location where they’re invoked. Components are modular and reusable—an example might be a button to “like” a video on Vine, which is shown when you’re looking at the specific video and also shown next to each video when you’re looking at a list of videos.
  • The Ember command line interface (CLI) is a handy tool that simplifies the process of setting up Ember apps. The Ember Inspector is a browser extension that helps with debugging and inspecting Ember objects in the browser.
  • Ember uses special Ember Objects (which are a class in Ember), which enable data binding in Ember. Among other things, using Ember Objects allows for the creation of computed properties, which calculate properties of an object based on the values of other properties of that object. Computed properties “watch” the properties on which they depend and will update on the fly as those properties change. They’re a little bit like virtual properties in Mongoose, but they’re more aware.

Cool things to know about Ember:

  • Ember was created by Yehuda Katz, who was also instrumental in Ruby on Rails and jQuery (and created Handlebars). Ember feels a lot like Rails in many ways, and uses Handlebars for its templates.
  • There’s an Ember conference on the Boston Harbor Islands each summer, which sounds awesome.

Day 50

Routing

Tuesday was about routing and components. We talked first about static routing, which you might use for something like /about, which would display a view containing your hypothetical personal library site’s “About” content, or /books, which would list all of the books. We then talked about nested routing—let’s say your /about view has some general “About this library site” content, but you actually run the site with two of your friends, and each of you has a bio and a personal philosophy on literature that you’d like to display beneath the About content at, say, /about/helga. Nesting routes lets you display the content for Helga inside of the About content. Inside the template for the /about route, you add Ember’s {{outlet}} helper. When you visit a nested route (/about/helga), the template for that route will render inside of that helper.

Next up: dynamic and resource routing. Resource routes in Ember (or Rails, or other frameworks) are routes that are associated with a specific data resource—the /books example above is one, as it maps to a books resource on the site’s back end. Conversely, /about is not a resource route, as (in this example) it doesn’t draw on any data; it contains static content about the site. When you’re working with resources, dynamic routing becomes important—we might expect a route that looks something like /books/1 to show us the first book. Dynamic routing lets us create routes like this without having to specify a route for each individual book. Instead, the route contains parameters that indicate which resource to load within a view. Instead of /books/1 and /books/2 and so on, we can create a route for /books/:book_id to handle all possible cases for us. (As a side note, this isn’t a new concept—we covered parameters like this in Rails in Week 5.)

Components

On to components: components are reusable pieces of UI within an Ember app. Knowing when to split component out of a template is a bit of an art, but generally, if you’re starting to work with replicable actions (for example, a button that looks like a pencil that means “click this to edit something,” that you want to reuse for different kinds of objects throughout the app), it’s a good idea to use a component.

A few things to know about components:

  • Components can be nested within routes and within each other, and components can be used multiple times in a single view.
  • Components must have at least one dash (-) in their name to prevent clashes with HTML elements and help Ember recognize them automatically.
  • Components don’t have a model hook, meaning any data they receive needs to come from a parent route.
  • By default, Ember wraps all components in a div. You can customize a component’s element and its class, if you want.
  • Components can “send” actions up to their parents, which is how you would, say, move from clicking the pencil button next to a blog post up to a route that recognizes that what you want to do is edit blog post #7 and transitions you to the correct edit view. This is Ember’s “data down, actions up” convention at work.

Day 51

Now that we have a better handle on how Ember applications are structured and how to map routes to views (which may or may not contain components), it’s time to talk about data. As already mentioned a few times, Ember uses unidirectional data flow: data down, actions up. Data comes in through a model hook that is associated with a route, and is passed down through that route’s template to any components. When actions happen at the component level, they are bubbled up (using sendAction) to the route. Data is only ever changed at the route level (generally speaking / when following best practices), and the UI only changes when something changes in the data store or after a successful response from an API call. This is called “pessimistic” UI, where the UI is the last thing to update. This is different than frameworks that use two-way data binding, where actions at the component/lowest level take immediate effect on the UI and simultaneously persist any changes on the back end.

Data binding in Ember involves, in part, passing the correct data down to a component. Let’s say you have that edit button, and you want to include it in the view for a single book. You might do something like {{edit-button book=book edit='edit'}}. In this example, edit-button is the component; book=book points the book value in the component to the book data coming in from the model, and 'edit' is the name of the action bubbling up from that component (this.sendAction('edit')), which the route is listening for under the name edit. We’re binding the book data down, and sending the actions back up to the route.

Ember applications include Ember Data, a library that handles data models and interaction with those models through adapters and serializers. Adapters handle making requests to servers. Adapters enable Ember to interact with data stored in a variety of places and formats, from localStorage to WordPress to Elasticsearch to Rails. (Ember Data also works with streaming servers, for apps that update in real time.) Serializers format the data on its way to and from the server. Ember comes with three different serializers (JSON API, JSON, and REST), but you can also write custom serializers if your server provides or expects data in a different format. An example: we worked with an API that returned a piece of information called content. “Content” is an internal property used by Ember Data, which means we needed to rename this data to something else so we could use it in our app without causing conflicts. We wrote a custom serializer that renamed “content” to “item,” which solved the problem.

Collectively, Ember Data, adapters, and serializers allow you to work with data via models and the Ember data store. Different routes (or component that send actions up to routes / display data that is bound down from routes) ask the store for data through different models. Data needed in multiple parts of your application is fetched only once and held in the store, and different pieces of UI can then quickly grab the data they need from the store rather than making redundant requests to the API. This speeds up your application (you’re not waiting for the response to an AJAX request every time you switch to a new view), and puts all responsibility for fetching data in a single place (the store), rather than splitting it out across different components and routes.

Day 52

We spent Thursday working with templates in Ember and building out a simple todo list application. As mentioned above, Ember uses Handlebars as its templating language; Ember comes with a handful of built-in Handlebars “helpers” that do things like conditionally display content or loop over content. You can also write your own helpers to do things like format date and time values. Ember also has a set of built-in input helpers for working with forms (you might notice there’s no way to use a select element with these helpers—fellow GA grad Jen Weber has written up a simple guide to creating a select element in Ember.js targeted at beginning Ember users).

Day 53

On Friday, we talked about authentication in Ember. We were provided with an Ember template that includes the code to handle authentication via a Rails API that follows the Rails API template also provided by GA. The gist:

  • The API requires users who want to access protected resources to sign up with an email address, a password, and a password confirmation field that matches the password.
  • The API requires users to sign in (using their email address and password) before accessing protected resources. The API returns a token from a successful sign in request. This token must be included as a header with all requests for protected resources, as well as on requests to sign out. The token is deleted/invalidated on sign out and cannot be used again.
  • The Ember application includes two custom services, auth and ajax, which are injected into one another.
  • The auth service uses the ajax service to make the appropriate AJAX requests for sign up, sign in, change password, and sign out. Upon successful sign in, the response data from the server (user id, email address, and token) is stored in a credentials object. On sign out (whether or not the response from the server indicates success), the credentials object in Ember is reset, and the data is cleared.
  • The ajax service extends ember-ajax, which offers methods to make AJAX requests in Ember. The custom service sets an Authorization header before AJAX requests that includes the authenticated user’s token, if there is an authenticated user. This header is used for all requests Ember makes to the API, which gives authenticated users access to protected resources throughout the app.

After covering auth, we were given Friday afternoon to start work on our capstone projects, the last piece of the Web Development Immersive program (!). Friday afternoon was one of the hardest/best days of all of GA for me—more on that in my Week 12 / capstone project post, which I promise is coming soon(ish).