Submit method don't work in rails - javascript

I need to replace submit button to "link_to".
#View
<%= form_for :task, remote: true, id: 'create_form' do |f| %>
....
<%= link_to 'OK', '', id: 'submit_link' %>
<% end %>
#CoffeeScript
ready = ->
$("#submit_link").click (event) ->
$("#create_form").submit()
$(document).ready ready
$(document).on "page:load", ready
Click trigger work good, but "submit()" method doesn't work and i don't know why.
Also i try to add "event.preventDefault()", but nothing changed.

I think you need to set the id of your form like this
<%= form_for :task, remote: true, html: { id: 'create_form' } do |f| %>
http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for
Or, just use the form id that form_for generates which should be new_task
#CoffeeScript
ready = ->
$("#submit_link").click (event) ->
$("#new_task").submit()
$(document).ready ready
$(document).on "page:load", ready

Related

How to call a javascript function in a rails form?

I have a rails form that looks like this :
= form_for :location, :url=>'/welcome' do |f|
= f.text_field '', placeholder: 'Enter your zip code', id:'input_id'
= f.button "Continue", class: 'button-test'
So when the button continue is clicked upon , rails get the controller and execute the method /welcome
so what i am trying to do is to actually execute a simple javascript function like :
function wawa() {
alert('it works')
};
when the button continue is cliked instead of rails getting to execute the method /welcome.
How can I approach this problem using Javascript only and no library ?
You can use submit() function of jquery.
= form_for :location, :url=>'/welcome', html: {id: "id_form_location"} do |f|
= f.text_field '', placeholder: 'Enter your zip code', id:'input_id'
= f.button "Continue", class: 'button-test'
In javascript file:
$("#id_form_location").submit(function(event) {
alert('it works');
});
You need to add some JavaScript On submit Listener I suppose you need it before form is submit. If you want only on click then have a look at on click Listener also have a look at event prevent as it will help you to prevent from default behaviour of button.
Try this code
<%= form_for :location, :url=>'/welcome' do |f| %>
<%= f.text_field '', placeholder: 'Enter your zip code', id:'input_id' %>
<%= f.button "Continue", class: 'button-test', id: 'demo' %>
<% end %>
<script type="text/javascript">
document.getElementById("demo").addEventListener("click", function(event){
event.preventDefault()
alert('Hello')
});
</script>

Rails reCAPTCHA with callback

I am trying to integrate a recaptcha into my website and I wanted to add some client side validation.
I chose to use a gem to include the recaptcha tags, but I wanted to trigger a function once the recaptcha is checked.
Looked through some google sites and found that a data-callback attribute with its value set to function name is all I need.
I used recaptcha_tags helper from the gem to set it up and then a jquery method to add this data-callback attribute as I have not seed an option to do this inside the gem.
$('.g-recaptcha').attr("data-callback", "myFunctionName");
After clicking the recaptcha the function is not called. Why?
I asume you have a form like this
app/views/contacts/contact.html.erb
<%= form_for #contact do |f| %>
<%= f.text_field :nombre, :placeholder => I18n.t("contacto_formulario_nombre"),:required => true %>
<%= f.text_field :apellido :placeholder => I18n.t("contacto_formulario_apellidos"), :required => true %>
<%= f.text_field :email, :placeholder => I18n.t("contacto_formulario_email"), :required => true %>
/** (....other tags ....) **/
<%= recaptcha_tags :display => 'clean' %>
<%= f.button I18n.t("contacto_formulario_continuar"), type: "submit" %>
<% end %>
app/assets/javascripts/contact.js
$(function() {
$('.g-recaptcha').attr("data-callback", "recaptcha");
})
function recaptcha()
{
console.log("captcha pulsado!");
/** the actions you want, i.e. activate submit button **/
}
The magic ocurrs in the attribute "data-callback"
Hope it helps.
Marino

Can't find reason why xhr is not defined

I am getting an uncaught reference error: XHR is not defined in my coffeescript below.
jQuery ->
# Create a comment
$(".comment-form")
.on "ajax:beforeSend", (evt, xhr, settings) ->
$(this).find('textarea')
.addClass('uneditable-input')
.attr('disabled', 'disabled');
.on "ajax:success", (evt, data, status, xhr) ->
$(this).find('textarea')
.removeClass('uneditable-input')
.removeAttr('disabled', 'disabled')
.val('');
$(xhr.responseText).hide().insertAfter($(this)).show('slow')
# Delete a comment
$(document)
.on "ajax:beforeSend", ".comment", ->
$(this).fadeTo('fast', 0.5)
.on "ajax:success", ".comment", ->
$(this).hide('fast')
.on "ajax:error", ".comment", ->
$(this).fadeTo('fast', 1)
I have been unable to figure out the issue and I've pretty weak in javascript.
What I'm trying to do is add a comment to a users page then show it via AJAX. The comment saves without any problem as I can see it if I manually refresh the page. However neither the create or delete actions work in the Coffeescript.
Since neither the create or delete AJAX calls seem to work, I am assuming it's in the way the script is called. I'll include the relevant controller code here as well.
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :destroy]
def create
#comment_hash = comment_params
#obj = #comment_hash[:commentable_type].constantize.find(#comment_hash[:commentable_id])
# Not implemented: check to see whether the user has permission to create a comment on this object
#comment = Comment.build_from(#obj, current_user, #comment_hash[:body])
#comment.user = current_user
if #comment.save
render partial: "comments/comment", locals: { comment: #comment }, layout: false, status: :created
else
p #comment.errors
render js: "alert('error saving comment');"
end
end
def destroy
if #comment.destroy
render json: #comment, status: :ok
else
render js: "alert('error deleting comment');"
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit( :commentable_id, :commentable_type, :body, :user_id)
end
end
Also my partial for the comment:
<div class='comment'>
<hr>
<%=link_to "×", comment_path(comment), method: :delete, remote: true, confirm: "Are you sure you want to remove this comment?", disable_with: "×", class: 'close' %>
<small><%=comment.updated_at.to_s(:short) %></small>
<p><%= comment.body %></p>
And the form itself to add new comments:
<div class='comment-form'>
<%= simple_form_for comment, remote: true do |f| %>
<%= f.input :body, input_html: { rows: "2" }, label: false %>
<%= f.input :commentable_id, as: :hidden, value: comment.commentable_id %>
<%= f.input :commentable_type, as: :hidden, value: comment.commentable_type %>
<%= f.button :submit, 'New Note', class: "button tiny radius", disable_with: "Submitting…" %>
<% end %>
</div>
Any help would be appreciated since I just don't know where to start right now. I'm not sure how I should be defining the XHR.
Incidentally, most of the code for this was from the tutorial here

Coffeescript not completing but no error

I've having trouble with the following coffeescript:
jQuery ->
# Create a comment
$(".comment-form")
.on "ajax:beforeSend", (evt, xhr, settings) ->
$(this).find('textarea')
.addClass('uneditable-input')
.attr('disabled', 'disabled');
.on "ajax:success", (evt, data, status, xhr) ->
$(this).find('textarea')
.removeClass('uneditable-input')
.removeAttr('disabled', 'disabled')
.val('');
$(xhr.responseText).hide().insertAfter($(this)).show('slow')
# Delete a comment
$(document)
.on "ajax:beforeSend", ".comment", ->
$(this).fadeTo('fast', 0.5)
.on "ajax:success", ".comment", ->
$(this).hide('fast')
.on "ajax:error", ".comment", ->
$(this).fadeTo('fast', 1)
Basically, I have a user form that I add comments to. When a new comment is added it should change class and disable the textarea before sending the data off to the database. Then it should reset the class, clear the textarea and enable the textarea again. Then finally it should add the new comment after the textarea.
The first part of the code works and the class is added to the textarea and it is set to disabled but the rest of the script never happens. Of course the comment is actually saved to the database and a refresh of the page will show the comment.
I've gone over this a ton of times and can't figure out what is going wrong. I did have an earlier issue with the indenting being wrong with the script but that has been fixed.
My CommentController code is as below:
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :destroy]
def create
#comment_hash = comment_params
#obj = #comment_hash[:commentable_type].constantize.find(#comment_hash[:commentable_id])
# Not implemented: check to see whether the user has permission to create a comment on this object
#comment = Comment.build_from(#obj, current_user, #comment_hash[:body])
#comment.user = current_user
if #comment.save
render partial: "comments/comment", locals: { comment: #comment }, layout: false, status: :created
else
p #comment.errors
render js: "alert('error saving comment');"
end
end
def destroy
if #comment.destroy
render json: #comment, status: :ok
else
render js: "alert('error deleting comment');"
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit( :commentable_id, :commentable_type, :body, :user_id)
end
end
Here's my form for creating comments:
<div class='comment-form'>
<%= simple_form_for comment, remote: true do |f| %>
<%= f.input :body, input_html: { rows: "2" }, label: false %>
<%= f.input :commentable_id, as: :hidden, value: comment.commentable_id %>
<%= f.input :commentable_type, as: :hidden, value: comment.commentable_type %>
<%= f.button :submit, 'Save Note', class: "button tiny radius", disable_with: "Submitting…" %>
<% end %>
</div>
And here's my code for displaying comments:
<div class='comment'>
<hr>
<%=link_to "×", comment_path(comment), method: :delete, remote: true, data: { confirm: 'Are you sure you want to remove this comment?',disable_with: 'x' }, class: 'close' %>
<small><%=comment.updated_at.to_s(:short) %></small>
<p><%= comment.body %></p>
By the way, the delete action partially works. It deletes the comment from the database and it hides all of the comments. A page refresh shows the comments that have not been deleted.
Any help would be greatly appreciated since I don't know where to go with this not at all. In my mind it should work so I must be missing something simple.
It's an issue with your indentation. The line .on "ajax:success" must be indented at the same level as the other .on. And the code that follows must be indented accordingly as well:
jQuery ->
# Create a comment
$(".comment-form")
.on "ajax:beforeSend", (evt, xhr, settings) ->
$(this).find('textarea')
.addClass('uneditable-input')
.attr('disabled', 'disabled');
.on "ajax:success", (evt, data, status, xhr) -> #<-- this line!
$(this).find('textarea')
.removeClass('uneditable-input')
.removeAttr('disabled', 'disabled')
.val('');
$(xhr.responseText).hide().insertAfter($(this)).show('slow')

rails: accessing a non-instance variable in js.erb

I have a page that renders multiple forms. Currently, when the user submits any one of these forms, it updates (via ajax) a div on the same page with the content from the form that was just submitted.
I also want to remove() the form element that was just submitted after the ajax post request is completed. However, I need to be able to access that specific form ID within the js.erb file to do so.
Since my page has x number of forms rendered dynamically, I cannot simply access an instance variable in my js.erb.
Page:
<% for peer_review in #peer_reviews %>
<%= render :partial => 'form', :locals => { :peer_review => peer_review } %>
<% end %>
<div id="completed_peer_reviews">
<%= render 'completed_peer_reviews' %>
</div>
The #peer_reviews instance variable contains an array of new PeerReview objects already containing some data.
Form:
<div id="peer_review_form_<%= peer_review.reviewee_id %>">
<%= form_for peer_review, :html => { :method => "post" }, :remote => true do |f| %>
<%= f.error_messages %>
<p>
Peer Review for: <%= User.find(peer_review.reviewee_id).name %><br />
</p>
<p>
<%= f.label :rating %>:
<%= f.select :rating, [1, 2, 3, 4, 5], { :include_blank => 'None' } %>
</p>
<p>
<%= f.label :review %><br />
<%= f.text_area :review %>
</p>
<%= f.hidden_field :user_id, :value => peer_review.user_id %>
<%= f.hidden_field :reviewee_id, :value => peer_review.reviewee_id %>
<%= f.hidden_field :review_period_id, :value => peer_review.review_period_id %>
<p><%= f.submit "Submit" %></p>
<% end %>
</div>
js.erb:
$("#completed_peer_reviews").html("<%= escape_javascript(render('completed_peer_reviews')) %>");
I was hoping to just add another line to the js.erb file that removes the form element that just triggered the execution of the js.erb file like so:
$("#peer_review_form_<%= peer_review.reviewee_id %>").remove();
How should I actually be referencing peer_review.reviewee_id here? Or should I be taking a completely different approach?
This is one of the classic issues of RJS templates.
Quick answer:
If you simply want to solve the problem, you could pass along some temporary id to identify the form. e.g:
# in the index
<% #peer_reviews.each.with_index do |peer_review, i| %>
<%= render :partial => 'form',
:locals => { :peer_review => peer_review, :i => i } %>
<% end %>
# then in the form (note, you don't need to specify POST in a form_for)
<div id="peer_review_form_<%= i %>">
<%= form_for peer_review, :remote => true do |f| %>
<%= hidden_field_tag 'temp_id', i %>
# finally in the create js.erb
$("#peer_review_form_<%= params[:temp_id] %>").remove();
Longer Answer:
That being said, while RJS templates were "the Rails way" for a long time, they've since fallen out of favor.
The more modern method is typically client side JS templates with a JSON API, rather than running server generated JS templates (RJS). This has a lot of advantages, one being that the DOM binding issue you're having right now no longer exists.
This is an example of how you might do this with pure jQuery, but there are many templating options out there.
<script id="peer_review_tmpl" type="text/x-jquery-tmpl">
<div class="completed_peer_review">
<p>${review}</p>
...
</div>
</script>
Then you'd create a handler and bind it to a successful ajax response. This would require that your peer_reviews#create action responded to JSON:
$('form.new_peer_review').bind("ajax:success", function(data) {
// remove the form which triggered the creation
$(this).remove();
// then render the data into a template, and append it to the list
$("#peer_review_tmpl").tmpl(data).appendTo("#completed_peer_reviews");
});

Categories