Easily bind AngularJS scope properties to your URL hash.
In simpler terms, if you have a property called user
on your scope, with a value of {firstName: 'John', lastName: 'Doe'}
, and you bind it to the URL, your URL hash will be something resembling #?user=~(firstName~'John~lastName~'Doe)
. When the state of $scope.user changes, the URL hash will change with it. If the page is loaded or reloaded with a valid hash, the state from the hash will be transferred to the $scope.user property on load.
See a simple example or an advanced example.
AngularJS's two-way binding allows you to bind data from a model to the DOM and back. ngUrlBind allows you to additionally bind data from an AngularJS model to the URL hash and back. Does that make it four-way binding?
While the whole Single-Page App thing is new and trendy, ngUrlBind is inspired by the "Hypermedia as the Engine of Application State" principle, one of the core components of REST's Uniform Interface constraint.
ngUrlBind is useful during development where you want to be able to hit refresh on your browser (or use livereload) without having AngularJS lose its scope state, or at least certain parts of it.
Subject to the limitations noted below, it is also useful in production, if you want your users to persist and exchange certain aspects of Angular's state. For instance think about exchange of URLs over email of IM, or just simple bookmarking.
We have made this as it's useful to us in both of these cases and are making it available to anyone else who may find it useful.
ngUrlBind's principle of operation is simple. Selected model properties are reflected to the URL hash as the AngularJS application is being used. They are then seeded back to the model when the page is loaded with the appropriate hash. We use the very elegant jsurl to serialise JSON data to the URL as it becomes both more readable and shorter than using Base64.
All you need is to inject the ngUrlBind service into your controller and call
ngUrlBind($scope, 'propertyName')
That's it. This will bind the user property of your current controller's scope to the URL hash.
Important: For the moment, only first-level properties are supported. So no dots in the 'propertyName' argument. Feel free to investigate and remove this limitation, pull requestes welcome.
Here's a more complete example:
angular.module('ngUrlBindExample', ['ngUrlBind'])
.controller('mainCtrl', function($scope, ngUrlBind){
$scope.user = {}
ngUrlBind($scope, 'user')
})
This will bind the state of the user property to the URL hash. Refreshing the page will restore the state of the user object through the URL hash.
A major limitation is that ngUrlBind doesn't play well with AngularJS routing. We're fairly confident this can be remedied, but haven't had the need for now.
Another limitation is that the first user action creates a hash, which adds a step to the user's history. By strict HATEOAS this is correct, but this should probably be improved for the sake of UX and practicality.
ngUrlBind is not for everything, and it's not for everywhere. But it's got its uses.
I haven't done any performance testing, but I wouldn't be surprised if it wasn't fantastic at this point. In object.Observe() we trust.
bower install ngUrlBind
make sure ngUrlBind/dist/ngUrlBind.js is loaded before your angular module. ngUrlBind is wrapped in the Universal Module Definition so it supports AMD, CommonJS, and plain ol' global declaration via script tag.
Make your angular module require the 'ngUrlBind' module and inject the ngUrlBind service into your controller. You're ready to go.
You'll need to clone this repository, have gulp installed globally (via npm install -g gulp
) and then run npm install
.
Once you're set up run gulp build
to convert the source to a js file in /dist or simply run gulp
to build continuously with a watcher. The code in /example points to the version in /dist as a dead-simple way of testing.
At the end of the day this is a simple little module that's been used non-trivially in only one project. There's undoubtedly lots to fix, for which we welcome your pull requests and issues.