A long-lived project that still receives updates
An Active Admin plugin to add dynamic behaviors to fields
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 2.4

Runtime

>= 2.0, < 4
 Project Readme

ActiveAdmin Dynamic Fields

gem version gem downloads linters specs

An Active Admin plugin to add dynamic behaviors to some fields.

Features:

  • set conditional checks on fields
  • trigger actions on target elements
  • inline field editing
  • create links to load some content in a dialog

The easiest way to show how this plugin works is looking the examples below.

Please ⭐ if you like it.

Install

First, add the gem to your ActiveAdmin project: gem 'activeadmin_dynamic_fields' (and execute bundle)

If you installed Active Admin without Webpacker support:

  • add at the end of your ActiveAdmin javascripts (app/assets/javascripts/active_admin.js):
//= require activeadmin/dynamic_fields

Otherwise with Webpacker:

  • Execute in your project root:
yarn add blocknotes/activeadmin_dynamic_fields
  • Add to your app/javascript/packs/active_admin.js:
require('activeadmin_dynamic_fields')

Options

Options are passed to fields using input_html parameter as data attributes.

Conditions:

  • data-if: check a condition, values:
    • checked: check if a checkbox is checked (ex. "data-if": "checked")
    • not_checked: check if a checkbox is not checked (equivalent to "data-if": "!checked")
    • blank: check if a field is blank
    • not_blank: check if a field is not blank
    • changed: check if the value of an input is changed (dirty)
  • data-eq: check if a field has a specific value (ex. "data-eq": "42" or "data-eq": "!5")
  • data-not: check if a field has not a specific value (equivalent to "data-eq": "!something")
  • data-match: check if a field match a regexp
  • data-mismatch: check if a field doesn't match a regexp (ex. "data-mismatch": "^\d+$")
  • data-function: check the return value of a custom function (ex. "data-function": "my_check")

Actions:

  • data-then: action to trigger (alias data-action), values:
    • hide: hides elements (ex. "data-then": "hide", "data-target": ".errors")
    • slide: hides elements (using sliding)
    • fade: hides elements (using fading)
    • addClass: adds classes (ex. "data-then": "addClass red")
    • addStyle: adds some styles (ex. "data-then": "addStyle color: #fb1; font-size: 12px")
    • setText: set the text of an element (ex. "data-then": "setText A sample text")
    • setValue: set the value of an input element (ex. "data-then": "setValue A sample value")
    • callback: call a function (with arguments: data-args) (ex. "data-then": "callback a_fun")
  • data-else: action to trigger when the condition check is not true
  • data-args: arguments passed to the callback function

Targets:

  • data-target: target css selector (from parent fieldset, look for the closest match)
  • data-gtarget: target css selector globally

A check condition or a custom check function are required. A trigger action is required too, unless you are using a custom function (in that case it is optional).

Examples

Dynamic fields examples

  • A checkbox that hides other fields if is checked (ex. model Article):
form do |f|
  f.inputs 'Article' do
    f.input :published, input_html: { data: { if: 'checked', then: 'hide', target: '.grp1' } }
    f.input :online_date, wrapper_html: { class: 'grp1' }
    f.input :draft_notes, wrapper_html: { class: 'grp1' }
  end
  f.actions
end
  • Add 3 classes (first, second, third) if a checkbox is not checked, else add "forth" class:
data = { if: 'not_checked', then: 'addClass first second third', target: '.grp1', else: 'addClass forth' }
f.input :published, input_html: { data: data }
  • Set another field value if a string field is blank:
f.input :title, input_html: { data: { if: 'blank', then: 'setValue 10', target: '#article_position' } }
  • Use a custom function for conditional check (title_not_empty() must be available on global scope) (with alternative syntax for data attributes):
attrs = { 'data-function': 'title_empty', 'data-then': 'slide', 'data-target': '#article_description_input' }
f.input :title, input_html: attrs
function title_empty(el) {
  return ($('#article_title').val().trim() === '');
}
  • Call a callback function as action:
data = { if: 'checked', then: 'callback set_title', args: '["Unpublished !"]' }
f.input :published, input_html: { data: data }
function set_title(args) {
  if($('#article_title').val().trim() === '') {
    $('#article_title').val(args[0]);
    $('#article_title').trigger('change');
  }
}
  • Custom function without action:
collection = [['Cat 1', 'cat1'], ['Cat 2', 'cat2'], ['Cat 3', 'cat3']]
f2.input :category, as: :select, collection: collection, input_html: { 'data-function': 'on_change_category' }
function on_change_category(el) {
  var target = el.closest('fieldset').find('.pub');
  target.prop('checked', (el.val() == 'cat2');
  target.trigger('change');
}

Inline editing examples

  • Prepare a custom member action to save data, an update helper function is available (third parameter is optional, allow to filter using strong parameters):
member_action :save, method: [:post] do
  render ActiveAdmin::DynamicFields.update(resource, params)
  # render ActiveAdmin::DynamicFields.update(resource, params, [:published])
  # render ActiveAdmin::DynamicFields.update(resource, params, Article::permit_params)
end
  • In index config:
# Edit a string:
column :title do |row|
  div row.title, ActiveAdmin::DynamicFields.edit_string(:title, save_admin_article_path(row.id))
end
# Edit a boolean:
column :published do |row|
  status_tag row.published, ActiveAdmin::DynamicFields.edit_boolean(:published, save_admin_article_path(row.id), row.published)
end
# Edit a select ([''] allow to have a blank value):
column :author do |row|
  select ActiveAdmin::DynamicFields.edit_select(:author_id, save_admin_article_path(row.id)) do
    options_for_select([''] + Author.pluck(:name, :id), row.author_id)
  end
end
  • In show config (inside attributes_table block):
row :title do |row|
  div row.title, ActiveAdmin::DynamicFields.edit_string(:title, save_admin_article_path(row.id))
end

Dialog example

Example with 2 models: Author and Article

Prepare the content dialog - in Active Admin Author config:

ActiveAdmin.register Author do
  # ...
  member_action :dialog do
    record = resource
    context = Arbre::Context.new do
      dl do
        %i[name age created_at].each do |field|
          dt "#{Author.human_attribute_name(field)}:"
          dd record[field]
        end
      end
    end
    render plain: context
  end
  # ...
end

Add a link to show the dialog - in Active Admin Article config:

ActiveAdmin.register Article do
  # ...
  show do |object|
    attributes_table do
      # ...
      row :author do
        link_to object.author.name, dialog_admin_author_path(object.author), title: object.author.name, 'data-df-dialog': true, 'data-df-icon': true
      end
    end
  end
  # ...
end

The link url is loaded via AJAX before opening the dialog.

Do you like it? Star it!

If you use this component just star it. A developer is more motivated to improve a project when there is some interest. My other Active Admin components.

Or consider offering me a coffee, it's a small thing but it is greatly appreciated: about me.

Contributors

  • Mattia Roccoberton: author
  • The good guys that opened issues and pull requests from time to time

License

The gem is available as open-source under the terms of the MIT.