This post was originally published on Mozilla Hacks.
In Telenor Digital we decided to build a ready-to-go application framework that deals with these shortcomings, built on top of AngularJS, the MVW framework by Google. The template is the result of iterating over our internal applications that we built for Firefox OS, and addresses the following things:
- Built on top of AngularJS, that has provides data binding; templating; routes; and code structure
- Built in set of UI components
and transitions, in the style of Firefox OS
- Ability to publish apps as a mobile web page (hosted app),
or as a packaged app for the Firefox OS marketplace
- Offline first approach. Every app built on top of the template works offline,
also when hosted on your own web server.
- A build system to create release builds with one command,
that does minification and template caching for optimal performance
Let’s look at how the demo application looks like. It’s a standard CRUD app that shows a list-detail pattern: http://janjongboom.com/ffos-list-detail/. You can click on items to go to the detail view, you can edit items, or add new items. The ‘+’ button is an install button (only visible in Firefox) and allows you to add the app to your phone (Android / FxOS).
Getting the code
To start building, do this:
git clone firstname.lastname@example.org:comoyo/ffos-list-detail.git
- Now you can open
www/index.htmlin any browser, or use the app manager and add the
wwwfolder as a packaged app.
The application lives in the www/ folder, and is made up of the following subfolders:
- components/, third party libraries, loaded through bower
- css/, style sheets. List all styles used by your app in
They will be combined into one big stylesheet, for optimal performance.
- img/, holds the icons for the app in three formats.
- js/, our code
- controllers/, the code that binds data to our UI
- lib/, external libraries that are not in bower
- services/, data providers, or code that is not bound to UI
- app.js, starting point of the application, contains global configuration like routes
- main.js, bootstrap file based on RequireJS.
- views/, view templates
- index.html, bootstrap file where we load the application. You probably never will touch this.
- manifest.appcache, AppCache file.
You’ll need to list all the images & other resources (other than CSS/JS) that your app needs here,
to enable offline for hosted applications.
- manifest.webapp, Firefox OS App manifest file.
You don’t need any build chain set up during development, you can just edit files in www, and refresh index.html at will. That’s the power of the web :-) Of course if you’re developing in the app manager, press UPDATE to refresh the app.
Now let’s add some new functionality to this application, so we can see how developing new features works in practice.
Adding a new button
Let’s say that we want to add a credits screen that shows who built the application. First thing we need to do is add a button somewhere. In our case let’s put it on the home screen of the app. The code of the view is in
The components that you see come from the Firefox OS Building Blocks, which are the same blocks that are used to build Firefox OS itself. Let’s add a new button at the bottom of the screen (below
</ul> and the
<a class="recommend" role="button" ng-tap="go('/credits', 'popup')">Credits</a>
Important here is the
ng-tap attribute. When we tap this item we go to
/credits URL, with animation
popup. There are four built in animations:
but you can create your own using simple CSS.
Now when we look at this it doesn’t look like a button yet, because we didn’t tell that we needed the button building block. Go to
css/main.css and add the following line to make it look nice:
All this is always documented on the page on the Building Blocks website.
Hooking it up
When we click on the button nothing happens though (well, we get redirected back to the list view), and that’s because we don’t listen on the /credits URL yet. To fix that we need to create a route handler (like in any MV* server side framework as well).
Open the list of routes in
js/app.js, and add a handler for the credits URL (before the
Here we tell which controller we want to consult (with JS code), and which view (with HTML) belongs to that. Let’s create the view first. Add a new file called credits.html in the
To style this view we can add some content in
css/app.css, f.e. add some padding and make the text bigger:
Now write a simple controller to fill the content of
, using standard AngularJS data binding. Add a new file called
Last thing is to tell RequireJS that we have a new JS file that needs to be included in our builds, by editing
js/main.js and adding a line above
When we now click the button in the app, everything works as expected. The view pops in, we have data, and we can dismiss by clicking the back button. What’s also great is that when you send the URL to someone else (f.e. http://your/url/index.html#/credits) they will go to the same view by default. That’s because we do proper state management through URLs by default.
Talking to a third party data source
The app currently only talks static data, so we want to hook it up to a real data source. In our case the project list should come from GitHub’s page with projects by mozilla-b2g. They have an API at: https://api.github.com/users/mozilla-b2g/repos.
AngularJS has an idea of services, that abstract data away from your controller. For this app we have a database service that currently returns in-mem data. We can modify the service to talk to a web service instead. Clear out
www/js/services/database.js and replace the content with:
This API is now asynchronous though, but that doesn’t matter for Angular. If you data-bind to a promise, Angular will wait until the promise resolves until data binding happens.
The beauty here is now that even when there is no Internet connection, the data will still load (as long as it was loaded at least once), and the data is auto-cached. No need for the controller to worry about that.
Publishing the app
These were two ways we quickly added some functionality to this application. First, adding a new button and a new view; and second, showing data binding and offline caching of server data. Please note that this application template can be used for much more than just list->detail applications, you’ve got the whole power of AngularJS at your hands!
Now when we want to share this application with the rest of the world, we can go two ways:
- Create a hosted application. This is an app that lives on your own server, like any mobile website. Hosted apps can still be published on the marketplace, and will work offline, but cannot use all the APIs in Firefox OS due to security limitations.
- Create a packaged application. This is a ZIP file, similar to APK files on Android, that contain all the assets of your app, and are distributed through the marketplace.
Both of these applications can be generated using our build script. The script will create a new folder
dist/ that lists all the files the app needs. If you want to publish the app to your own server, just copy over the contents of the
folder. If you want to publish the app as a packaged app, ZIP up the content and publish to the marketplace.
To build, run:
node build.js appcache
There are 8 comments on this article, read them on Mozilla Hacks.