I have an HTML table with a list of instances of a model called Transaction. The first row, however, contains a form used to create a new transaction. Here is the _tranasctions_table.html.erb partial with the table:
<table id="transactions-table-id" class="table table-striped table-bordered table-hover">
<thead>
<tr><th>Date</th><th>Description</th><th>Category</th><th class="transaction-value-cell">Value</th><th class="icon-cell"></th></tr>
</thead>
<tbody id="transactions-table-body">
<tr id="new-transaction-row">
<%= form_for @new_transaction, url: {action: "create"}, remote: true do |f| %>
<td><%= f.text_field :date, id:"datepicker", readonly: true %></td>
<td><%= f.text_field :description %></td>
<td><%= f.text_field :category_id %></td>
<td class="transaction-value-cell"><%= f.number_field :value %></td>
<td class="icon-cell"><a href="#" class="fa fa-plus fa-lg text-muted text-center" ></a></td>
<input type="submit" style="display:none;">
<% end %>
</tr>
<% transactions.each do |trans| %>
<tr class=<%= (trans.value < 0) ? "red-row" : "green-row" %> >
<td><%= trans.date %></td>
<td><%= trans.description %></td>
<td class="transaction-category-name" style="color:gray;"><%= trans.category.name %></td>
<td style="border-right:none;"><%= trans.value %></td>
<td class="icon-cell"><a href="#" class="fa fa-trash fa-lg text-muted text-center"/></td>
<td class="transaction-id" style="display:none;"><%= trans.id %></td>
</tr>
<% end %>
</tbody>
</table>
<%= paginate transactions %>
I can submit the form either by pressing 'Enter' or clicking on the 'plus' icon in the last table cell, and this is done with the jQuery command
$('#new_transaction').submit();
This works fine when the page is first loaded. However, there is a second table that lists categories. When the user clicks one of its rows, the transactions table is to be refreshed, showing only those that fall in the selected category. This is done via AJAX, so that only the transaction table is refreshed on the page. This was my attempt to do so:
function filter_by_category(category) {
var category_name = category.html();
$.ajax({
method: "GET",
url: "expenses/filter_category",
data: { category: category_name }
})
.done(function( msg ) {
$('tr').removeClass("selected-category");
category.closest('tr').addClass("selected-category");
$('#transactions_table_span').html(msg);
add_listeners();
});
}
The add_listener()
function binds the jQuery submit command to the new form, among other things. And here is the relevant part of the controller that handles the request:
def filter_category
@new_transaction = Transaction.new
# other variables are set, such as @transactions, depending on the selected category
render partial: 'transactions_table', locals: {transactions: @transactions}
end
The result is a correctly rendered table, with a seemingly correct form. However, when I try to submit from this newly rendered form, no parameters are sent.
What have I done wrong?
Update:
As asked, I'm including the view index.html.erb that holds both tables:
<%= javascript_tag do %>
$(document).ready(function() {
add_listeners();
select_current_category();
highlight_expenses_menu_tab();
});
<% end %>
<div class="container-fluid">
<div class="row">
<div class="col-lg-8">
<div class="panel panel-primary">
<div class="panel-heading">Transactions</div>
<div class="panel-body">
<%= form_tag({action: :upload}, multipart: true, class: "form-inline") do %>
<div class="form-group">
<label class="sr-only" for="transactions">File upload</label>
<%= file_field_tag 'transactions' %>
</div>
<%= submit_tag("Upload", class: "btn btn-default") %>
<% end %>
</div>
<span id="transactions_table_span">
<%= render partial:"transactions_table", locals: {transactions: @transactions} %>
</span>
</div>
</div>
<div class="col-lg-offset-1 col-lg-3">
<div class="panel panel-primary">
<div id="category-panel-heading" class="panel-heading">Categories</div>
<%= render partial:"categories_table", locals: {categories: @categories, category_name: @category_name, new_category: @new_category} %>
</div>
</div>
</div>
</div>
This is how the call to filter_by_category()
happens:
- A click event listener is attached to the category rows with
add_select_category_listener()
- The listener calls another function,
select_category()
, whose behavior depends on whether there is a transaction currently selected. If there is, clicking on the category changes those transactions into the selected category.
Here are the two functions:
function add_select_category_listener() {
$('tr.category-row > td').not('td.icon-cell').off('click');
$('tr.category-row > td').not('td.icon-cell').click( function() {
select_category($(this));
});
}
function select_category(category) {
var category_name = category.html();
var number_selected_rows = $('.selected-transaction').length
if (number_selected_rows == 0) {
filter_by_category(category);
} else {
var selected_transactions = [];
var html_selected_transactions = $('.selected-transaction > td.transaction-id');
for (i = 0; i < html_selected_transactions.length; i++) {
selected_transactions.push(html_selected_transactions[i].innerHTML);
}
change_to_category(category_name, selected_transactions);
}
}
I checked and filter_by_category()
is indeed being called. Also, I'm using Rails 4.1.7.