Bootstrap Modal in Rails Keeps displaying the first record - ruby-on-rails

When I click on the View in Modal, it keeps on displaying only the first record. Even if I click on the second record it still displays the first one. Below is how I implemented the link_to toggle to modal box called myModal.
<%= link_to 'View in Modal', "#", data: {toggle: "modal", target: "#myModal"} %>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<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">Test</h4>
</div>
<div class="modal-body">
<span class="note"><%= raw(usernote.note) %></span>
</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>
</div>
</div>

The problem
I supposed you've done something like:
<% #usernotes.each do |usernote| %>
<%= link_to ... %>
// code of modal associated to the usernote
<% end %>
The problem is that you used the same html ID for all the modals (#myModal).Besides the fact ID duplication is not W3C conform, this is the cause of the issue.
When you will click on one of the links, it will open the first modal with the #myModal ID (which is the modal of the first record).
So, how to patch the issue?
Easy way: one modal per usernote
One way, the easy way, is to use different IDs for all the modals. For example:
<%= link_to ... data: {toggle: "modal", target: "#modalForUserNote#{ usernote.id }"} %>
<div id="modalForUserNote<%= usernote.id %>" ...>
// ....
But this way is not the best one: you just create one modal per usernote... If you have 1000 usernotes, you will generate 1000 modals in your html... This is obviously pretty bad...
An other way: javascript callback
An other way to do it will be to create only one modal and to edit its content with some Javascript code.
An example of code can be:
html code
// the modal code
<% #usernotes.each do |usernote| %>
<% link_to ..., data: {toggle: "modal", target: "#modal"}, 'data-usernoteid' => ..., 'data-usernotedata' => ... %>
<% end %>
javacript code (using jQuery)
$('.modalLink').on('click', function() {
$('#modal #idOfTheUserNote').html($(this).data('usernoteid'));
// ...
});
You can note the usage of data attributes.
Data attributes can be replaced by an AJAX request to your Rails application which will returns JSON data.
An other way: AJAX request
The last way to do it is to request your Rails application with an Ajax call. Your application will render an Javascript view (the code will be sent to your browser and evaluated).
This can be simply done by using the remote: true option in your link_to (rails will handle the ajax request by itself.
The following code can do the trick:
html code
// the modal code
<% #usernotes.each do |usernote| %>
<% link_to 'text', some_action(usernote), data: {toggle: "modal", target: "#modal"}, remote: true %>
<% end %>
controller code
def some_action
#usernote = Usernote.find_by_id(param[:id])
end
view to render: for example usernote/some_action.js.erb
$("#modal #modalIdOfTheUsernote").html("<%= #usernoed.id %>");
What is the best way to do it?
Obviously not the first one.
Choosing between the two others just depends on what you want to do:
For real time updates, AJAX request may be better. But you can get some latency because you need to wait the server response.
Otherwise, data attributes are good enough.

3 options here:
generate one modal for each record - the worst thing you can do
use data attributes to update content of the modal
use ajax action where you'll update the content of the modal and open the modal with $('#myModal').modal('show') http://getbootstrap.com/javascript/#modals-usage
1. generate one modal for each record
<% #usernotes.each do |usernote| %>
<%= link_to 'View in Modal', "#", data: {toggle: "modal", target: "#myModal_<%= usernote.id %>"} %>
<div class="modal fade" id="myModal_<%= usernote.id %>" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
....
<span class="note"><%= raw(usernote.note) %></span>
....
</div>
<% end %>
2. use data attributes to update content of the modal
<% #usernotes.each do |usernote| %>
<%= link_to 'View in Modal', "#", data: {usernote: usernote.note}, class: 'user_note_modal' %>
<% end %>
$('.user_note_modal').on('click', function() {
$('#myModal span.note').html($(this).data('usernote'));
$('#myModal').modal('show');
});
p.s. why use .modal('show')? just so you make sure to update the content of the modal first then display it.
3. use ajax action - assuming your resource name is UserNote and you have user_notes_controller with show action:
<% #usernotes.each do |usernote| %>
<%= link_to 'View in Modal', usernote_path(usernote), data: {toggle: "modal", target: "#myModal"}, remote: true %>
<% end %>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-body">
<span class="note"></span>
</div>
</div>
clicking on one link will trigger an ajax event that will expect a show.js.erb template, where you'll update the content of the modal and then display it:
app/views/user_notes/show.js.erb
$('.modal-body span.note').html('<%= j(render #usernote.note) %>');
$('#myModal_').modal('show');

Related

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.

The content is loaded into both modals

There are two modals being used in the Rails app.
One modal is used for editing (#editModal)
The other one is for displaying text (#textModal)
link_to for both the modals are:
<%= link_to edit_user_path(user), {:remote => true, 'data-toggle' => "modal", 'data-target' => '#editModal', 'data-backdrop' => 'static', :class => "icon-edit" } do %>
Edit
<% end %>
<%= link_to display_path(data), {:remote => true, 'data-toggle' => "modal", 'data-target' => '#textModal', 'data-backdrop' => 'static', :class => "icon-edit" } do %>
Display
<% end %>
_editModal.html.erb
<div id="editModal" class="modal fade edit-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
</div>
<div class="modal-body">
<%= render 'shared/ajax_load' %>
</div>
</div>
</div>
</div>
_textModal.html.erb
<div id="textModal" class="modal fade edit-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
</div>
<div class="modal-body msg-body">
<%= render 'shared/ajax_load' %>
</div>
</div>
</div>
</div>
The problem is when any of the link is clicked one modal is displayed, but the content is loaded into both the modals.
Am I doing anything wrong or that's how it works??
Well... Yes and Yes.
You are doing something wrong... and that's how it works. :)
The only difference I can see in your two modals is the id. Every other thing is the same... even up to the partial being rendered: <%= render 'shared/ajax_load' %>
What this means is that whenever you click any of the buttons, the partial 'shared/ajax_load' gets populated and will remain populated until you refresh the page.
Fix:
Two things I can readily suggest here:
1) You can decide to have separate partials rendered for the two modals
2) You can decide to use JS to populate the modal(If you want to use the single partial): then you will have the control to clear off the content of the partial before populating it and rendering into the respective modals
Hope I've been able to explain and hope you understand this.

Submit photo to database from Image Gallery in Rails

I have an images index page which displays an entire album of photos from the User's Facebook profile in a uniform square grid. To get the square grid shape, I had to use some css which crops a little bit of the image from the sides (essentially a thumbnail).
I want the users to be able to click on an image so that a modal comes up that shows the full image, which they can then crop themselves.
Most importantly, I'm wondering how to make it so the modal that pops up is like a form, where you select the part that you want cropped and then click submit, and the photo and crop parameters get saved to the database
Here is what I have so far:
<!-- 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-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Submit</button>
</div>
</div>
</div>
</div>
<% #profile = #graph.get_object("me") %>
<%= #profile["name"] %><br>
<%= link_to 'Sign Out', sign_out_path, method: :delete %>
<br>
<% #albums = #graph.get_connections("me", "albums?fields=name,photos{name, images{source}}") %>
<% #albums.at(3)["photos"]["data"].each do |data| %>
<div id="<%= data["id"] %>" class="myImages" data-toggle="modal" data-target="#myModal">
<%= image_tag data["images"].first["source"] %>
</div>
<% end %>
<script>
$(document).ready(function() {
$(".myImages").click(function (e){
e.preventDefault();
$(".modal-body").html($(this).html());
});
});
</script>

Rails form above Twitter Bootstrap modal

I'm trying to create a newsletter subscription from scratch using rails 4 and Twitter Bootstrap 3 modal.
I created a Subscriber model and subscribers controller which contains a 'create' method.
The button which openes the modal has to appear anytime, so I included it in the navbar that is placed in the application.html.erb layout view file.
This is the code I used for the modal: (in views/layout/application.html.erb)
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel">Newsletter Subscriptions</h4>
</div>
<% form_tag(controller: 'subscribers', action: 'create') do %>
<div class="modal-body">
<p><%= text_field_tag :email, params[:email] placeholder: "Enter your email address" %></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<p><%= submit_tag "Subscribe", class: "btn btn-primary" %></p>
</div>
<% end %>
</div>
</div>
</div>
For some reason it won't show anything in the modal except the title.
Where am I going wrong?
You just need to use <%= form_tag instead of <% form_tag.
In previous versions of Rails, <% form_tag was used I think, but since form_tag is outputting html, it should be used with <%= %>.

how to not improve this code to not repeat the twitter bootstrap modal?

I have a Project that have many Pictures. I am using the first picture as a link to call a twitter bootstrap modal, where some information will be displayed as well as the link for the project`s page.
<!-- Modal -->
<div id="<%= project.id %>" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3><%= project.title %> <small><%= project.sub_title %></small></h3>
</div>
<div class="modal-body">
<p><%= ActionView::Base.full_sanitizer.sanitize (project.description) %></p>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<%= link_to 'More Details', project_path(project), class: 'btn btn-primary' %>
</div>
</div>
In order to get the modal working for each project, I have added the project.id to the Modal id. So, I am actually creating many modals, one for each project.
<% #projects.each do |project| %>
<%= link_to (image_tag project.pictures.first.url), "##{project.id}", class: 'btn', role: 'button', data: { toggle: 'modal' } %>
<%= render 'projects/modal', project: project %>
<% end %>
Well, everything is working fine, but I don't like it! It will became a loading problem if I have many projects.
So, I would like to find a way to not load all modals. I would like to have one modal template that is populated by the project information.
Any idea on how to improve it?
NOTE: I don't have rails set up at the moment, so can't test this directly, but should work:
Put the following generic modal code into the modal partial:
<div id="genericModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3></h3>
</div>
<div class="modal-body">
<p></p>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<%= link_to 'More Details', nil, class: 'btn btn-primary' %>
</div>
</div>
Include the following at the top of your view:
<script>
function populateModal(projectId) {
$(".modal-header").find("h3").html($(projectId).find("#p_title").html());
$(".modal-body").find("p").html($(projectId).find("#p_desc").html());
$(".modal-footer").find("a").attr("href", $(projectId).find("#p_link > a").attr("href"));
$("#genericModal").modal('show');
}
</script>
Then further down in your view, you can do something like this:
<%= render 'projects/modal' %>
<% #projects.each do |project| %>
<%= link_to (image_tag project.pictures.first.url), html => {:onclick => "populateModal('##{project.id}')", :class => 'btn', :role => 'button'} %>
<div id="#{project.id}" class="hide">
<span id="p_title"><%= project.title %> <small><%= project.sub_title %><small></span>
<span id="p_desc"><%= ActionView::Base.full_sanitizer.sanitize (project.description) %></span>
<span id="p_link"><%= link_to project_path(project) %></span>
</div>
<% end %>
Create a single modal, not one for each project. Use javascript to open the modal on each link (instead of data-toggle="modal") and before you do, set the project's title, subtitle, description and link using Javascript.

Resources