Reputation: 43
I'm trying to make filtering function with ajax and render partial. The reason why I need these two is because there is an element I should not reload. Because of this I'm trying to get a filtered data by ajax and render partial the filtered data. If there is anything I should let you know more, please tell me.
Making index page work is fine.
controllers/item_controller.rb
def index
@items = Item.all
end
views/item/index.html.erb
<div>
An element that should not be reloaded
</div>
<div id="item_list_wrapper">
<%= render partial: 'item/item_list' %>
</div>
views/item/item_list.erb
<% @items.each do |i| %>
something
<% end %>
When I click a button, ajax is called and item/item_list.erb is reloaded.
controllers/item_controller.rb
def item_filter
filtered_items = Item.where(filtered item)
render json: filtered_items
end
javascript
$.ajax({
method: 'get',
url: '/item/filter',
dataType: 'json',
data: {
price: $('#price').val()
},
success: function(data) {
console.log(data);
$("#item_list_wrapper").html("<%= escape_javascript(render partial: 'item/item_list') %>");
},
error: function(){
alert('error');
}
});
I can see the ajax called data in my console. It took me several days but I really cannot find out a way to use the ajax called data as @items in the reloaded item/item_list.erb. Thanks in advance for all comments.
Upvotes: 2
Views: 2478
Reputation: 102036
You can't.
The ERB interpolation (anything in ERB tags <% %>
or <%= %>
) happens on the server before the the javascript is sent to the client. If your script is placed in app/assets/javascripts
this done when the scripts are compiled at deploy time.
The Ajax request happens later on the client.
You either need to do the templating on the client side:
var $template = $('<li></li>');
var promise = $.getJSON(
url: '/item/filter',
data: {
price: $('#price').val()
},
success: function(data) {
$.each(data, function( index, value ) {
$("#item_list_wrapper").append( $template.clone().text(value));
};
},
error: function(){
alert('error');
}
)
Or use a js.erb
template:
var promise = $.ajax(
url: '/item/filter',
data: {
price: $('#price').val()
},
dataType: 'application/javascript',
error: function(){
alert('error');
}
)
You can also use Rails UJS to send the ajax request by adding the data-remote="true"
to the form (usually done by adding remote: true
to the form helper options).
# defaults to the js format
# set "data-type" => :json to send JSON instead
<%= form_tag('/item/filter', remote: true) %>
<%= number_field_tag(:price) %>
<%= submit_tag 'Filter items' %>
<% end %>
You need to setup your controller to respond to the js
format:
class ItemsController
def filter
# ...
respond_to do |format|
format.js
end
end
end
// app/items/views/filter.js.erb
$("#item_list_wrapper").html("<%= escape_javascript(render partial: 'item/item_list') %>");
Upvotes: 1
Reputation: 787
I think it may have to do with not passing in the data
to your partial. Try changing views/item/item_list.erb to
<% items.each do |i| %>
something
<% end %>
then call it in your view:
<%= render partial: 'item/item_list', locals: { items: @items } %>
then finally pass in data to the partial using JS:
$("#item_list_wrapper").html("<%= escape_javascript(render partial: 'item/item_list', locals: { items: data }) %>");
Having said all that, I'd also recommend learning to use remote => true to simplify your js. I've found this guide straightforward: https://coderwall.com/p/kqb3xq/rails-4-how-to-partials-ajax-dead-easy
Upvotes: 0