Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 4 + Turbolinks + JQuery Turbolinks + Coffeescript: Events being fired multiple times

At first, all the javascript bounded are running pretty well.

However, from the moment I navigate to another page, any event is being fired multiple times. If I refresh the page, everything is back to normal.

In the jquery.turbolink docs, there is an alert about binding the document events inside a $(function()) block. However, seems like the coffescript works like this by default. So, what should I do?

This is my environment:

Gemfile:

gem 'turbolinks'
gem 'jquery-turbolinks'

application.js

//= require jquery
//= require jquery.turbolinks
//..app js
//= require turbolinks

application.html.erb

<html>
  <head>
    <meta charset="utf-8">
    <title><%= t 'brand' %> </title>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
    <%= yield :head %>
    <%= csrf_meta_tags %>
    <meta name="description" content="<%= yield :page_description %>">
    <meta name="keywords" content="<%= yield :page_keywords %>">
  </head>

controller.js.coffee

$(document).ready ->    
  $(document).on 'click', '.addition .label i', (e) ->
    console.log ".addition .label i 'click' fired!"

The thing is, apparently the javascript file generated by coffeescript IS inside a block by default. Check it out:

controller.js (generated by coffeescript)

function() {
  $(document).ready(function() {
    $(document).on('click', '.addition .label i', function(e) {
      console.log(".addition .label i 'click' fired!");
    });
...

So, what should I do to use coffeescript + JQuery Turbolinks properly? Should I make a different configuration?

Cheers.

like image 867
Rogério R. Alcântara Avatar asked May 08 '14 07:05

Rogério R. Alcântara


2 Answers

The problem is in controller.js.coffee.

You wrote this:

$(document).ready ->    
  $(document).on 'click', '.addition .label i', (e) ->
    console.log ".addition .label i 'click' fired!"

But since you're using jQuery Turbolinks, you need to move the event handlers outside the $(document).ready function:

$(document).ready ->
  # Other code can go here, but not binding event handlers
$(document).on 'click', '.addition .label i', (e) ->
  console.log ".addition .label i 'click' fired!"

Take a look at the jQuery Turbolinks README. It mentions this problem and solution. (Search the readme for "Events firing twice or more.")

like image 198
Brian Morearty Avatar answered Nov 05 '22 21:11

Brian Morearty


Well, it turned out that I've changed the approach completely.

Now, I've got exactly the same environment, but I'm using classes to represent the javascript for each controller. Here is one example:

foo.js.coffee:

window.App or= {}

class App.Foo
  constructor: ->
    @$foo_container = $('.foo')
    @bind()

  bind: ->
    console.log 'App.Foo.bind has been fired!'
    @$foo_container.on 'click', '.label i', @foo_clicked

  foo_clicked: (e) =>
    console.log 'App.Foo.foo_clicked has been fired!'
    alert '.label i has been clicked!'

create_foo = ->
  window.app.foo = new App.Foo()
  console.log 'App.Foo has been created!'

$(document).ready create_foo

Now, it works like a charm. :)

like image 1
Rogério R. Alcântara Avatar answered Nov 05 '22 21:11

Rogério R. Alcântara