4
\$\begingroup\$

In my Rails 4 app I have this event listener:

$('.remove-tag-button').on('click', function () {
    $.ajax({
      type: "POST",
      data: {id: <%= @item.id %>, tag: $(this).data("tag-name")},
      url: "/remove_tag"
    });
  });

in three places and I'm wondering if there's a way to refactor.

I have an items controller with some actions including show, add_tag, and remove_tag.

def show
  @item= Item.find_by_id(params[:id])
end

def add_tag
  (omitted for brevity)
  respond_to do |format|
    format.js
end

def remove_tag
  (omitted for brevity)
  respond_to do |format|
    format.js
end

My show.html.erb has a form with a button to remove tags (class="remove-tag-button") that the event listener is referring to. I have the listener inside script tags at the bottom of my show.html.erb (inside a $(document).ready()) and also inside my add_tag.js.erb and remove_tag.js.erb.

show.html.erb

<div id="taglist">
  <%= render partial: 'items/tag_list', locals: {item: @item} %>
 </div>
 <form action="<%= add_tag_path %>" method="post" id="custom-tag" class="input-group" autocomplete="off" data-remote="true">
   <%= text_field_tag :tag, nil, placeholder: 'Add tag', class: "form-control typeahead", id: 'add-tag' %>
   <span class="input-group-btn">
     <%= submit_tag 'Add', id: "add-button", class: "btn btn-default" %>
    </span>
 </form>
<script>
$(document).ready(function(){

  $('.remove-tag-button').on('click', function () {
    $.ajax({
      type: "POST",
      data: {id: <%= @item.id %>, tag: $(this).data("tag-name")},
      url: "/remove_tag"
    });
  });
});
</script>

add_tag.js.erb

$("#taglist").html('<%= escape_javascript(render partial: "items/tag_list", locals: {item: @item}) %>');

$('.remove-tag-button').on('click', function () {
  $.ajax({
    type: "POST",
    data: {id: <%= @item.id %>, tag: $(this).data("tag-name")},
    url: "/remove_tag"
  });
});

remove_tag.js.erb

$("#taglist").html('<%= escape_javascript(render partial: "items/tag_list", locals: {item: @item}) %>');

$('.remove-tag-button').on('click', function () {
  $.ajax({
    type: "POST",
    data: {id: <%= @item.id %>, tag: $(this).data("tag-name")},
    url: "/remove_tag"
  });
});

items/_tag_list.html.erb

<% item.all_tags_list.each do |t| %>
  <span class="tag-container">
    <%= link_to t, tag_path(t), class: "item-tag" %>
    <% if item.tags_from(current_user).include?(t) %>
      <span>
        <%= link_to "×", '', class: "remove-tag-button", :'data-tag-name' => t, remote: true %>
      </span>
    <% end %>
  </span>
<% end %>

I have 3 instances of this code because a user needs to be able to add and remove tags through AJAX requests while on the page. So it listens when the page loads, then I need it to still be listening after a user has added and/or removed a tag (both which are done through AJAX).

This seems sloppy. I'm wondering if theres a better way to do it.

\$\endgroup\$
1
\$\begingroup\$

I was able to get rid of the duplicate code by using event delegation. I changed my event listener to:

$('#taglist').on('click', '.remove-tag-button', function () {
    $.ajax({
      type: "POST",
      data: {id: <%= @item.id %>, tag: $(this).data("tag-name")},
      url: "/remove_tag"
    });
  });
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.