I'm trying to open a modal that displays a list of items. The list of items is already available in the view as a variable. How do I pass this variable to the modal?
Below is roughly how the main view looks like:
View.html.erb
<div>
<%= #users.each do |user|%>
<h1>user.name</h1>
<h2>user.email</h2>
<%= link_to remote: true, 'data-toggle' => 'modal', 'data-target' => '#taskModal do %>
<i><%= user.tasks.count%></i>
<% end %>
<% end %>
</div>
<div class="modal" id="taskModal" aria-hidden="true">
...
<%= render partial: 'list_modal' %>
list_modal is a partial with the structure of the modal.
As opposed to having the list of items already on the view, and wanting to pass it to the modal, One thing you can do is make the button ( or link ) for opening the modal to call a controller action by ajax, and then let the action respond to JS, where you will now use the corresponding view.js file to both populate the modal as well as programmatically render it ( after populating it ).
Example:
Link to open modal:
<%= link_to "Open users list", users_open_list_modal_path, remote: true %>
Users open list modal controller action:
def open_list_modal
#user_list = User.all
respond_to do |format|
format.js
end
end
open_list_modal.js.erb:
//populate modal
$('#modal').html('#{ escape_javascript(<%= render partial: 'user_list', locals: {user_list: #user_list} %> )}');
//render modal
$('#modal').openModal();
And then on the modal itself, you can now have access to the user_list (NOT #user_list) list.
Note: In this example, I made use of both erb, js, and material-modal. If you are using something different from these ( maybe slim, haml, coffee, bootstrap...), you will have to suite the example to your case.
Hope this helps.
you can just directly pass it to modal. here what i did thou, on my view i have a button that trigger my modal and then i created a partial (to DRY up my code) _modal.html.erband called that partial after my button.
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#modal"></button
<%= render 'modal' %>
make sure your modal has id <div class="modal fade" id="modal" tabindex="-1" role="dialog">...
gl mate!
You can set it as how you would normally do for view components. Better yet, separate out your model into partial, say it's _modal.html.erb. Then you can call the modal by
<%= render 'partial_name', :variable_name => your_current_variable %>
The variable would now be available as variable_name inside the partial. Also, if it's an instance variable like #your_current_variable then it will be automatically available in your partial.
Related
I have a menu item that fires ajax that returns javascript partial that is a bootstrap modal. The problem I am having is when a user clicks the menu item the first time, the modal opens as expected. The user closes the modal and tries to open it again, it doesn't open (although the ajax fires again from backend).
Consider the following code (using bootstrap 4):
Menu.html.erb:
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">
<%= link_to user_profile_path(current_user.user_profile.id), remote: true, class: "dropdown-item" do %>
<%= fa_icon "id-card", text: "Profile Settings" %>
<% end %>
</div>
...
<div id="user_profile"></div>
user_profile/show.js.erb (ajax js partial):
$("#user_profile").replaceWith("<%= j render "user_profile" %>");
user_profile/_user_profile.html.erb (bootstrap modal):
<script>
$('#user_profile_modal').modal('show');
</script>
<%= form_with model: #user_profile do |f| %>
<div class="modal fade" id="user_profile_modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
...
</div>
</div>
<% end %>
Is there a way to fire the the modal('show'); each time the modal is fired from the backend? By the way, this is just one of 3 modals that get loaded this way on the page.
Thanks again!
After trying a few things, simply replacing the replaceWith with html in the user_profile/show.js.erb will cause the ajax to fire each time.
Old:
$("#user_profile").replaceWith("<%= j render "user_profile" %>");
New:
$("#user_profile").html("<%= j render "user_profile" %>");
The reason for this is because the replaceWith is replacing the element in the parent, and thus not firing again because the element has already been replaced the first time.
Hope that helps anyone in the future!
I am learning Ruby On Rails.I'd like to understand how RoR works. I have the following url when i want to edit user informations:
http://localhost:3000/users/3/edit
Here is my controller :
# GET /users/1/edit
def edit
end
The form is :
<div class="ui middle aligned center aligned grid">
<div class="column">
<h1>Profil</h1>
<div class="ui form segment">
<%= render "form" %>
</div>
</div>
</div>
<%= link_to 'Show', #user %> |
<%= link_to 'Back', users_path %>
I understand that the form is print by the code <%= render "form" %>. I'd like to know how to see what contains form ? Which informations are available in form ?
In your case
<%= render "form" %>
renders partial. You should find file with name _form.html.erb
or read more about partials in GUIDE
The render method is used to load a partial. A partial is basically repeated fragment of code in a view. To keep things dry, you separate it out in a partial and then pass it to the render method to render it.
In your case, the form is a partial.
You will most probably find it at app/views/users/_form.html.erb
Partials are always prefixed with a _ in their filename.
In my quest to keep my application views as DRY as possible I've encountered a little snag. My appliation.html.erb incorporates a static sidebar menu. Each of my main controllers incorporates a secondary sidebar menu (essentially a submenu). I can take the code that renders the menu out of application.html.erb and put it in each of my views and change the secondary sidebar there, but this produces a lot repetition in my views.
I saw this SO post and looked at this page, but I was unable to get either idea to work. I was thinking that I could put something like:
<% provide(:submenu, 'layouts/sidebars/sidebar_customers_contacts') %>
at the top of each view and use that to render the associated partial by doing
<% content_for(:submenu) do %>
<%= render :partial => :submenu %>
<% end %>
from the application.html.erb but of course that didn't work.
This is my current application.html.erb:
<div class="side">
<%= render 'layouts/sidebar' %>
<%= render 'layouts/sidebars/sidebar_dashboard' %><!-- this needs to load a sidebar based on the controller that calls it. Each view of the controller will get the same sidebar. -->
</div>
<div class="main-content">
<%= yield %>
</div>
I feel like I'm making this more difficult than it really is. Is there a simple way to do this?
Rails provides a helper called controller_name which you can read more about here.
Assuming you adhere to your own naming conventions, this should work as-is. If you decide some controllers don't get a sidebar, you may need to throw in some conditionals...
application.html.erb
<div class="side">
<%= render "layouts/sidebar" %>
<%= render "layouts/sidebars/#{ controller_name }" %>
</div>
<div class="main-content">
<%= yield %>
</div>
EDIT
Sorry, my mistake was using single quotes instead of double-quotes. You cannot use #{string interpolation} within single quotes. Source
I am currently trying to optimize rendering a page in ruby on rails.
I have a question, is there a way to make a page, only render another page when a link (href) associated to it is clicked.
some codes in index.html.erb:
.....
.....
<h4>
<%= item.name %>
<br/>Details
</h4>
<div id="<%=item.id%>_item_modal" class="modal fullscreen">
<div class="item-modal">
<%=render item%>
</div>
</div>
.....
.....
In code above, I am using modal. So that when the link is clicked, _item.html.erb will be shown appear in a smaller page. Similar like a popup.
When index.html.erb is loaded, then all codes inside _item.html.erb will also be loaded automatically and all queries inside will be executed because of
<%render item%>
code.
What I want is, I don't want index.html.erb also render all item inside _item.html.erb page unless I click "Details" button.
<br/>Details
I think by doing this think, I can save some amount of time when a user requests for item page, because the system doesn't need to retrieve all information which are not yet required.
Could you guys help me?
Please let me know if you need another information.
You have to use ajax in order to achieve this. You can create a hidden div with a specific id, say "modal".
Revert your h4 to this:
<h4>
<%= item.name %>
<br/>
= link_to 'Details', item_path(item), data: {remote: true}, item_details: true
</h4>
Then in your item controller, on the show action:
def show
# load the item
if params[:item_details]
respond_to {|format| format.js}
else
# do what you already do here
end
end
And in your item views folder, create a file show.js(.coffee):
$('#modal').html('<%= j(render partial: "item", object: #item) %>');
$('#modal').modal('show');
This is just the idea, you have to make it compatible with your code.
If you want to go the ajax route:
<h4>
<%= item.name %>
<br/>
<%= link_to "Details", item_path(item), remote: true %>
</h4>
Then in your items_controller:
def show
...
respond_to do |format|
format.js
end
end
Then create the view "views/items/show.js"
$(body).append(<%= escape_javascript(render partial: "items/item_modal") %>);
...code to show modal...
...hook to remove modal when it is dismissed...
And the view "views/items/_item_modal.html.erb"
<div id="<%=item.id%>_item_modal" class="modal fullscreen">
<div class="item-modal">
<%=render item%>
</div>
</div>
I have an index view for a model(nested ) that never gets called from the model, but is rendered from a couple different models. One view can render the index with either JS or html. With JS is it in a #related div in the show view and a data-remote link. Another option uses the same controller action to render it only has html.
All was fine until I added Kaminari paging. In the full page view, there was no #related div so paging didn't work. I broke out the guts into a partial and added a #related div and rendered the partial. From js I just rendered the partial from JS. That worked fine in the full page view, but in the show page it would render the partial, but the links didn't work, looks like it renders the entire show page. Clinking on another tab and then going back to the Progressions tab loads the partial and all works fine. It is just on the initial load of the show page that I can't get the page links to work.
I can load another tab that does not use paging first and solve my problem, but this was kind of the main information that you go to this page for.
Any ideas?
EDIT Request for code
The controller action method. The index method in this controller also sets #progressions
def progressions
authorize! :read, Progression
#stage = Stage.find(params[:id])
#progressions = #stage.progressions_by_score.page(params[:page]).per(20)
if params[:status] && !params[:status].blank? && #progressions
#progressions = #progressions.where(status: params[:status]).page(params[:page]).per(20)
end
respond_to do |format|
format.js
format.html {render :template => "progressions/index"}
end
end
The progressions.js.erb file in the stages view
$("#related").html("<%= escape_javascript(render('progressions/index'))%>");
The relations div in the show view. This is pretty much my scaffold template where I display or link to related information. The <div id="related"> is where any date-remote links will load the data. On initial load it loads the _index partial.
<div class="relations">
<span class="navspan">
<%= link_to 'Progressions: Status ->', progressions_stage_path(#stage), :'data-remote' => true,
:onclick => '$("#progression_status").val("")' %>
<span class="huh">
<%= hidden_field_tag :stage_id, params[:id]%>
<%= select_tag :progression_status, options_for_select(Progression.statuses["all"], params[:status]),
:prompt => 'All', :class => 'f-left' %>
</span>
<%= link_to 'Assessors', assessors_stage_path(#stage), :'data-remote' => true %>
<%= link_to 'Events', events_stage_path(#stage), :'data-remote' => true %>
<%= link_to 'Select', select_stage_path(#stage) if can? :select_candidates, #stage %>
<%= link_to 'Ad Mgmt', edit_ad_stage_path(#stage) if can? :manage_ad, #stage %>
</span>
<div class="f-clear"></div>
<div id="related">
<%= render "progressions/index"%>
</div>
</div>
The index.html.haml file
#related
= render "progressions/index"
The _index.html.haml file is just an index table listing the progressions but it does contain:
= paginate #progressions, :remote => true
Shortly after posting some code, I went back in my memory and used javascript to load the related div. I've tried to stay away from javascript, but in this case I added this to the end of the page after adding :id => "status_id" to the progressions link:
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$("#status_link").trigger("click");
})
</script>
While this fixes my problem, I still don't understand why the initial html response does not respond to the page links in the related div. I'll leave that as something else to learn. I'll put it in coffescript after I figure out how to have fire only on initial load of the show page.