Published by Dan on Jul 14, 2016

Loading Buttons

Converting action buttons into loading buttons is a common way for AJAX applications indicate that it's waiting on the server to verify an action and respond.

Filed under Features

Introduction

Loading buttons are a common user-experience concept used to indicate the state between starting and completing an action. They are most useful when server-side logic decides what happens next, such as displaying validation errors or a success message.

Single page applications may bypass loading buttons to appear more responsive since they use client-side logic, but loading buttons still play a large role in the standard MVC Rails application.

  Log out represents an action for the user to perform.

  Log out indicates the action in processing via a loading icon and disabled button.

Demo

Click the buttons below for a live demonstration.

This webpage is not hosted by Rails, so the above UX is just a simulation.
A "Log out" button would normally redirect you to the sign-in page.

How it Works

  1. A Rails helper method renders a button with data-remote=true and data-loading=true attributes.
  2. data-remote=true instructs jquery_ujs.js to begin an ajax request.
  3. data-loading=true instructs a jQuery listener to disable the button and insert a spinner.
  4. Your Rails application determines what happens after the request finishes:
    • Reset the button's state
    • Redirect to another page

The Code

# config/routes.rb
resources :sessions, only: %w(new destroy)

# controllers/sessions_controller.rb
class SessionsController < ApplicationController

  def destroy
    reset_session
  end

end

# helpers/sessions_helper.rb
module SessionsHelper
  def link_to_log_out
    link_to_with_icon('sign-out', 'Log out', url, {
      method: 'DELETE',
      remote: true,
      class: 'btn btn-primary',
      data: {loading: true}
    })
  end
end

# helpers/layouts_helper.rb
module LayoutsHelper
  def link_to_with_icon(icon, title, url, options = {})
    icon = content_tag(:span, nil, class: "fa fa-#{icon}")
    title_with_icon = icon << ' '.html_safe << h(title)
    link_to(title_with_icon, url, options)
  end
end

# Gemfile
gem 'jquery-rails'

// assets/javascript/application.js
//
// jquery_ujs allows us to use 'data-remote',
// 'data-type', and 'data-method' attributes
//
//= require jquery
//= require jquery_ujs
//= require loading

# assets/javascripts/loading.coffee
$ ->
  # Insert a spinner and disable the button
  $(document).on('click', 'a[data-loading]', (e) ->
    $(this).attr('disabled', 'disabled')
    $(this).find('.fa:first').attr('class', 'fa-refresh fa-spin')

<%# views/layouts/application.html.erb %> 
<%= link_to_log_out %> 

/* views/sessions/destroy.js.erb */
Turbolinks.visit("<%= new_session_path %>");

Wrap-up

The Rails code is rather boring, but two important user-experience concepts occur on the frontend:

  1. Disabling the button prevents duplicate submissions.
  2. Using a loading spinner lets the user know we started performing the action.

For further reading, my AJAX Toggle Buttons article builds on these concepts to implement an on/off feature for buttons.

Dan

© 2012-2018 Dan Cunning. All rights reserved.