Activeadmin: Adding custom javascript

Created on 4 Aug 2011  路  31Comments  路  Source: activeadmin/activeadmin

I was wondering if there was a mechanism for adding custom javascript to the admin UI?
Was thinking it might be a useful way of injecting features without requiring massive updates of the ruby code?

An example would be adding a plugin like jquery chosen [http://harvesthq.github.com/chosen/] to enhance certain filters and drop downs on forms.

Most helpful comment

just check the active_admin.rb file

# config/active_admin.rb

# == Register Stylesheets & Javascripts
#
# We recommend using the built in Active Admin layout and loading
# up your own stylesheets / javascripts to customize the look
# and feel.
#
# To load a stylesheet:
  config.register_stylesheet 'my_stylesheet.css'
#
# To load a javascript file:
  config.register_javascript 'my_javascript.js'

All 31 comments

There is such mechanism, all you need to do is read the docs or browse to the config file in your project

right, awesome, cheers

is there other documentation than here: http://activeadmin.info/documentation.html

just check the active_admin.rb file

# config/active_admin.rb

# == Register Stylesheets & Javascripts
#
# We recommend using the built in Active Admin layout and loading
# up your own stylesheets / javascripts to customize the look
# and feel.
#
# To load a stylesheet:
  config.register_stylesheet 'my_stylesheet.css'
#
# To load a javascript file:
  config.register_javascript 'my_javascript.js'

How would you do this on certain pages only though?

It would indeed be lovely to be able to insert javascript on only certain pages. @wejrowski did you come up with a good solution?

No I have not.. I basically just have a bunch of jquery that applies events and changes to specific elements that won't get called if they don't exist.

would love to see a possibilty to include js only on certain pages/views! :)

+1 for per-page javascript/css

+1 for per-page javascript/css too...

+1 for per-page javascript/css

+1 for per-page javascript/css

You guys do realize that this is the going against rails best practices, right? The asset pipeline compiles all of your JS into a single file so it's more efficient for the client to grab. If you still want this feature, you can always call javascript_include_tag from a partial.

Note that you can also scope JS to only act upon pages based on the URL (document.location.href).

Last of all, here's some info specific to the asset pipeline.

Understood. The scoping is what I started to do, but then I found a way to achieve what I needed without any JavaScript.

@haikoschol can you share your solution here?
I also tried to use Paul Irish's solution but i don't know if there is a way to add those data-* to the body element of active admin.
http://viget.com/inspire/extending-paul-irishs-comprehensive-dom-ready-execution

@unrealhoang Unfortunately I don't even remember what exactly the problem was I tried to solve with per-page JavaScript, let alone where to look for my workaround in the code. But it didn't involve any JavaScript, so it probably wouldn't be useful to you anyway.

This is how I manage to run certain piece of javascript per page:

in app/assets/active_admin.js:

//= require jquery
//= require jquery_ujs
//= require jquery-ui
//= require ./init
// = require_tree ./admin

in app/assets/init.js:

// initialize your global object will all your model names
YOUR_APP = {
    contracts:{},
    products:{},
    purchases:{},
    rentals:{},
    users:{}
}

jQuery(document).ready(function($) {
       // get the page action
    var action,model, b = $("body");
    if (b.hasClass("edit")) {
        action = "edit";
    } else if(b.hasClass("view")){
        action = "view";
    } else if(b.hasClass("index")){
        action = "index"
    } else if(b.hasClass("new")){
        action = "new"
    }

        // run the code specific to a model and an action
    for (var m in YOUR_APP) {
        if (b.hasClass("admin_"+m)) {
            if (YOUR_APP[m][action] && typeof YOUR_APP[m][action] == "function") {
                YOUR_APP[m][action]();
                break;
            }
        }
    }
});

And then inside my directory app/assets/admin I have one js file per model with for example for the user model something like that:
in app/assets/admin/user/js

YOUR_APP.users = {
    index: function() { alert("this code run only on the user index page"); },
    view: function() { alert("this code run only on the user view page"); },
    edit: function() { alert("this code run only on the user edit page"); }
};

I hope this will be useful for those who are looking for a solution. It's not the best but it works.

Interesting approach @loicginoux

@unrealhoang this is how I did it: app/admin/layout_hacks.rb

# ruby 2.0 only, visit link below for more information
# http://stackoverflow.com/questions/4470108/when-monkey-patching-a-method-can-you-call-the-overridden-method-from-the-new-i
module ActiveAdmin::Views::Pages::BaseExtension
  def add_classes_to_body
    super
    @body.set_attribute "data-controller", params[:controller].gsub(/^admin\//, '')
    @body.set_attribute "data-action",     params[:action]
  end
end
class ActiveAdmin::Views::Pages::Base
  # mixes in the module directly below the class
  prepend ActiveAdmin::Views::Pages::BaseExtension
end

Compiling the solutions by @batamire and @loicginoux

# app/admin/layout_hacks.rb

module ActiveAdmin::Views::Pages::BaseExtension
  def add_classes_to_body
    super
    @body.set_attribute "data-controller", params[:controller].gsub(/^admin\//, '')
    @body.set_attribute "data-action",     params[:action]
  end
end
class ActiveAdmin::Views::Pages::Base
  # mixes in the module directly below the class
  prepend ActiveAdmin::Views::Pages::BaseExtension
end
# app/assets/javascripts/active_admin.js.coffee

#= require active_admin/base
ActiveAdmin = {
  dashboard: {},
  user: {}
}

ActiveAdmin.dashboard.index = () ->
  console.log 'Hello'

$(() ->
  controller = $('body').data('controller')
  action = $('body').data('action')
  ActiveAdmin[controller][action]() if ActiveAdmin[controller][action]?
)

My hack to add scripts at the top (added at the top of the ActiveAdmin initializer):

Rails.application.config.after_initialize do
  javascripts = [] 
  javascripts << "//maps.googleapis.com/maps/api/js?sensor=false&key="
  javascripts += ActiveAdmin.application.javascripts.to_a
  ActiveAdmin.application.javascripts.replace javascripts
end

@ivanyv You can do this too.

Add in your config/initializers/active_admin.rb.

ActiveAdmin.setup do |config|

  config.register_stylesheet "//cdn.foo.net/example.css"

  config.register_javascript "//cdn.foo.net/example.js"

  # ...
end

@serradura Yeah but that appends the scripts at the bottom and some scripts I need at the top.

@ivanyv I understood now. Thanks for sharing! :smile:

My solution to load additional JS before closing </body> tag, for each controller:

Create file /lib/active_admin/views/footer.rb

module ActiveAdmin
  module Views
    class Footer < Component

      private

      def powered_by_message
        para I18n.t('active_admin.powered_by', active_admin: link_to("Active Admin", "http://www.activeadmin.info"), version: ActiveAdmin::VERSION).html_safe

        if MyApplicationName::Application.assets.find_asset("ui/#{params[:controller]}.js")
          render text: javascript_include_tag("ui/#{params[:controller]}")
        end
      end

    end
  end
end

This will patch AA-view with our code. It includes JS-file it it exists.

For example we have controller /app/admin/customer.rb

ActiveAdmin.register Customer, as: 'Customer' do
  # ...
end

Then create relevant JS-file:
/app/assets/javascripts/ui/admin/customers.js

alert('controller_name is: admin/customers');

This works in development mode.

To get this work in production you need:

  1. in application.js and active_admin.js not to use "require_tree ." (IMPORTANT)
  2. /config/environments/production.rb add this
config.assets.precompile += %w(ui/admin/*.js)

Compile assets with:
RAILS_ENV=production bundle exec rake assets:precompile

My solution:

ActiveAdmin::Views::Pages::Base.class_eval do
  def build_active_admin_head_with_js_script
    build_active_admin_head_without_js_script
    add_js_config_to_head
  end

  def add_js_config_to_head
    within @head do
      script """
      I18n = window.I18n || {};
      I18n.defaultLocale = \"en\";
      I18n.locale = \"#{I18n.locale}\";
      """.html_safe
    end
  end

  alias_method_chain :build_active_admin_head, :js_script
end

Since config.register_javascript now appears deprecated, is there a prescribed mechanism for including an external JS? Specifically google maps, with a key.

I think you may be able to use arbre script tags to link in the google map scripts, and initialize.

for example

    script src: 'url for google maps'

and for inline initialization

    script do
      raw '$(document).ready(function($) {console.log("insert page initialization code here");})'
    end

And if you need to use ruby variables in the script part switch the quotation marks:

script do
    raw "$('.link-delete').bind('ajax:complete', function() {
      $('#content').load('#{customer_id}/customer_data');
    });"
end

Is there a way to add JS per namespace?

@dchersey @rivella50 Thanks for inline js stuff,
Could you please help to append html element from inline js in active admin with "script" helper?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  路  37Comments

seanlinsley picture seanlinsley  路  46Comments

stungeye picture stungeye  路  35Comments

gregbell picture gregbell  路  34Comments

simontol picture simontol  路  28Comments