Reputation: 25
I'm venturing in Ruby on Rails for a while but never did anything with js. I searched the internet some tutorials but nothing went right to what I wanted.
I have a rails application where in one view I have two partials, one form and another that shows a list of tasks that were created by the form. I want that when the submit button is clicked, the partial list is updated with the new newly created task, while also keeping the others that were created before.
Anyone have a better link to help me? Or a little time to explain to me?
Edit:
with the help of the answers below, I changed my code to:
_to_do_list.html.erb ( with the partial form, it should update the form below, list when pressed the button subit form.)
<%= form_for @todo_list, remote: true do |f| %>
....
<div class="field">
<%= f.label :name%><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label 'Público?'%>
<%= f.check_box :is_public %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<div id= "show_list">
<%= render 'show' %>
</div>
And, partial show, not changed, which must be updated:
<table id="list" border="1" >
<tr>
<th>Name</th>
<th>Description</th>
<th>is public?</th>
<th>Add Tasks</th>
<th>erase List</th>
</tr>
<% @todo_lists.each do |f|%>
<tr>
<td><%=f.name %></td>
<td><%=f.description%></td>
<td><%=f.is_public %></td>
<td><%= link_to new_task_path :method => :get %></td>
<td> <%= link_to 'Destroy', f, confirm: 'Are you sure?', method: :delete%></td>
</tr>
<% end %>
</table>
And, new js file :
$("#todos").html('<%=j render partial: "to_do_lists/show", locals: { todo_lists: @todo_list } %>');
Controller:
def create
@todo_list = ToDoList.new(params[:to_do_list])
@todo_list.member_id = current_member.id
respond_to do |format|
if @todo_list.save
format.js{}
format.html { redirect_to @todo_list, notice: 'Lista ' +@todo_list.name+ ' foi criada com sucesso!' }
format.json { render json: @todo_list, status: :created, location: @todo_list }
else
format.html { render action: "new" }
format.json { render json: @todo_list.errors, status: :unprocessable_entity }
end
end
end
The idea is to create a new row in the table with the new task created without leaving the page.
Thank you.
Edit
Upvotes: 2
Views: 1311
Reputation: 9173
What you need is AJAX
. If you look at docs it says
JavaScript can also make requests to the server, and parse the response. It also has the ability to update information on the page. Combining these two powers, a JavaScript writer can make a web page that can update just parts of itself, without needing to get the full page data from the server. This is a powerful technique that we call Ajax.
For this to work you first need to change your form to have remote: true
option which basically allows your forms values to be submitted by js. Your form will look like
<%= form_for @todo_list, remote: true do |f| %>
...
// form fields
<% end %>
<div id= "some-id"> // to target this div to render your partial from js
<%= render 'show' %> // it doesn't make sense to have your partial inside form and
</div>
it should be outside your form
In your create action you need to have a respond_to
block
def create
@todo = Todo.new(todo_params)
respond_to do |format|
if @todo.save
format.js{} # this will allow rails to look for create.js.erb in your views/controller directory where you can use your js to render your partial or append newly created todo
else
format.html{render "new"}
end
end
end
In your create.js.erb template use your js to render partial or append your newly created item
$("#some-id").html("<%=j render "show" %>");
OR
Instead of rendering whole partial again what you can do it just append your newly created todo in your table by js
$("#table-id").append("<%=j render partial: "todo", locals: {f: @todo} %>");
Here your _todo.html.erb will contain
<tr>
<td><%=f.name %></td>
<td><%=f.description%></td>
<td><%=f.is_public %></td>
</tr>
For details checkout Working with javascript in rails
UPDATE
If you look at your partial you have
<table id="list" border="1" >
<% @todo_lists.each do |f|%> // your @todo_lists is a collection of todos
<tr>
<td><%=f.name %></td>
<td><%=f.description%></td>
<td><%= link_to new_task_path %></td> // you don't need to specify method here link_to by default uses a get request
<td> <%= link_to 'Destroy', f, confirm: 'Are you sure?', method: :delete%></td>
</tr>
<% end %>
</table>
Change your controller method to this:
def create
@todo_list = ToDoList.new(params[:to_do_list])
@todo_list.member_id = current_member.id
respond_to do |format|
if @todo_list.save
@todo_lists = ToDoList.all // get a collection of todos to render in your partial
format.js{}
format.html { redirect_to @todo_list, notice: 'Lista ' +@todo_list.name+ ' foi criada com sucess!' }
format.json { render json: @todo_list, status: :created, location: @todo_list }
else
format.html { render action: "new" }
format.json { render json: @todo_list.errors, status: :unprocessable_entity }
end
end
end
And in your create.js.erb file
$("#show_list").html('<%=j render partial: "to_do_lists/show", locals: { todo_lists: @todo_lists } %>'); //You don't have an element with id = todos. You have it with show_lists so change that
Also render your partial after closing your form. It doesn't make sense to show todos inside a form
Upvotes: 1
Reputation: 76774
I want that when the submit button is clicked, the partial list is updated with the new newly created task, while also keeping the others that were created before.
This would indeed be achieved with ajax
--
Ajax
Ajax (Asynchronous Javascript And XML) is basically a way to send pseudo-requests to your backend from JS.
Since you're new to Rails, let me explain the idea of it being stateless. Stateless applications (which constitutes most built using the HTTP protocol) treat each request as "new" - not storing any personalized details for use each time
This means that if you want to send a request to Rails without reloading your page, you'll need to both send and receive data, appending it to your already loaded page. This is what Ajax does.
--
Rails
What you're asking is relatively simple
You need to do the following:
- Send your form data to Rails using ajax
- On the Rails backend, capture the event, perform functionality & respond
- On your front-end, "listen" to the response & append to the page
There are a number of ways to achieve this. For simplicity's sake, I'll detail the most direct way to achieve it (this uses the Rails UJS driver):
#app/views/todo_lists/new.html.erb
<%= form_for(@todo_list), remote: true do |f| %>
This will capture your form's submit
action & send the update to the required URL. This means you'll be able to capture the request in your controller & then handle it in the backend:
#app/controllers/todo_lists_controller.rb
Class TodoListsController < ApplicationController
def create
@todo_list = TodoList.new(todo_params)
@todo.save
respond_to do |format|
format.js #-> loads /views/todo_lists/create.js.erb
format.html
end
end
end
This will allow you to call the following:
#app/views/todo_lists/create.js.erb
$("#todos").html('<%=j render partial: "todo_lists/your_partial", locals: { todo_lists: @todo_lists }" %>');
This will call your JS for the user - appending the request to your view; making it appear like no refresh was needed :)
Upvotes: 1