Angular Sprinkles

Gem Version Circle CI Coverage Status

Angular Sprinkles is a gem for writing Rails-flavored AngularJS.

  • No frontend setup required: By just requiring it in your project, Sprinkles dynamically generates an Angular application around your Rails templates. It's never been easier to start developing with Angular and Rails.
  • Rails as it was intended to be written: Angular's two-way data binding, directives, and function calls are all done in the view via helper methods, giving you just a sprinkle of JavaScript.
  • A cleaner approach to JavaScript: Sprinkles allows you to continue to write Rails applications as you always have without all of the nasty jQuery spaghetti.

Setup

Add angular_sprinkles to your Gemfile.

gem 'angularjs-rails'
gem 'angular_sprinkles'

Add yield :sprinkles to the bottom of your body tag.

<body>

<%= yield %>

<%= yield :sprinkles %>
</body>

Include and angular_sprinkles into your application.js.

//= require angular_sprinkles
//= require_tree .

Examples

Two-way binding

Two-way binding works right out of the box with Sprinkles. Just wrap your objects with the bindable helper.

class UserController < ApplicationController
  def show
    # bindable gives your objects the bind method
    @user = ng_bindable(User.find(params[:id]))
  end
end
{{ <%= @user.bind(:name) %> }}
<input type="text" ng-model="<%= @user.bind(:name) %>" />

Directives

Use custom directives with the directive helper.

<script>
sprinkles.directive('blink', function () {
  // re-implement the blink tag
});
</script>

<%= ng_directive(:blink) do %>
  Hello, world
<% end %>

Directives can also return it's controller to a ruby block if the directive uses transclusion.

<script>
sprinkles.directive('someDirective', function () {
  return {
    transclude: true,
    template: '<div ng-transclude></div>',
    // note: 'controllerAs' must be the directive name + 'Ctrl'
    controllerAs: 'someDirectiveCtrl',
    controller: function () {
      this.alertMe = function (name) {
        alert('Hi, ' + name);
      };
    }
  }
});
</script>

<%= ng_directive(:someDirective) do |some_ctrl| %>
  <button ng-click="<%= some_ctrl.call('Gabe') %>">CLICK ME!</button>
<% end %>

Controllers and Isolate Scopes

If you would rather skip the directive and just create a controller, there is the ctrl helper.

<script>
sprinkles.controller('someCtrl', function () {
  this.alertMe = function (name) {
    alert('Hi, ' + name);
  };
});
</script>

<%= ng_controller(:someCtrl) do |some_ctrl| %>
  <button ng-click="<%= some_ctrl.call('Gabe') %>">CLICK ME!</button>
<% end %>

This is good for localizing JavaScript behavior. Additionally, if you'd just like to create a new scope, you can use the isolate helper which creates an "anonymous" controller to wrap your element.

<%= ng_isolate do |iso_ctrl| %>
  <input ng-model="<%= iso_ctrl.bind(:isolated_binding) %>">
  {{ <%= iso_ctrl.bind(:isolated_binding) %> }}
<% end %>

In contrast with the bind helper, bindings made here do not apply to the scope of the root controller.

Inlining function calls

Call services directly from the view with the service helper.

<script>
sprinkles.service('alertMe', function () {
  return function (input) {
    alert('Hello, ' + input);
  };
});
</script>

<button ng-click="<%= ng_service(:alert_me, "world") %>">Click me!</button>

Form helpers

Sprinkles comes with helpers for automatically creating bindings with your form elements. Almost all of the usual form helpers are available with the bind_* prefix. (See issue #4 for a list of helpers that are not currently supported).

<%= form_for @user do |f| %>
  <%= f.bind_text_field :name %>
  <%= f.bind_select :age, (1..99) %>
<% end %>

<div>
  <%=# This value is automatically bound to the input of the form %>
  {{ <%= @user.bind(:name) %> }}
</div>

Additionally, the bind_form_for helper will prevent the form from being submitted and bind the form submission to an Angular service.

<script>
sprinkles.service('userFormHandler', function () {
  // receives the object and the AngularJS representation of the form
  return function (user, form) {
    // do something with the result
  };
});
</script>

<%= ng_form_for @user, :user_form_handler do |f| %>
  <%= f.bind_text_field :name %>
<% end %>

I want more!

Also see the demo application for more examples.

Copyright (c) 2014 Gabe Scholz, Brewhouse Software. See LICENSE.txt for further details.