Building Ember Data Apps with Firebase

31 January, 2016
post-banner

Firebase is an API for building real-time applications, without the need of setting up a backend or a database. Ember Data is 'a library for robustly managing model data in your Ember.js applications'. Using the Firebase adapter is a great way of working with Ember Data, and it makes the setup process super easy. The EmberFire adapter automatically synchronises any models stored in Ember Data once the app has been configured to work with Firebase.

In this post, we're going to build a simple Ember application using the Ember Data library and a Firebase backend to store and manage book data.

General Setup

To get started you’ll need a Firebase account. You can sign up for a Firebase account for free, if you haven't already.

Once you have your account set up, you will be able to create a new app from the Firebase dashboard. Simply give your app a name and set a URL, which we'll need to include in our Ember app's configuration, and Firebase will set everything up for you. You can change the app's name at any time by clicking the gear icon on the dashboard, and clicking the 'change name' option. The app's URL is fixed once the app is created, but paid Firebase accounts can use custom domains.

firebase-setup

You will need to install Ember-CLI and Bower, if you haven't already done so. Then, generate a new Ember app and cd into the project.

$ npm install -g ember-cli
$ npm install -g bower
$ ember new <APP-NAME>
$ cd <APP-NAME>

For simplicity I'm going to add Bootstrap for some quick styling for the app.

$ bower install bootstrap --save-dev

And then import the Bootstrap stylesheets into the ember-cli-build.js file.

...
app.import('bower_components/bootstrap/dist/css/bootstrap.css');  
return app.toTree();  

Now if you run ember serve and head over to localhost:4200 you should be greeted with the familiar 'Welcome to Ember' heading, with some small styling.

Installing EmberFire

Next you will need to install the EmberFire adapter to your Ember app, which can be done easily in the terminal.

$ ember install emberfire

Firebase will automatically be added as a dependancy to your bower.json file, and an adapter will be generated at app/adapters/application.js which will inject the FirebaseAdapter service across the entire app.

// app/adapters/application.js
import Ember from 'ember';  
import FirebaseAdapter from 'emberfire/adapters/firebase';

const { inject } = Ember;

export default FirebaseAdapter.extend({  
  firebase: inject.service(),
});

The last step of the setup stage is to configure your Firebase database URL, which was generated when you created your Firebase app. Simply add the data URL to the config/environment.js file.

...
firebase: 'https://YOUR-FIREBASE-NAME.firebaseio.com/',  
...

Storing Data Objects

Now everything is setup we can get on to storing data into our new Firebase database. For this article I'm going to build an app that allows the user to add and delete books from a list stored in the database.

To start, we'll generate an Ember Data model object using Ember-CLI generator. For this we are going to specify a book title and author as strings, and a publication year as a number.

$ ember generate model book title:string author:string pubYear:number

This will generate a model object at app/models/book.js with the following code.

// app/models/book.js
import DS from 'ember-data';

export default DS.Model.extend({  
  title: DS.attr('string'),
  author: DS.attr('string'),
  pubYear: DS.attr('number')
});

Routing and Templates

With the model object ready, we can start to create routes and templates to list and display the data. For this example we're going to have a books route as well as a books/new route to allow the user to add a new book.

First let's add some links to the application.hbs template for easier navigation once we've created these routes. Bare in mind that the app won't compile until these routes exist.

// app/templates/application.hbs
<div class="jumbotron text-center">  
  <h2 id="title">{{#link-to 'application'}}Firebase Books{{/link-to}}</h2>
  {{#link-to 'books'}}<button class="btn btn-primary">All Books</button>{{/link-to}}
  {{#link-to 'books.new'}}<button class="btn btn-primary">Add new book</button>{{/link-to}}
</div>  
{{outlet}}

Now we can generate the routes for books and books/new which will create a JavaScript route file and a HTMLbars template file for each of these routes.

$ ember generate route books
$ ember generate route books/new

This should have successfully created the relevant files for us, as well as adding them to the router.js.

...
Router.map(function() {  
  this.route('books', function() {
    this.route('new');
  });
});
...

We need to provide access for the books route to the model, by configuring the model hook to return the books. We can also add an orderBy property to list the books in alphabetical order.

// routes/books.js
import Ember from 'ember';

export default Ember.Route.extend({  
  model: function() {
    return this.store.find('book', {
      orderBy: 'title',
    });
  },
});

So, now that the route is set up, we can edit the template file for the books route to display a list of all the current books. Obviously there won't be anything to list yet, as we will be adding the data when the books/new template is written.

// templates/books.hbs
<div class="col-md-6 col-md-offset-3">  
  {{outlet}}
  <section>
    <h2>Book List</h2>
    {{#each model as |book|}}
    <p>
      <span><strong>{{book.title}}</strong> - <em>{{book.author}}</em> - {{book.pubYear}}</span>
      <button class="btn btn-danger" {{action "deleteBook" book}}>Delete</button>
    </p>
    {{/each}}
  </section>
</div>  

Now let's create the books/new.hbs file, which will display a form where we can enter the details of a new book.

// templates/books/new.hbs
<h2 id="newBook">New Book</h2>  
<form>  
  <div class="form-group">
    <label for="titleInput">Title</label>
    {{input value=title placeholder="Title" class="form-control" id="titleInput"}}
  </div>
  <div class="form-group">
    <label for="authorInput">Author</label>
    {{input value=author placeholder="Author" class="form-control" id="authorInput"}}
  </div>
  <div class="form-group">
    <label for="yearInput">Publish Year</label>
    {{input value=pubYear placeholder="Publish Year" class="form-control" id="yearInput"}}
  </div>
  <button {{action "publishBook"}} class="btn btn-default">Publish</button>
</form>  

Setting Actions with Controllers

So, now if you view the app in the browser, we should see any empty page for the books list at localhost:4200/books and a form for entering in new books at localhost:4200/books/new.

empty-form

The buttons we created for adding and deleting book records aren't working yet, so we'll need to generate controllers to manage the behaviour of the 'actions' we set on the templates.

$ ember generate controller books
$ ember generate controller books/new

The books controller will contain the behaviour for the deleteBook action. This will delete the selected record from the database and then save the current state.

// controllers/books.js
import Ember from 'ember';  
export default Ember.Controller.extend({  
  actions: {
    deleteBook(book) {
      book.deleteRecord();
      book.save();
    },
  },
});

The books/new controller will contain the publishBook action. This will create a new book record in the database and assign each of the entered values to the model. It will then save the record and transition to the books route to display the list.

// controllers/books/new.js
import Ember from 'ember';  
export default Ember.Controller.extend({  
  actions: {
    publishBook: function() {
      var newBook = this.store.createRecord('book', {
        title: this.get('title'),
        author: this.get('author'),
        pubYear: this.get('pubYear'),
      });
      newBook.save();
      this.transitionTo('books');
    },
  },
});

Displaying the Data

Now we should be able to add new books to the Firebase database, view the list of all books we have stored, and delete any unwanted books from the list. If you head over to http://localhost:4200/books/new you will be able to enter a new book into the database.

books-list

You can also view the stored data at https://<YOUR-APP-NAME>.firebaseio.com/. The data can also be managed here as well, so we could add, delete, and even edit existing records from the Firebase dashboard.

firebase-db

Adding or deleting records with our app's form or in the Firebase dashboard will live-update in both instances, which is really useful for managing our data.

To Be Continued...

So, we've successfully built a working Ember Data app which uses Firebase as the backend/database. There are lots more useful features of Firebase that can be implemented with Ember such as querying data, defining relationships between models and implementing user authentication.

I'm going to continue with using Ember and Firebase and, in the near future, write some more about setting up user authentication and deploying to Firebase with this books app example. Hopefully this article was useful, and if you have any questions feel free to tweet me.

Further Reading

comments powered by Disqus