blazeP
blazeP

Reputation: 91

Rails - how put javascript variable into erb code

I've seen some similar question, but still don't know how achieve my goal. I want to do that thing:

  1. Display modal with products represented by divs.
  2. User choose some products (I add .active class to chosen products)
  3. Then I use jQuery to make array of chosen products ids.
  4. In the end I want to create div for each product, which will be include some informations about this product from database. I'm using js .append() to do it. And here is a problem.

This code is in my script tag in proper view.

    var chosen_products_array;

    $('.product-to-choose').click(function() {
        $(this).toggleClass("active");
        $(this).find('i').toggleClass("visible");
    });

    $('#chosen-products-confirm').click(function() {
        var chosen_products = $('.product-to-choose.active');
        chosen_products_array = jQuery.makeArray( chosen_products );
    });

    $('#confirm').click(function() {

        var textToInsert = '<div><h4>Products:</h4>';
        $.each(chosen_products_array, function(count, item) {
            var id = $(item).attr('id').substr(8); // id is product_number
            textToInsert += '<div><li name="chosen-product"> <%= current_user.products.find(' + id +').name %></li></div>';
        });
        textToInsert += '</div>';
        $('#div-example').append(textToInsert);
    });

My controller create action:

def create
@meal = current_user.meals.build(meal_params)
if @meal.save
  current_user.type_tags.each do |type_tag|
    key = "type#{type_tag.id}"
    if params[key]
      @meal.type_tags << type_tag # zapis do bazy danych
    end
  end
  flash[:success] = "Create new meal!"
  redirect_to meals_path
else
  #render 'meals/new'
end

end

This line generates error:

textToInsert += '<div><li name="chosen-product"> <%= current_user.products.find(' + id +').name %></li></div>';

Error:

Couldn't find Product with 'id'=+id+ [WHERE "products"."user_id" = ?]

I know there is a problem in passing js variables to rails erb, but how can I solve it in this case? I tried with gon too.

In my controller, I added:

gon.products = current_user.products

and then try

alert(gon.products)

it's ok - array of objects, but when I try

alert(gon.products.find(1))

it doesn't work.

Have you got any idea how can I put this javascript id variable to erb code? Or maybe is any different solution?

Upvotes: 0

Views: 2832

Answers (3)

nowRails
nowRails

Reputation: 267

I think first make your model visible to the browser as js variable(json object) . Some thing like below at the end of your view file(below is the haml syntax):

:javascript

   var userProducts        = #{@current_user.products.to_json};

Then use it in javascript expression

Upvotes: 0

bosskovic
bosskovic

Reputation: 2054

Probably the best would be to add a remote form (it may be hidden) that posts whatever you want (javascript values) and then it is handled by a controller. Then you can render it with js views.

This would probably be the most "rails-like" solution.

Here's some code:

In the routes:

resource :my_form, only: :create

In the view:

<%= form_tag(my_form_path, remote: true, method: :post) do %>
  <%= hidden_field_tag :val %>
<% end %>

You alter the val dynamically by javascript, and submit the form whenever you want to.

Then, in the controller you have something like this:

respond_to :js

def create
  # do something with params['val']
  @my_val = params['val']
end

And you would also add create.js.erb view, where you could add some javascript that can use any of the instance variables created in the controller.

//create.js.erb
$('#someElement').html('<%= @my_val %>');

Let me stress if it is not clear, the form is remote (ajax), so it is sent in the background and the page is not reloaded.

When the browser receives the response, it may contain any javascript you decide to render (the contents of create.js.erb), and then the browser executes that javascript.

So, you can add there any jquery commands with arguments that you changed dynamically by rails, or you could also render html partials and replace any elements with them, like this:

//create.js.erb
$('#my_id').html('<%= j(render partial: 'my_form/_some_partial.html.erb', locals: { my_val: @my_val }) %>');

More details on Working with JavaScript in Rails


UPDATE

Another, inferior but simpler to implement solution would be to always render all products, but have them hidden initially, and then show them by jQuery on demand. You would just need to add appropriate css classes or data attributes to those products, as well as the links you use to select them.

Upvotes: 1

Amr Noman
Amr Noman

Reputation: 2637

The problem is that erb code is evaluated on the server before the browser even fetches the javascript file, so it doesn't make sense to use this way. It's recommended that you only use erb in your javascript for simple things like asset_path

Upvotes: 0

Related Questions