Posting forms with AJAX on checkbox toggle

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

&#91;/code&#93;

Nothing magical here: just retrieve the necessary model instances, update the collection content, and set variables used in the view.
<h2>View code</h2>


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.

This entry was posted in AJAX, CoffeeScript, jQuery, Rails. Bookmark the permalink.