Reputation: 38349
I've got a view for a resource
and some javascript that is specific to it. So, I dutifully put the Javascript in app/assets/javascripts/resource.js.coffee
.
Problem is that when I go to other views in my application I get all kinds of Javascript errors like:
Type issue: 'null' is not an object...
page_url = page_image.getAttribute('src');
app works fine but these scripts, really, shouldn't be trying to run in views they weren't intended for.
Obviously I'm missing something...well...obvious! What is it?
Upvotes: 0
Views: 200
Reputation: 2286
Two suggestions, the first is hacky, the second is awesome.
Create a new JS manifest file for those views that require a different combination of JS, call that manifest file from a new layout, and call the new layout from the controller actions that render those views.
In your example:
app/assets/javascripts/resource.js.coffee
// Requires
//= require_whatever_js_files_your_resource_page_needs_here
// Custom JS below
...
app/views/layouts/resource.html.erb
...
<%# Within your <head> tag %>
<%= javascript_include_tag "resource" %>
...
app/controllers/resources_controller.rb
class ResourceController < ApplicationController
# filters, default layout, other actions, etc.
...
# Your action that needs only the resource JS,
# and therefore the resource layout
def action_that_only_uses_resource_js
@some_objects = SomeObjects.all
render layout: 'resource' # <- This is the important part
end
Obviously this method doesn't scale particularly well because it isn't flexible i.e., you can't combine your JS as you'd like and will no doubt need. Which brings us to breaking your JS into...
Integrate RequireJs into Rails using this gem. You'll get the modularity you're looking for and prevent conflicts from happening. RequireJs employs the AMD pattern which I believe is what you're looking for.
Upvotes: 0
Reputation: 84114
There's nothing baked into rails for only running some javascript on some pages. The approach I take is based on this post
Each of my page specific coffeescript files looks like
window.App.controller_name =
init: ->
#stuff that happens for all actions
edit: ->
#Stuff that happens only for the edit action
The body element is decorated with data-controller and data-action attributes. Some javascript in application.js then runs the appropriate javascript:
execute_hook = (controller, action='init') ->
ns = window.App
if controller?
if ns[controller] && typeof(ns[controller][action]) == "function"
ns[toplevel][controller][action]()
jQuery ->
body = document.body
controller = body.getAttribute("data-controller")
action = body.getAttribute("data-action")
execute_hook(controller)
execute_hook(controller, action)
Upvotes: 1
Reputation: 11520
By default, application.js
includes all the scripts in app/assets/javascripts
, and by default, your layout includes all these scripts. This has the advantage that the browser has to make only one request for Javascript files, which can then be cached -- but the disadvantage that all your Javascript runs on every page.
There are two basic solutions:
application.js
to not include everything, include individual Javascript files when you need them, and change config.assets.precompile
to include all your new top-level files.Upvotes: 2