Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to submit form and update element on the page without refresh, in Rails 4

I'm having a lot of trouble trying to do something that I imagine would be fairly simple.

I have a list of items, let's say, todos. At the bottom of that list I have a text field where I add new items to that list. I want to make it so that the new items are added to the bottom of that list dynamically, without a full page refresh, like in a chat window.

I made the submit form remote: true and it successfully submits without reloading the page, but I can't get the new item to appear at the bottom of the list at the same time. I have to refresh the page to see the changes.

I tried a few different approaches I found on SO (there's no shortage of similar questions here) and the web, and even a gem called Sync, but each of them had errors and problems of their own and I couldn't get any to work properly. Each of them could be its own SO question. So instead I ask: Is there a "recipe" that is sure to successfully implement this in Rails 4?

like image 849
San Diago Avatar asked Mar 27 '14 17:03

San Diago


3 Answers

let's say, now you have a user form to submit,

<%=form_for @user,remote: true%><%end%>

And you also have a controller,

UsersController

In your controller, you have a function,

def create
  #something
end

which is for the form.

the only thing you need is to modify the function like

def create
  #something
  respond_to do |format|
    format.js
    format.html
  end
end

then in your view side, under directory of view/users/ , create a create.js file, in the file, you can do the js action, like get the new record, and append the new record to the users list.

reference:

http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#form-for

like image 52
Chuanpin Zhu Avatar answered Oct 19 '22 01:10

Chuanpin Zhu


There are various ways to do what you are asking. My approach would be:

  • Create an AJAX call to the controller that passes the parameters of the form

  • Inside the controller, you save/update things and then return a JSON object

  • On the success callback of the AJAX function, you append a list item/table row, using the object values

The code could be something like this:

model.js

$(function() {
  $("#submit_button").on("click", function(event) {
    event.preventDefault();
    $.ajax({
      type: "POST",
      url: "your_controller_url",
      data: "your_form_data"
      success: function(result) {
        // Append the result to a table or list, $("list").append(result)
      },
    });
  });
});

controller.rb

def your_action
  # Do your stuff
  # return JSON to the ajax call
end

Well, this is just a skeleton. I prefer doing things this way. (Because i hate the js.erb approach)

like image 44
MurifoX Avatar answered Oct 19 '22 00:10

MurifoX


Here is rails 5, hope it will help someone ( it still works on rails 4 ):

Try this ajax example:

In 'routes.rb':

# set the route that ajax can find the path to what controller in backend
get   '/admin/some_great_flow',   to: 'great_control#great_flow'

In 'great_control_controller.rb' controller:

 # this function in controller will response for ajax's call
 def great_flow
    # We can find some user or getting some data, model here.
    # 'params[:id]' is passed by ajax that we can use it to find something we want.
    @user = User.find(params[:id]) 

    # print whole data on terminal to check it correct.
    puts YAML::dump(@user.id) 

    # transform what you want to json and pass it back.        
    render json: {staff_info: @user } 
end

In 'app/views/great_control/index.html.erb' view:

<div>
     <label>Staffs</label>
     <%=select_tag(:staff, options_from_collection_for_select(@staffs, :id, :name), id:"staff_id", required: true)%>
</div>
<script>
//every time if option change it will call ajax once to get the backend data.
$("#staff_id").change(function(event) {
    let staff_id = $("#staff_id").val()
    $.ajax({
        // If you want to find url can try this 'localhost:prot/rails/info/routes'
        url: '/admin/some_great_flow', 
        type: 'GET',
        dataType: 'script',
        data: { id: staff_id },
        // we get the controller pass here
        success: function(result) {
             var result = JSON.parse(result);
             console.log(result['staff_info']);
             // use the data from backend for your great javascript.
        },
    });
});
</script>

I write it for myself.

like image 43
Zan Zas Avatar answered Oct 19 '22 01:10

Zan Zas