I am venturing into AJAX and would like to delete a record of a model and followed this thread : How to perform Controller.destroy action asynchronously in rails?
models:
Photographe
Photographephoto
views/photographes/edit.html.erb
<div id="sectionimages" class="gutter-0 row" >
<% #photographe.photographephotos.all.each do |f| %>
<div class="col-md-2 col-sm-3 col-xs-6 col">
<%= link_to professionnel_photographe_photographephoto_path(#photographe.professionnel.id,#photographe.id, f.id), method: :delete, remote: 'true', id: "destruction"+f.id.to_s do %>
<div class="killimage" >
<%= image_tag f.image.url(:small) %>
<%= image_tag 'fatcrosswhite.svg', class: 'imgover' %>
</div>
<% end %>
</div>
<% end %>
</div>
link to Photographephotos#destroy is remote and there's an id like "destruction134"
photographephotos_controller.rb
def destroy
#imagedestroyed = Photographephoto.find(params[:id])
#imagedestroyedid = #imagedestroyed.id
#imagedestroyed.image = nil
#imagedestroyed.save
#imagedestroyed.destroy
respond_to do |format|
format.js
end
end
views/photographephotos/destroy.js.erb
var destroyelement = document.getElementById("<%= "destruction"+#imagedestroyedid.to_s %>");
destroyelement.parentNode.remove();
Problem is the file is indeed deleted but I have to refresh the page to see it removed. It seems the javascript is not effective. (I am trying to remove the parent of the link which is a Bootstrap DIV)
Related
I have a setting in which I would like to dynamically change a buttons disabled state. Currently the logic I have looks as follows:
<% if #has_attachment_file_sent %>
<% if current_user.id != #offer.user_id %>
<%= link_to send_signature_requests_path, remote: true, method: :post,
data: { confirm: "Are you sure?" },
id: "signature_request_button",
class: "button is-info is-fullwidth m-t-10 m-b-10" do %>
<span>Send request</span>
<% end %>
<% end %>
<% else %>
<button class="button is-info is-fullwidth m-t-10 m-b-10" disabled>Send request</button>
<% end %>
However, the problem with this method is that this only changes the state of the button when you refresh the page. Is there a way to do this kind of Ajax with RoR or what should I do here?
Also tried using javascript as follows:
<script>
$(document).ready(function() {
var has_attachment_file_sent = <%= #has_attachment_file_sent %>
console.log(has_attachment_file_sent);
if(has_attachment_file_sent) {
$('#signature_request_button').attr('disabled', true);
}
})
</script>
but this doesn't seem to be doing anything.
Also here's my controller
def show
#offer = Offer.find(params[:id])
#has_attachment_file_sent = Comment.where(user_id: #offer.user_id).any? {|obj| obj.attachment_file.attached?}
respond_to do |format|
format.html
format.js { render layout: false, content_type: 'text/javascript' }
end
end
First place your html in a partial and wrap the content in div, assume that the partial's name is 'buttons.html.erb'
_buttons.html.erb
<% if #has_attachment_file_sent %>
<% if current_user.id != #offer.user_id %>
<%= link_to send_signature_requests_path, remote: true, method: :post,
data: { confirm: "Are you sure?" },
id: "signature_request_button",
class: "button is-info is-fullwidth m-t-10 m-b-10" do %>
<span>Send request</span>
<% end %>
<% end %>
<% else %>
<button class="button is-info is-fullwidth m-t-10 m-b-10" disabled>Send request</button>
<% end %>
<div id="buttons">
<%= render partial: 'buttons' %>
</div>
Add button in view
<%= link_to 'Refresh', show_page_path(id: #offer.id), id: 'btn_call_ajax', remote: true %>
you should adapt show_page_path with your route
def show
#offer = Offer.find(params[:id])
#has_attachment_file_sent = Comment.where(user_id: #offer.user_id).any? {|obj| obj.attachment_file.attached?}
respond_to do |format|
format.html
format.js
end
end
Then you should create a file named show.js.erb that contain the following code:
$('#buttons').html('')
$('#buttons').append("<%= escape_javascript render(:partial => 'buttons') %>");
Oh yeah, how annoying, forgot about that
Maybe something like this inside js.erb
It should work, hacks but I’m sure there is another solution I’m going blank on
# render partial line here
<% if #disabled %>
$(‘#button-id’).prop(“disabled”, true);
<% else %>
$(‘#button-id’).removeAttr(“disabled”)
<% end %>
create the file show.js.erb and in your controller just leave it as format.js without curly braces.
create a partial with
<button class="button is-info is-fullwidth m-t-10 m-b-10" disabled="<%= disabled ? “disabled” : “” %>”>Send request</button>
And add a div in original file, wrap rendering of the partial above
<div id=“woohoo”>
<%= render partial: “file_above”, locals: {disabled: true} %>
</div>
Then in that .js.erb file add this $(‘#div-around-button’).html(“<%= j render(‘show’, disabled: #disabled_variable_from_controller) %>”) and it will basically refresh that button with new value that you got from controller 🙂
P.S. I wrote this all on my iPhone so I might have missed small things like syntax
When I submit form using jQuery-Ajax in ROR the submit button gets freezed.
I am practicing "Integrating Ajax and Rails: A Simple Todo List App", provided by GitHub.
class TodosController < ApplicationController
def create
#binding.pry
#todo = Todo.create(todo_params)
respond_to do |format|
format.html {redirect_to home_path}
format.js {}
end
end
private
def todo_params
params.require(:todo).permit(:description, :priority)
end
end
index.html.erb
<h2>Create Todos</h2>
<%= render 'new' %>
<h2>Todos List</h2>
<ul>
<%= render #todos %>
</ul>
_new.html.erb
<%= form_for Todo.new, html: {id: "form1"} do |f| %>
<p>
<%= f.label :description %>
<%= f.text_field :description %>
</p>
<p>
<%= f.label :priority %>
<%= f.text_field :priority %>
</p>
<p>
<%= f.submit 'Submit' %>
</p>
<% end %>
_todo.html.erb
<li>
<%= todo.description %><br>
<strong>Priority:</strong><%= todo.priority %><br>
<%= link_to 'done', todo_path(todo) , method: 'delete' %>
</li>
create.js.erb
$("ul").append("<%= j render partial: 'todo', locals: {todo: #todo} %>");
app/assets/javascript/todos.js
$(function(){
$("#form1").submit(function(event){
event.preventDefault();
let method = $(this).attr('method');
let action = $(this).attr('action');
let description = $(this).find('#todo_description').val();
let priority = $(this).find('#todo_priority').val();
let data = $(this).serializeArray();
$.ajax({
method: method,
url: action,
data: data,
dataType: 'script'
});
});
});
The button gets frozen because nowadays there is a jquery script that disables it to prevent multiple submissions. Check for any classes/attributes added to the submit button when it's clicked, and then put some jquery to your create.js.erb to remove them and also clear the fields if you want to submit a new todo item.
I am trying to implement AJAX in my to do type app, but am getting a missing template error (Missing template items/create, application/create with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee]}.) on my create action. There shouldn't be a create.html.erb page because the creation of items happens on a lists#show page:
<div class='new-item'>
<%= render 'items/form' %>
</div>
<div class="js-items">
<% #items.each do |item| %>
<%= div_for(item) do %>
<p><%= link_to "", list_item_path(#list, item), method: :delete, remote: true, class: 'glyphicon glyphicon-ok', style: "margin-right: 10px" %>
<%= item.name %>
<% if item.delegated_to != "" && item.user_id == current_user.id %>
<small>(Delegated to <%= item.delegated_to %>)</small>
<% elsif item.delegated_to != "" && item.user_id != current_user.id %>
<small>(Delegated by <%= item.user_id %>)</small>
<% end %></p>
<% end %>
<% end %>
</div>
And the _form.html.erb partial to which it links:
<div class="row">
<div class="col-xs-12">
<%= form_for [#list, #item], remote: true do |f| %>
<div class="form-group col-sm-6">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control', placeholder: "Enter Item Name" %>
</div>
<div class="form-group col-sm-6">
<%= f.label 'Delegate To (Not Required)' %>
<%= f.text_field :delegated_to, class: 'form-control', placeholder: "Enter an Email Address" %>
</div>
<div class="text-center"><%= f.submit "Add Item to List", class: 'btn btn-primary' %></div>
<% end %>
</div>
</div>
Here's the create method in the items_controller:
def create
#list = List.friendly.find(params[:list_id])
#item = #list.items.new(item_params)
#item.user = current_user
#new_item = Item.new
if #item.save
flash[:notice] = "Item saved successfully."
else
flash[:alert] = "Item failed to save."
end
respond_to do |format| <<<<ERROR CALLED ON THIS LINE
format.html
format.js
end
end
And here's my create.js.erb file:
<% if #item.valid? %>
$('.js-items').prepend("<%= escape_javascript(render(#item)) %>");
$('.new-item').html("<%= escape_javascript(render partial: 'items/form', locals: { list: #list, item: #new_item }) %>");
<% else %>
$('.flash').prepend("<div class='alert alert-danger'><button type='button' class='close' data-dismiss='alert'>×</button><%= flash.now[:alert] %></div>");
$('.new-item').html("<%= escape_javascript(render partial: 'items/form', locals: { list: #list, item: #item }) %>");
<% end %>
Anyone have any ideas why I am getting this? I tried removing the format.html line from the items_controller but I got an unrecognizable format error.
You can force the form submission to use a JS format, instead of the default HTML format, so that your respond_to block will render the create.js.erb view instead of the create.html.erb view.
<%= form_for([#list, #item], format: :js, remote: true) do |f| %>
Typically, Rails will detect your remote: true option via "unobtrusive JavaScript (ujs)", which will effectively handle the format: :js option for you. There is something unique in your setup that we have not identified, which is requiring you to enforce the format option.
To see that your create.js.erb is working, you can change the line that renders your item partial:
$('.js-items').prepend("<%= escape_javascript(render(#item)) %>");
To render a the item's name, wrapped in a <p> tag:
$('.js-items').prepend("<p>" + <%= #item.name %> + "</p>");
You can customize that line to generate the html that you want to appear for your new list item. Based on your code above, this looks like it will work out for you.
As you finish your to-do app, you can create a partial for your item, and then change that line again so that your partial will be appended to your list of items.
I'm trying to create a nested form where there is a "+" button which adds fields via jquery and ajax. I am doing it adding a step at once, so untill now I am able to add a simple text pushing the "+" button, but, as I have just said, I want to add some fields.
I have the followings:
new.html.erb
<h1>New Campaign</h1>
<%= form_for #campaign, html: { multipart: true } do |f| %>
....
<div class="goods">
<%= render "goods/good", f: f, child_index: Time.now.to_i %>
</div>
<div class="actions">
<%= link_to '+', add_good_row_path(params[:campaign]=#campaign, params[:f] = f), remote: true, class: 'btn btn-large btn-success' %>
<%= f.submit 'Crea', class: 'btn btn-large btn-warning' %>
</div>
<% end %>
goods/_good.html.erb
<%= f.fields_for :goods, #campaign.goods.build, child_index: child_index do |good| %>
<%= good.text_field :name, placeholder: 'Nome' %>
<%= good.text_area :description, placeholder: 'Descrizione' %>
<%= good.text_field :cost, placeholder: 'Costo' %>
<% end %>
campaigns_controller.rb
class CampaignsController < ApplicationController
....
def add_good_row
respond_to do |format|
format.js
end
end
end
add_good_row.js.erb
$('.goods').append("hello");
I think that I understood the problem, it is to pass a f variable, a #campaign variable and a child_index to the partial, but how can I do that via jquery?
Hope I was clear...
Have a look at this gem.
I think it's what you are looking for
https://github.com/nathanvda/cocoon
My comment app works ,but the only problem is whenever i refresh the page the comments disappear.In the log it shows the body is inserted in the comments table(it is saved).What am i doing wrong here?Any help will be appreciated.Thank you in advance.
View#show
<div id="comments"></div>
<%= form_for :comment,:remote => true,:url=> {:controller=>"comments",:action=>"create"},:html => { :id => 'new-comment'} do |f| %>
<%= f.text_area(:body) %>
<div class="errors"></div>
<%= f.submit "post" %>
<% end %>
Comment controller
class CommentsController < ApplicationController
respond_to :js
def create
#deal=Deal.find(1)
#comment =#deal.comments.build(params[:comment])
#comment.save
respond_with( #comment, :layout => !request.xhr? )
end
def show
#comment=Comment.all
#deal=Deal.find(1)
#comment=#deal.comments
end
end
create.js.erb
$('#comments').append("escape_javascript(#comment.body)");
I don't see where your comments are being display in your show template.
How about something like this?
<div id="comments">
<% #comments do |comment| %>
<%= comment.body %>
<% end %>
</div>
<%= form_for :comment,:remote => true,:url=> {:controller=>"comments",:action=>"create"},:html => { :id => 'new-comment'} do |f| %>
<%= f.text_area(:body) %>
<div class="errors"></div>
<%= f.submit "post" %>
<% end %>
Note, you need to set #comments in the controller or use another method of getting comments, e.g. #view = View.find(params[:id]) and <%= #view.comments.each do |comment| %>...
I guess the comment has a belongs_to relationship with the post that is not assigned.
In your form you should add
<%= f.hidden_field :post_id, #post.id %>
If you want to play by the book, post_id should be attr_protected and instead assign it manually in the comments controller
#comment = Comment.new(params[:comment])
#comment.post_id = params[:comment][:post_id]
#comment.save