Tips and tricks on using AngularJS with Parse.com

4-meals
Louise Parker iOS application by Tumba Solutions

Recently the team at Tumba delivered a solution for a weight loss company supporting clients worldwide. The solution consisted of an iOS application through which a client enters their data and a web application through which a nutritionist supervises the client regime. Nutritionists have also the ability to add recipes for the clients.

The solution comprised of a tailor-made iOS application, and a single page web application. Technology-wise we decided to use Parse.com as a backend, cloud storage and web application hosting solution and AngularJS as our javascript MVC framework.

While building the web application we encountered some bits that were not that straight-forward and we believe our recipes for handling these corner cases are worth sharing, hence the birth of this article.

The technological challenges:

  • binding seamlessly Parse.com data to AngularJS $scope with Parse.com JS SDK
  • forcing https redirection when serving the AngularJS application from Parse hosting service
  • painlessly deploying code to Parse, setting up environments for incremental development

Challenge: Binding Parse.com data to AngularJS $scope

The problem:

Parse queries do not bind out of the box to AngularJS $scope property values, because Parse logic is outside of the AngularJS environment. For example the code below will not provide the results we are looking for and $scope.currentArticle property will not update with the result of the Parse query as AngularJS is not subscribed to the Parse events automatically:

A plunkr to play around.

Why not use the Parse REST API instead?

At this point a very logical doubt came to our minds – ‘Why not use the Parse REST API if AngularJS integration with the JS SDK does not come out of the box?’.

A plunkr to play around.

It is pretty much straight-forward as AngularJS is designed to work with a REST API. Headers configuration could be abstracted a bit more, eliminating the need to be written with every endpoint configuration.

The first reason we decided to go with the Parse JS SDK is that Parse team recommends using the correlated SDK for your project. It is a good practice to listen to the words of the developers who have created a product, but nevertheless, we shouldn’t take it for granted, so we looked for more reasons to choose the Parse JS SDK over the Parse REST API:

  • user session and authentication handling out of the box
  • Facebook and Google integration
  • tidy and easy to read query syntax

Our recipe:

Using Parse JS SDK and AngularJS $q service:

The team wanted to steer away from $scope.$apply() (which is a bad pattern, because it internally calls $scope.$digest() which forces digesting of the current scope and all its child scopes). Instead, we use the AngularJS $q service to resolve with Parse data when it is fetched, thus making the data a legal citizen in the AngularJS environment:

A plunkr to play around.

Challenge: Force https redirection for AngularJS application hosted on Parse

The problem:

While Parse API endpoint is served with https, static websites that are deployed onto Parse hosting are not. Since our application is based on AngularJS and all the business logic happens on the client side, from strictly structural point of view, it is considered a static website. In our application there is a sign up/sign in form, so we needed to force https redirection so we wouldn’t present a security breach for the customers.

Our recipe:

The way to force server-side https redirection with Parse-hosted applications is to use the cloud code and Express application that come with Parse hosting and configure the express app to use the parseExpressHttpsRedirect module. (Check out the Parse docs).

The tricky part is that as far as Parse is concerned, the AngularJS application consists of static files. The way Parse serves files is first it checks whether the file is present in the public directory (i.e, if the file is static) and if it is, it serves it, bypassing the Express application and any routing you may have defined there.

As AngularJS resolves the actual routing of the application in a configuration script, the Express app should return the file that calls this configuration script (usually it is index.html) on every get request that is a path to AngularJS route (e.g. /customers/{id}). This means that everything that is not resolved to a static resource (remember that Parse checks if the requested resource is static first and then examines the Express routing defined?) will serve the index.html which would resolve routing as configured in the AngularJS world.

Here is another Parse tip – the sendFile method is not available on the result parameter in the Express get() method (you cannot use res.sendFile('index.html')) as this is a way to serve a static file and Parse already handles that in a different way. Instead we set up the ejs template engine to serve the index.html file as index.ejs template with res.render('cloud/index.ejs'). The content of the index.ejs is exactly like the one in index.html of our AngularJS application. The index.html file should be removed from the public directory, otherwise it will be served as a static resource, bypassing the Express routing. The full code for a working force redirection in cloud/app.js which is required from cloud/main.js via require('cloud/app.js') (Note that app.js and main.js both sit in the cloud directory of the deployment directory):

Challenge: Keeping a maintainable deployment process

The problem:

There is no way to get current artefacts of a deployed application via Parse. So you should (Parse team recommends it themselves) use source control to check in the development files. Remember from the previous recipe that we renamed a file and moved it to the cloud directory? But, to develop the app locally, index.html file is needed as such in the public directory.

Also, in order to set up incremental development process, we need some Test and Production environment deployment configuration.

Our recipe:

Instead of copying and renaming files every time before deployment or push to the remote repository, we took advantage of (if you have followed our previous posts, you should know by now that we are big time fans of) GruntJS and its task automation powers.

Parse deployable structure consists of three directories:cloud, public and config. cloud and public store the cloud and static files respectively. The config directory contains a global.json file that stores the name, id and keys of the Parse application that should be deployed.

deploy-structure

We have written GruntJS tasks for Test and Production deployment that creates a new directory and copies in it the static and cloud files, removing index.html from the public and putting it in the cloud directory as index.ejs so it would be served by the Express app which is needed for the forced https redirection.

The Grunt task also takes care of placing the right config files (containing the app name, id and keys) for the requested environment. So, at the end all that is needed in order to deploy the web application to the particular environment is: