Populating modals with dynamic ids in Rails - undefined local variable - ruby-on-rails

So..I’m trying to understand usage of modals in Rails and looking for a few pointers.
I have a list of items at at category/1 which are being displayed in a loop. I have a modal which I’m rendering at the bottom of the page with <%= render "category/update_item_modal" %>
There’s already a form setup for updating params of each item, but I’m trying to get a modal pop up to specifically just update the title. The modal popup works, and so far I have the following for the button which opens the modal:-
<button class="btn btn-primary btn-sm">Edit Title</button>
And the modal itself:-
<div class="modal fade" id="updateItemModal-<%= item.id %>" tabindex="-1" role="dialog" aria-labelledby="updateItemModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="updateItemModalLabel">Change Item</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<!-- UPDATE TITLE HERE? -->
</div>
</div>
</div>
</div>
This gives me the error of undefined local variable "id" from the modal id for obvious reasons, and this is where my understanding hits a wall. How do I pass the data from a loop iteration into my modal?
End goal is to have an editable textarea field with the existing title in it, and a submit button which will post the edit.

Provided you have defined #item in your controller:
<%= render "category/update_item_modal", locals: item: #item %>
Then you have access to item in your partial. One more thing you can do to avoid that error is to use the safe operation operator item&.id. More on the safe navigation operator here: https://bugs.ruby-lang.org/issues/11537

Related

Render a Show Page Inside an Index Page on a Modal

Say I have a Scaffolded Post with just one field, body.I would like to render the show page for any post by clicking show only instead of loading a separate show page, It loads it inside a modal. Kinda like twitter does
I assume you are using Bootstrap and you would like to use a modal. You will have the list view have the modal with some links.
Now to get the data, we can do it either on page load (lets say data attributes), or on demand through XHR.
I like to get things on demand... so lets make a modal and some links.
<% #posts.each do |post| %>
<%= link_to post.title, post_path(post), remote: true, data: { method: 'get' } %>
<% end %>
<div class="modal fade" tabindex="-1" role="dialog">
<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">Modal title</h4>
</div>
<div class="modal-body">
<p>One fine body…</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
Then in the controller we need to make it fire...
class PostsController < ApplicationController
def show
#post = Post.find(params[:id])
respond_to do |format|
format.js
end
end
end
In the view show.js.erb we will do some thing like this.
$('h4.modal-title').html("<%= #post.title %>");
$('.modal-body p').html("<%= #post.body %>");
$('.modal').modal();
Let me know if it has bugs, I just wrote it out of my head and the modal code came right from Bootstrap with no editing. You will probably have to refactor them to make sense.
You cannot render the entire show page directly, but you can do this with a partial. I would recommend creating a partial that encapsulates all of the view information that is common to your show page and your modal. You can then reference that partial in both your show page and your modal reducing the amount of duplicated code.
Partials are normal view files with an underscore as the first character of the file name. For example: _post.html.erb.
You render the partial inside other views with the render command:
#show.html.erb
<%= render 'post' %>
I would also recommend the Rails Guide on Layouts and Rendering

Rails way to pass data from 'for' to modal

I'm trying to pass a variable being defined in an 'for' loop down to a modal button. Currently I have the modal block being rendered in the for as a quick win but I find it redundant to be making the entire modal block in the DOM for nothing.
<h3>User</h3>
<p>Name: <%= #user.name if #user.name %></p>
<p>Email: <%= #user.email if #user.email %></p>
<% #user.authentications.each do |i| %>
<%= i.provider.titleize %><br>
<%= i.created_at.strftime("%m/%d/%Y") %><br>
<button type="button" class="btn btn-info btn-lg modal-btn-swap" data-toggle="modal" data-target="#myModal" data=<%= i.id %>>Delete Auth</button>
<!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Remove authorization</h4>
</div>
<div class="modal-body">
<p>Some text
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<%= button_to 'Delete Auth', deauth_url(i.id) %>
<button type="button" class="btn btn-default"></button>
</div>
</div>
</div>
</div>
<% end %>
The concept is to just get a modal popup to give legal information prior to completing the transaction.
I'm thinking I'll need ot use jQuery to swap the href for the link when I click the 1st Delete Auth button.
Input?
If you create the modal once, you will have to write some javascript in the button click handler to populate the modal's attributes with the data you want each time you click, rather than hard coding it into each copy of the modal as you are doing now.
The ruby code would generate the modal -- you would have to leave the button_to('Delete Auth') without a target. Then you can copy the values from the data attribute to the modal when you click the button.

Call Bootstrap 3 Modal from an MVC razor model?

Currently I'm using a Model that after posting back from a Form I look at a model property to display an Alert. However I now need to have a Modal displayed instead. I know I need a Modal div at the bottom of my page to display but I can't figure out how to call that from the Razor Model.
Researching ideas all I've found is where a button click or some click event would call some JS and show the modal. I can't find anything on how to just open it from the View.
The concept is that the end user will click a button do basically do like a Time Stamp into the database. In the controller I set a MessageType property and then based on that I would show say a Bootstrap Error Alert if there was an error or Success Alert if everything was okay. Now instead of calling the Success Alert I need to open a Modal.
Here is how I'm doing it now with an Alert. This is in my MVC View. Is there a way to do the same but instead of Alert open a Modal?
#if (Model.MessageType == "PUNCH")
{
<div class="alert alert-success">
<h3>Punch accepted at <strong>#Model.CurrentTime.</strong></h3>
</div>
}
Similar to what you did, you may execute the javascript code which shows the modal dialog.
Assuming you have the required bootstrap files loaded to your page,
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel">
<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">Modal title</h4>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
#section Scripts
{
#if (Model.MessageType == "PUNCH")
{
<script>
$('#myModal').modal();
</script>
}
}

Display a modal conditionally on page load

I have a form in my view, and upon submission, my controller validates the fields and returns a list of errors in #errors, if any.
Now, I want to display these errors in a modal.
Here's what I have in my View:
!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<%= render 'shared/errors' %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
I want to display this modal on page load, if and only if #errors exists.
It looks like coffeescripts don't have access to variables passed by the controller.
I came across a few similar questions, but none of them seem to solve my problem.
you can do this with the help of gon gem.
Add "gem 'gon'" to your Gemfile.
run bundle install.
set value in controller like this: gon.form_errors = true if #errors.present?
Add this line in application layout in head section before all javascript include tags:- For rails 4: <%= Gon::Base.render_data %> and for rails 3 <%= include_gon %>
Now you can access this variable in your coffee file like this: gon.variable_name and use it like this:
if gon.form_errors
$('#your-modal-id').modal('show')

Getting data in each loop rails

In my rails application I have this each loop
<ul>
<% #job.job_applications.each do |job_application| %>
<li>
<%= raw (simple_format(job_application.cover_letter)) %>
<!-- Button trigger modal -->
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#pdfModal">
view cv
</button>
<!-- Modal -->
<div class="modal fade" id="pdfModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" style = "height:500px; width:1000px;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body" style = "height:500px; width:1000px;">
<iframe src="<%= job_application.resume.url %>" frameborder="0" style = "height:100%; width:100%;"></iframe>
</div>
</div>
</div>
</div>
</li>
<% end %>
</ul>
So what I'm trying to do is to get the cover_letter and open the resume in modal for every job_application but the problem is for resume because whatever the resume that I open it will show the first application resume in modal So I am wondering why I'm getting this is there any error in my code because something like thsi <%= link_to "Applicant cv", job_application.resume.url %> work just fine but I want to open resume in modal
Your problem is that you are creating many modal divs, all with the id of "pdfModal", and every button on your page is targeting the SAME id. In CSS, an ID is supposed to be used only once per page. So, to fix your problem, I'd suggest adding an index to your each loop, naming each modal according to the index, and then having the button point to that specific modal.
<% #job.job_applications.each_with_index do |job_application, index| %>
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#pdfModal-<%= index %>">
<div class="modal fade" id="pdfModal-<%= index %>" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">

Resources