19

I put the following function in my application.js:

function test() {
  alert("See Me")
}

classrooms/_new_small.html.haml:

:javascript
  alert('test');
  test();

In my application.html.haml I'm using the following:

= javascript_include_tag 'application'

I'm getting a test is not defined error in my firebug console. Isn't the test function supposed to be available project-wide because its in the application.js file? Thanks

edit: I'm rendering the page via javascript. Would that affect it?

$('#test_container').html("<%= escape_javascript(render :partial => 'classrooms/new_small') %>");
perseverance
  • 6,372
  • 12
  • 49
  • 68
  • yes it should be, can you post your partial? – Trent Earl Dec 31 '12 at 00:53
  • Just updated it with the partial code that is calling the function. – perseverance Dec 31 '12 at 01:04
  • Are you sure your controller is rendering a layout that includes `application.js` ? – Jef Jan 05 '13 at 01:09
  • Why the partial and not just the javascript in your response? – Reuben Mallaby Jan 06 '13 at 20:09
  • Is your `javascript_include_tag` in your ``, or is it at the end of your ``? If it appears at the end of your ``, (i.e.: *after* you try to call it from your view), then it won't have been defined yet. Try replacing your call to `test()` with `$(function () { test() });` to see if it succeeds. – Matt Huggins Jan 07 '13 at 20:09

7 Answers7

28

Assuming you are using asset pipeline & coffeescript: Don't write code in application.js

In order to keep clean structure, create a folder (eg: application) in app/assets/javascripts

then require it in your application.js

//= require jquery
//= require jquery_ujs

//= require_tree ./application

Create a coffee file (eg: app/assets/javascripts/application/my_feature.js.coffee

@test = ->
  alert('Hello world')

Coffee output:

(function() {

  this.test = function() {
    return alert('Hello world');
  };

}).call(this);

It's preferable to use namespaces:

@myGreatFeature =
  test: ->
    alert('Hello world')

or according to the coffeescript FAQ, you could write

namespace = (target, name, block) ->
  [target, name, block] = [(if typeof exports isnt 'undefined' then exports else window), arguments...] if arguments.length < 3
  top    = target
  target = target[item] or= {} for item in name.split '.'
  block target, top

namespace 'myGreatFeature', (exports) ->
  exports.test = ->
    alert('Hello world')

then you can call myGreatFeature.test() everywhere

m4tm4t
  • 2,361
  • 1
  • 21
  • 37
  • How is Coffeescript directly relevant? – JackHasaKeyboard Jun 16 '17 at 06:46
  • @JackHasaKeyboard Perhaps it is not directly relevant, but it seems at least indirectly relevant as "Rails ships with CoffeeScript by default" per https://guides.rubyonrails.org/working_with_javascript_in_rails.html. – CFitz Mar 21 '19 at 20:52
1

Simple solution, remove escape_javascript, but it's dangerous see Why escape_javascript before rendering a partial? . Currently you want to execute

$('#test_container').html("<script>
//<![CDATA[
 alert('test');
 test();
//]]>
</script>

which is converted into

$('#test_container').html("<script>\n  //<![CDATA[\n    alert(\'test\');\n    test();\n  //]]>\n<\/script>\n");

How do i solve this problem ?

i will include project_wide.js in app/assets/javascripts/ and then tell application.js to include my file .

//= require project_wide

Be sure to put the above line after

//= require jquery
//= require jquery_ujs

Now, whatever i put in app/assets/javascripts/project_wide.js it will shamelessly appear in whole project except the files which are in public/ folder . In this file, i will put everything which i want to execute .

Follow common practice

Currently,you are adding javascript directly inside classrooms/_new_small.html.haml which is uncommon. Mostly , rails developer put such things in assets/javascripts/*.js or call content_for :javascript_custom block in views , which is added in layout file by yield :javascript_custom

Community
  • 1
  • 1
Paritosh Piplewar
  • 7,982
  • 5
  • 26
  • 41
1

I tried this without an issue. Here's how I did it.

// application.js

var test=function(){
  alert("hello");
}

// in a view, whichever one, i have a content_for :additional_javascripts

<% content_for :additional_javascripts do %>
  <%= javascript_tag do %>
    test();
  <% end %>
<% end %>

// in application layout

<%= javascript_include_tag "application" %>
<%= yeild(:additional_javascripts) %>

Furthermore, if I want to alert this dynamically later on I could append it to the page and call it then, or put it in a click listener or something.

I like the syntax var functionName = function(){...} because it properly scopes the method. Also, because of the way javascripts are compiled through the asset pipeline, adding the ; at the end of every executed line is very important.

This also worked for me as far as loading the script dynamically and calling it from anywhere in the page:

$("#click_me").live("click", function(){
  $("<script />").text("test();").appendTo("body");
});

And in the page I had a simple link.

<a href="#" id="click_me">click</a>
Jeff Ancel
  • 3,076
  • 3
  • 32
  • 39
0

You're probably thinking of the line

= javascript_include_tag "application"

rather than

= stylesheet_link_tag 'application', :media => 'all'

If the former is missing, your javascript won't be included.

Dan Wich
  • 4,923
  • 1
  • 26
  • 22
0

Try using:

<%= javascript_include_tag :all %>

in your application.html.erb file

Michael Durrant
  • 93,410
  • 97
  • 333
  • 497
0

I noticed your function test() is indented, which suggests it is nested. If you define a function in the scope of another function, it will not be available outside of it.

For example this should work, using jQuery:

function test() { /* do something */ }

// another file or inline script

$(function() {
   test();
});

But this won't

(function() {
   function test() {}
})();

// another file

test(); // undefined
AJcodez
  • 31,780
  • 20
  • 84
  • 118
  • Thanks for looking but its not indented in the actual code. Cutting and pasting in into stackoverflow caused the indent. – perseverance Jan 02 '13 at 04:27
0

put all those javascript functions in application.js file and include <%= javascript_include_tag 'application' %> in head tag of your layout file

shweta
  • 8,019
  • 1
  • 40
  • 43