Bootstrap Modal window doesn't render model validation errors - javascript

I have a basic modal window on my home page that renders a form to create a new Post.
I have a length validation in the Post model and want the form to display an error if it doesn't meet the minimum length.
This is the Post model:
class Post < ApplicationRecord
belongs_to :user
validates :content, length: { in: 1..400 }
end
And this is my home.html.erb view
<!-- Modal button -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#tweetModal">
New Tweet
</button>
<!-- Tweet Modal -->
<div class="modal fade" id="tweetModal" tabindex="-1" aria-labelledby="tweetModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="tweetModalLabel">Send a new Tweet</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">X</button>
</div>
<div class="modal-body">
<%= simple_form_for #post, remote: true do |f| %>
<div class="form-inputs">
<%= f.input :content %>
</div>
<div class="form-actions">
<%= f.submit "Submit", class: "btn btn-primary"%>
</div>
<% end %>
</div>
</div>
</div>
</div>
Post controller:
class PostsController < ApplicationController
before_action :set_user
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.user = #user
if #post.save
redirect_to root_path
else
render :new
end
end
private
def post_params
params.require(:post).permit(:content)
end
def set_user
#user = current_user
end
end
The modal window won't render the error and the only way I've found to render it is to render :new if the Post could not be saved.
The problem with that is that it will render the new.html.erb view that belongs to Post instead of the modal window that I have in my home page.
Can I make the modal window display the error? Should I move the modal window code to a separate partial file and use JS to render it?

Related

rails 6 dynamic bootstrap modal using js.erb error

I'm trying to display bootstrap modal with dynamically, so every time user click on record it shows modal with that record information. I don't want to show modal for all record every time I reload the page.
I got this error in browser console.
SyntaxError: Unexpected token '==='
Controller
events_controller.rb
def pay
#event = Event.find(params[:id])
respond_to do |format|
format.js{}
end
end
View
index.html.erb
<%= link_to pay_path(id: event.id), remote: true, class: "", method: :patch do %>
Paid <i class="fe fe-dollar-sign"></i>
<% end %>
Pay view
_pay.html.erb
<!-- Modal: pay invoice -->
<div class="modal fade show" id="pay_invoice" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-vertical" role="document">
<div class="modal-content">
<div class="modal-body">
<!-- Modal body -->
</div>
</div>
</div>
</div>
js.erb
pay.js.erb
document.querySelector("#pay_invoice").insertAdjacentHTML('afterbegin', "escape_javascript(<%= render partial: 'pay', locals: {event: #event} %>)");
document.querySelector("#pay_invoice").modal('show');
Routes
routes.rb
patch "events/:id/pay", to: "events#pay", as: :pay
any help?
You need to move the ERB tags outwards so that you actually call escape_javascript:
document.querySelector("#pay_invoice").insertAdjacentHTML(
"afterbegin",
"<%= escape_javascript(render partial: 'pay', locals: { event: #event }) %>"
);
The reason you are getting a syntax error is that you're outputting the partial unescaped and it contains at least one double quote which ends the string.

uncaught TypeError: ajaxForm is not a function in rails version 5?

I am trying to submit the modal form using ajaxForm and display the response in modal itself. But, I am getting uncaught type error (...).ajaxForm is not a function.
Basically I want to create a modal form for lesson creation form and have to submit , my app consists of both API controller and front end controller.
api!
param_group :lesson
description 'creates a lesson'
example "
{
'id': 12,
'title': 'MUDRAS',
'active_video_id': 3,
'description': 'Description of the lesson',
'points': null,
'is_public': '1',
'videos': [
{
'video': {
'id': 1,
'video': {
'url': '/uploads/video/video/1/250-authentication-from-scratch.mp4'
},
'title': null,
'storage_type': 'Lesson',
'storage_id': 12
}
},
]
}"
def create
#lesson = Lesson.new(lesson_params)
#lesson.creator = current_user
if #lesson.save
render json: {
success: true,
message: "Lesson created Successfully"
}
else
render json: { success: false, message: "Could not Create : #{#lesson.errors.full_messages.join(', ')}" }
end
end
def new
#lesson = Lesson.new
end
The above code is my API controller.The below codes are my Front end controller and lesson related forms.
def create
#lesson = Lesson.new(lesson_params)
if #lesson.save
render json: {
success: true,
message: "Lesson Created Successfully"
}
else
render json: {
success: false,
message: "Lesson Creation Failed"
}
end
end
I need to display the "New Lesson" button in Lesson Index page.
lessons/index.html.erb
<% unless current_user.student? %>
<div class="container-fluid">
<div class="col-md-3 col-sm-3 text-left">
<div id="newLesson" class="lesson-category btn-danger" lesson_url="<%= new_lesson_path %>">
<i class="fa fa-plus"></i> ADD LESSON
</div>
</div>
</div>
<div class="hidden" id="newLessonForm">
<% #lesson = Lesson.new ; #lesson.videos = [Video.new] %>
<%= render "lessons/form" %>
</div>
<% end %>
<%= render "shared/primary_modal" %>
<div class="container-fluid">
<div class="col-md-3 col-sm-3 text-left">
<h2 class="main-tab tab-active">LESSONS</h2>
</div>
<div class="col-md-9">
<div class="col-md-12 text-right">
<h2 class="main-tab tab-inactive"><a id="responsesLink" class="blacko" href="#"><%= "MY" if current_user.student? %> RESPONSES</a></h2>
</div>
</div>
<div class="col-md-12"><hr/></div>
<!-- Lessons of this course Go here -->
<div class="col-md-3">
<% #lessons.each do |lesson| %>
<div id="lesson_<%= lesson.id %>" class="pill video-view lesson-load" data-lesson-id="<%= lesson.id %>" data-src="<%= lesson.active_video_url %>"><%= lesson.title %></div>
<% end %>
<!-- <div class="pill pill-inactive">Something</div> -->
</div>
<!-- Lesson Content goes here -->
<div class="col-md-9">
<div class="row">
<div class="col-md-12">
<%= render "shared/video_player" %>
</div>
</div>
<div id="lessonContent">
</div>
</div>
</div>
<script>
$("#newLesson").click(function(){
var lesson_path = $(this).attr("lesson_url");
$.get(
lesson_path,
function(content){
$("#primaryModalContent").html(content);
$("#format").val('js');
$("#primaryModal").modal("show");
}
);
});
</script>
My lesson creation form is given as a partial.
<div class="col-md-12">
<%= simple_form_for #lesson, html: {class: "newLessonform"} do |f| %>
<%= f.input :title, label: "Lesson Title", required: false %>
<%= f.input :description, required: false, as: :text %>
<%= f.input :points, required: false, as: :integer %>
<%= f.input :is_public, label: 'Check to Make this lesson public', as: :boolean %>
<div class="col-md-12">
<% unless #lesson.new_record? or #lesson.active_video_url.blank? %>
<h4> Currently Linked Video </h4>
<video src="<%= #lesson.active_video_url %>" style="width: 400px;"></video>
<% end %>
<hr/>
</div>
<h4>Add <%= #lesson.videos.blank? ? "a" : "another" %> Video</h4>
<% #lesson.videos = [Video.new(title: "")] if #lesson.videos.blank? %>
<%= f.simple_fields_for :videos do |g| %>
<%= g.input :title, label: "Video title" %>
<%= g.input :video, as: :file, lebel: "Select Video" %>
<% end %>
<center><%= f.submit class: "lesson-category btn-danger" %></center>
<% end %>
</div>
<script type="text/javascript">
$(".newLessonform").ajaxForm(function(data) {
$("#primaryModalContent").html(data.message);
});
</script>
In the above script , I have given ajaxForm. The modal form for this is given below.
<div class="modal fade" id="primaryModal" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" , data-dismiss="modal">×</button>
<h1 class="modal-title" id="modalTitle"></h1>
</div>
<div class="row modal-body" id="primaryModalContent">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
The error in chrome console , was uncaught error:(...)$.ajaxForm is not a function.
I am stuck in this for about a week. Could any one give me a solution.
Thanks in advance.
The best way to use an AJAX form in rails is to use rails_ujs.
First you have to tell rails_ujs that you want an AJAX action on your form :
<%= simple_form_for #lesson, html: {class: "newLessonform"}, remote: true do |f| %>
Then add a new file in your views, this view will be rendered after a successfull create action initiated by an AJAX action : views/lessons/create.js.erb
Inside you can put you js code, this code will be executed on the same page as the AJAX form. This is just a view and you can use variables from the controller.
$("#primaryModalContent").html("<%= #message %>")
Finally, you need to update your controller to handle AJAX action :
def create
#lesson = Lesson.new(lesson_params)
if #lesson.save
#success = true
#message = "Lesson Created Successfully"
else
#success = false,
#message = "Lesson Creation Failed"
end
respond_to do |format|
format.js
end
end
Here you can find some documentation about Rails UJS :
http://guides.rubyonrails.org/working_with_javascript_in_rails.html#remote-elements
https://blog.codeship.com/unobtrusive-javascript-via-ajax-rails/

How can I render the show action inside of the Bootstrap 4 Modal?

I'm having with populating the bootstrap 4 modal with a show action for a clickable image link. I'm currently using Carrierwave for uploading images. At this point, when I click the image, only the modal overlay displays. The modal container with content inside of it, doesn't show at all.
User/Show.html.erb
<div class= "container">
<div class="username">#user.username</div>
<div class="posts_container_pos">
<hr style="border: 2px solid #515558;">
<%= render 'posts/posts', post_items: #user.posts %>
</div>
</div>
Posts/_Posts.html.erb
<div class"container-fluid">
<%= #post_items.each do |post| %>
<%= link_to image_tag(post.photo.url(:medium), style: 'height: 300px; width: 500px;'), modal_post_path(post), data: {:toggle => 'modal', :target => '#reusable_modal'}, lazy: true %>
<div id="post-modal" class="modal fade"></div>
<!-- Modal -->
<div class="modal fade" id="reusable_modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
</div>
</div>
</div>
<% end %>
<script type= "text/javascript">
$(document).on('page:change', function () {
$(document).on('click', '#reusable_modal [data-dismiss="modal"]',
function (e) {
$(e.target).removeData('bs.modal');
$('#reusable_modal').find('.modal-content').empty();
});
$(document).on('click', '[data-target="#reusable_modal"]', function (e) {
$("#reusable_modal").find(".modal-content").load($(this).attr("href"));
});
});
</script>
</div>
Posts/Modal.html.erb
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<i><%= image_tag(#post.user.avatar_url(:thumb), class: 'round-image-50') %></i>
<h4 class="modal-title" id="myModalLabel" style="margin-left: 60px; margin-top: -42px;"><%= post.user.username %></h4>
</div>
<div class="modal-body">
<% if #post.photo.present? %>
<%= image_tag(#post.photo.url(:large), style: 'max-width: 570px;') %>
<% end %>
<div class="modal_post_pos">
<%= sanitize content_with_emoji(#post.body) %>
</div>
</div>
<div class="modal-footer">
<%= render partial: 'comments/template', locals: {commentable: #post, new_comment: #comment} %>
</div>
Users_Controller.rb
def show
if params[:id].to_s.match(/^[0..9]+$/) && !User.friendly.exists?(params[:id])
render 'public/404.html', status: 404
else
#user = User.friendly.find(params[:id])
#post_items = #user.posts.paginate(page: params[:page])
end
end
Posts_Controller.rb
def modal
render layout: false
end
def show
#post = Post.find(params[:id])
#new_comment = Comment.build_from(#post, current_user.id, "")
respond_to do |format|
format.html
format.js
format.json {render json: #post }
end
end
Routes.rb
resources :posts, except: [:edit, :update] do
member do
get 'like', to: 'posts#like'
get 'dislike', to: 'posts#unlike'
get :modal
end
end
Server Log
Started GET "/posts/13/modal" for 127.0.0.1 at 2016-04-11 11:41:00 -0400
ActiveRecord::SchemaMigration Load (0.5ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by PostsController#modal as HTML
Parameters: {"id"=>"13"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 5]]
Rendered posts/modal.html.erb (47.5ms)
Completed 500 Internal Server Error in 240ms (ActiveRecord: 1.5ms)
NoMethodError - undefined method `user' for nil:NilClass:
app/views/posts/modal.html.erb:5:in `_app_views_posts_modal_html_erb__227267806_63456696'
Since you dont have any instance variable #post defined on _posts partial and still trying to call it within _posts, its throwing up error.
The approach to solve this issue if you want to use Bootstrap Modal without extra js script is to bring _post partial code to _posts partial itself and <% end %> the loop after modal.
<% #post_items.each do |post| %>
<%= link_to image_tag........................
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Post Show</h4>
</div>
<div class="modal-body">
# complete partial code goes here
</div>
</div>
</div>
</div>
<% end %>
Obviously above approach is not good for performance as it will render everything without the need for it.
Better approach is to use Ajax using jQuery (my preference). listen for this button event (onClick) and load modal on the fly using ajax get method. consider looking at this approach for better performance reasons.
The second solution i am talking about is well explained here: https://stackoverflow.com/a/22144587/2545197
Maybe something like this?
In your JS
var $modal = $('#ajax-modal');
$.fn.modalmanager.defaults.backdropLimit = 1;
$('.modal-link').on('click', function(){
var modal_url = $(this).data("modal-url");
if(modal_url != null){
// create the backdrop and wait for next modal to be triggered
$('body').modalmanager('loading');
$modal.empty().load(modal_url, '', function(){
$modal.modal();
// Any callback functions such as let's say selectpicker
// $('#ajax-modal .selectpicker').selectpicker('refresh');
});
return false;
}
});
and in ERB
<%= link_to 'Show', post_path(#post), class: 'modal-link', data: { modal_url: post_path(#post) } %>
I solved this problem by simply rendering the file for the modal show view instead of the normal show action.
def show
#post = Post.find(params[:id])
#new_comment = Comment.build_from(#post, current_user.id, "")
respond_to do |format|
format.html {render :file => "posts/modal", layout: false}
format.js {render :file => "posts/modal", layout: false}
format.json {render json: #post }
end
end

Displaying flash messages on modal dialog box on submit rails

I am trying to build the modal box for registering emails addresses in rails.
I have done it but can not able to find the way to display the flash messages on modal dialog box when registration fails.
On submit the box gets closed and message is only getting display on home page. I do not have good knowledge of web or rails, but would be nice if I can get some pointers.
The functionality is working fine expect on fail, dialog box should display the messages on it instead of on home page. I know where is issue in my code but do not know approach to do it. Here is my code for dialog box
<div id="register" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<%= form_for(#email, url: home_esave_path, :html => {class:"model-dialog"}) do |f| %>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Register</h4>
</div>
<div class="modal-body">
<div class="form-group">
<%= f.text_field :email, class:"form-control", placeholder: "Enter a valid gmail address" %>
</div>
<%= f.show_simple_captcha(:email=>"email", :label => "Human Authentication", :refresh_button_text => "Refresh text", class:"form-control", :placeholder => "Enter the code") %>
<%= f.submit "Register me!", :class => "btn register_button" %>
</div>
<div class="modal-footer" style="text-align:left">
<!-- show in case of success -->
<% if #email.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#email.errors.count, "error") %> prohibited
this email from being saved:
</h2>
<ul>
<% #email.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
<% end %>
</div>
</div>
my controller code to get the messages
def save
#email = Email.new(user_params)
if !user_params.nil?
if #email.save_with_captcha
flash[:success] = "Success! The email address #{#email.email} has been successfully registered. We will contact you as soon as we have available rooms for new beta testers."
redirect_to :action => 'index'
else
if #email.valid?
flash[:error] = "The captcha is not correct, enter again the captcha."
redirect_to :action => 'index'
else
flash[:error] = "You have put invalid #{#email.email}"
redirect_to :action => 'index'
end
end
end
end
Flash messages I am displaying outside this model which is obvious that will be displayed on home page. But I did not find way to display it on model dialog box.
here is how I am displaying the messages
<% flash.each do |type, message| %>
<div class="alert <%= alert_for(type) %> fade in">
<button class="close" data-dismiss="alert">×</button>
<span class="sr-only">Close</span>
<%= message %>
</div>
<% end %>
Thanks for suggestions
Flash is designed as a way to pass data between (controller) actions (see documentation for more information). In your case, you specifically, do not want an action, so I don't think there is a way to do this.
You can however generate a message that looks like your other flash messages using Ajax. Here is one way to do it.
You will need the following components:
Remote call from modal
Add remote: true or :remote => true to your form within the modal. This tells Rails that you want an Ajax call to the server when the form is submitted, not a full page post.
Controller changes
You'll need to respond to formats other than HTML. Something like this:
def save
if !user_params.nil?
#email = Email.new(user_params)
#email.save_with_captcha
respond_to do |format|
format.html { redirect_to #email, notice: 'This should not happen.' }
format.json { render action: 'show' }
format.js { render action: 'show' }
end
end
end
Javascript to insert/clear "flash" error message in your modal
View file - show.js.erb (can be named differently but name should match action above).
$('#build_error').remove();
<% if #email.errors.any? %>
var build_error = "<div class='alert alert-danger' id='build_error'>";
build_error += "The form contains <%= pluralize(#email.errors.count, 'error') %>.";
build_error += "<ul id='error_explanation'>";
<% #email.errors.full_messages.each do |msg| %>
build_error += "<li><%= j msg %></li>";
<% end %>
build_error += "</ul>";
build_error += "</div>";
$(build_error).insertBefore( "#xxxxxx" );
<% else %>
$('#email-modal').modal_success();
<% end %>
Basically, you'll need to clear any previous "flash" error message (the first line) and then either display the new one (you'll need to find somewhere in the DOM to attach it - see xxxxxx) or close the modal. Pretty brute force but it works for me.
Hopefully you get the idea - I doubt any of this will work as is so you will need to understand the concept.

Rails Modal Popup after create action

I have a simple vote action in my rails app and i would like a modal popup (like the on in twitter bootstrap) to show after a successful create action. I have a modal view partial, a respond_to block that accepts .js and a create.js.erb file which should in theory be displayed when the create action is called, if im not mistaken?
I just don't quite understand how to wire all of these things together, ( also i assume the javascript is incorrect) any tips would be great thanks!
controller.rb
def create
#vote = Vote.new(params[:vote])
respond_to do |format|
if #vote.save
format.html { redirect_to :back, notice: "Thank you for voting! why not Tweet your vote?" }
format.js <!--should there be a call to a specific file here?-->
else
flash[:error] = "please try again"
redirect_to :back
end
end
end
end
votes/info.html.erb
<div class="modal hide fade">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3>Thanks for voting!</h3>
</div>
<div class="modal-body">
<p>Why not tweet your selection?</p>
</div>
<div class="modal-footer">
Close
Save changes
</div>
</div>
votes/create.js.erb
$(".modal").html(<%= escape_javascript render partial: 'votes/info' %>);
$(".modal").show();
vote _form.html.erb
<%= form_for([Vote.new(hotel_id: hotel.id)]) do |f| %>
<%= f.hidden_field :hotel_id %>
<%= f.submit "Vote", class: "btn-large btn-info" %>
<% end %>
You didn't show us votes/new.html.erb but I think the problem is that <div class="modal hide fade"> needs to be in that file, not the partial. Also, ensure that the partial file name begins with an underscore, "_info.html.erb".

Categories

Resources