Posting forms with AJAX on checkbox toggle

Posted on November 6, 2011

In a recent Rails 3.1 project, I wanted to have some values updated via AJAX when a checkbox value is checked or unchecked. As I was unable to find anything on the subject online, I figured I would document it here.

Background

I have collections that each have many catalog items. In the collection show view, I want to be able to update a checkbox to indicate whether or not a given catalog item belongs to that collection. In addition, catalog items that are in a collection are highlighted (simply using an “in_collection” CSS class).

HTML markup

  
  
    <div id="collection_content" collection_id="1">
    <div id="catalog_item_id_2">
        <input id="collection_catalog_item_id_2" type="checkbox" value="2"
            name="collection&#91;catalog_item_ids&#93;&#91;&#93;" checked="checked">
        <label for="collection_catalog_item_id_2">In collection</label>
    </div>

    <div>
        <!-- another catalog item -->
    </div>
</div>
  
  

Nothing fancy here, but you’ll notice I included the collection id in the HTML. That is simply because I wanted to include the requisite CoffeeScript in the asset pipeline; therefore, the collection id is made accessible to jQuery by navigating the HTML.

CoffeeScript code

  
  
    @collection_content_updater = () ->
  collection_id = $('#collection_content').attr("collection_id")
  $('#collection_content .collection_check_box').each (index, element) ->
    checkbox = $(element)
    checkbox.click ->
      $.post(
        "/collections/update_item_for_collection"
        catalog_item_id: checkbox.attr("value")
        collection_id: collection_id
        in_collection: checkbox.is(':checked')
        'script'
      )

  
  

Here, we simply add event listeners to check boxes. These listeners will send the info we need to the collections controller, namely: the catalog item, the collection id, and the flag indicating whether or not the catalog item is in the collection. Note you have to use checkbox.is(‘:checked’) to determine whether the checkbox is checked or not, you can’t simply call “checkbox.attr(‘checked’)” as it doesn’t get updated after the HTML is sent to the browser (i.e. (un)checking the checkbox won’t toggle the value).

To actually load this function, we’ll need to add to the CoffeeScript file:

  
  
    
    $(->
      collection_content_updater()
    )
  
    
  

Controller code

  
  
    def update_item_for_collection
  @collection = Collection.find(params[:collection_id])
  @catalog_item = CatalogItem.find(params[:catalog_item_id])
  @item_is_in_catalog = params[:in_collection] == "true"
  if @item_is_in_catalog
  	@collection.catalog_items << @catalog_item unless @collection.catalog_items.include? @catalog_item
  else
  	@collection.catalog_items.delete(@catalog_item)
  end
  @collection.save

  respond_to do |format|
    format.js
  end
end

  
  

Nothing magical here: just retrieve the necessary model instances, update the collection content, and set variables used in the view.

View code

  
  
    
    var $element = $("#catalog_item_#{@catalog_item.id}");
    - if @item_is_in_catalog
      $element.addClass("in_collection");
    - else
      $element.removeClass("in_collection");
  
    
  

All we do here is (un)set the "in_collection" HTML class, which will trigger the HTML element to be styled according to the CSS rules.


Would you like to see more Elixir content like this? Sign up to my mailing list so I can gauge how much interest there is in this type of content.