Rails, AngularJS and jQuery_ujs
Unobtrusive JavaScripts plays well with AngularJS
In the previous post I talked about handling AngularJS CSRF configuration in Rails. But still left one question unresolved, that’s how to make Unobtrusive JavaScripts(UJS) still runs well in AngularJS + Rails environment but without jQuery dependency?
Unobtrusive JavaScripts
First, in rails world, UJS is done by the gem (with javascript assets) called jquery_ujs. It integrated with Rails so well so we’re easily to ignore it. What does it do? Basically when you write:
ul
li= link_to ‘Sign Out’, destroy_user_session_path, method: :delete
somewhere of navigation bar, and it will translate to the html:
<ul>
<li><a href=”/users/sign_out”, data-method=”delete”>Sign Out</a></li>
</ul>
Notice the data-method attribute? It allows user to issue a http DELETE request when user click on the “Sign Out” link, making it simple to deal with a RESTful api.
You can found a typical, real world example on the RubyGems official site:
Unobtrusive Scripting
This technique is so called unobtrusive scripting: using data-attribute to create zero config extra behavior. You can read more on this in the wiki page of jquery_ujs.
However, as its name shows, jquery_ujs depends on jQuery, which is a great library for Document-Based web page. While we’re using angularjs to create Component-Based web app, the removal of jQuery dependency arises. And I planed to write a plugin to replace jquery_ujs after reading it’s source codes.
angular_ujs
It’s also released as a ruby gem, so you can easily use it with Rails and Assets Pipeline (just like jquery_ujs does).
It supports the following features:
1. data-method 2. data-remote (require extra config in angular controllers/htmls) 3. data-confirm
To prevent these directive pollute non-Rails generated attributes, such as form’s method attribute, we’ll check on the element to make sure the attribute is declared with data- prefix before link state of directive.
Form Elements
With data-remote, we want to submit the form with ajax. But angular don’t know how to serialize the form into a json object (there’s no equlvalent $.fn.serializeArray). However, the angular way has already solve this problem with ngModel!!!
For those data you want to send to backend, just give them an ng-model directive. You can bound them to a object and assign the object name as the value of data-remote (As we shown below).
<form accept-charset=”UTF-8" action=”/contact_me” data-remote=”contact” method=”post”>
<input ng-model=”contact.first_name” required=”required” type=”text”>
<input ng-model=”contact.email” required=”required” type=”email”>
<input name=”commit” type=”submit” value=”Submit”>
</form>
Same API, Same Functionalities
We can definitely support all three logic into one element:
<a href=”/confirm” data-confirm=”Are u sure?” data-method=”PUT” data-remote=”true”>
So that it will issue a http PUT ajax request to server when the user click the link and confirm the popup dialog.
Wish you have a nice day with angular_ujs.