Alex Zakruzhetskyi Alex Zakruzhetskyi - 4 months ago 21
Ajax Question

Inline error messages in a form_for with remote: true

I have a form in a modal that looks like this:

<%= form_for (@change_office_address_), remote: true, format: :json, html: { class: :contact_form } do |f| %>
<div id="error_explanation" style='display:none;' class="bg-danger text-danger alert fade in alert-danger alert-dismissable errors">
<ul>
<% if @change_office_address_.errors.any? %>
<% @change_office_address_.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
</ul>
</div>
<%= f.hidden_field :city_id, value: @office.city.id %>
<%= f.hidden_field :office_id, value: @office.id %>
<%= f.hidden_field :insurer_id, value: @office.insurer.id %>
<%= f.text_field :name, placeholder: 'Name', class: 'form-control' %>

<br>
<%= f.text_field :email, placeholder: 'e-mail', class: 'form-control' %> <br>
<%= f.label :city_name, 'City' %>
<%= f.text_field :city_name, class: 'form-control', value: @office.city.name.mb_chars.titleize, readonly: true %>
<br>
<%= f.label :insurer_name, 'Insurer' %>
<%= f.text_field :insurer_name, class: 'form-control', value: @office.insurer.short_name, readonly: true %>
<br>
<%= f.label :office_name, 'Insurer\'s office address' %>
<%= f.text_field :office_name, class: 'form-control', value: @office.address, readonly: true %>
<br>
<%= f.text_field :edit_office_address, placeholder: 'New address', class: 'form-control' %> <br>
<%= f.text_area :comment, placeholder: 'Comment', class: 'form-control', cols: '30', rows: '5' %> <br>
<div class="text-center">

<%= f.submit 'Inform about deleting', class: 'btn btn-danger' %>
<%= f.submit 'Inform about changing address', class: 'btn btn-default' %>
</div>
<% end %>


After the form was submitted, and validations didn't pass, I can see error messages at the top of my form. But I'd like to show errors inline. I tried to add
<span class="help-inline"><%= @change_office_address_.errors[:email] %></span>
into my form, but it doesn't work.

A controller:

class ChangeOfficeAddressesController < ApplicationController
def create
@change_office_address = ChangeOfficeAddress.new(change_office_addresses_params)
respond_to do |format|
if params[:commit] == 'Inform about changing address'
if @change_office_address.save
format.html { ChangeOfficeAddressMailer.change_office_address_new(@change_office_addres).deliver_now
redirect_to :back, notice: 'Thanks.' }
format.json { redirect_to :back, status: :created, location: @change_office_address,
notice: Thanks.' }
else
format.json { render json: @change_office_address.errors.full_messages, status: :unprocessable_entity }
end
elsif params[:commit] == 'Inform about changing address'
@change_office_address.delete_office_address = 'Some text'
@change_office_address.edit_office_address = nil
if @change_office_address.save
format.html { ChangeOfficeAddressMailer.change_office_address_new(@change_office_addres).deliver_now
redirect_to :back, notice: 'Thanks.' }
format.json { redirect_to :back, status: :created, location: @change_office_address,
notice: 'Thanks.' }
else
format.json { render json: @change_office_address.errors.full_messages, status: :unprocessable_entity }
end
else
if @change_office_address.save
format.html { ChangeOfficeAddressMailer.change_office_address_new(@change_office_addres).deliver_now
redirect_to :back, notice: 'Thanks.' }
format.json { redirect_to :back, status: :created, location: @change_office_address,
notice: 'Thanks.' }
else
format.json { render json: @change_office_address.errors.full_messages, status: :unprocessable_entity }
end
end
end
end

private

def change_office_addresses_params
params.require(:change_office_address).permit(:email, :name, :edit_office_address, :add_office_address,
:delete_office_address, :office_id, :insurer_id, :city_id, :comment)
end

end


And application.js:

$(document).ready(function() {
return $(document).bind("ajaxError", "form.contact_form", function(event, jqxhr) {
var $contact_form, $error_container, $error_container_ul;
$contact_form = $(event.data);
$error_container = $("#error_explanation", $contact_form);
$error_container_ul = $("ul", $error_container).empty();
if ($error_container.is(":hidden")) {
$error_container.show();
} else {
$("#error_explanation").remove("#error_explanation");
}
return $.each(jqxhr.responseJSON, function(index, message) {
return $("<li>").html(message).appendTo($error_container_ul);
});
});
});


Is there any way to add those error messages? Thanks.

Answer

To get inline validations, I would use Jquery Validate and validate on your change_office_address model.

When I had to do something similar I used this SO post as reference, which I paraphrase after:

How to use jquery validation plugin in rails

First include the jquery validation file in your layout, which can be found here:

https://jqueryvalidation.org/

Then in your form add a class to the required fields such as <%= f.text_field :firstname, :class => "required" %>. Then write a method with the form_id to trigger the validation.

function validateofficeFuction() {
    $("#change_office_form").validate({
        errorClass: "authError"
    })
}

$(document).ready(validateofficeFuction);
$(document).on('page:load', validateofficeFuction);

If you're using turbolinks 5, which is included in rails 5 instead of using $(document).ready use $(document).on "turbolinks:load"

If this is set up properly, you should get your error messages right underneath each field that failed instead at the top of the page or form.