I want to dynamically add classes to a container based on the name of the class that called my layout using the render method. Is it possible or do I need to pass it manually from each view?
File: emails/inbox.html.haml
render layout: 'shared/v3/panel' do
// whatever
Rendered HTML:
<div id="inbox" class="panel email_container"></div>
My temp solution is to do:
render layout: 'shared/v3/panel', locals: {class_panel: 'email_container', id_panel: 'inbox'} do
// whatever
But I want to do that dynamically.
Final solution: views/shared/_panel.html.haml
- # You need to use: "render layout", not "render partial" to pass the "do" block.
.container_content{class: "#{controller_name}_container #{local_assigns[:panel_class] ? panel_class : ''}", id: action_name}
- if local_assigns[:title]
.headline= local_assigns[:title]
= yield
- if local_assigns[:footer]
.footer= local_assigns[:footer]
- # Example of use:
-#= render layout: 'shared/v3/panel', locals: {title: 'Place', panel_class: 'my_custom_class'} do
-# - if #activity.place.present?
-# %p
-# = t('place')
-# = #activity.place
Related
I want to display a form partial within a shared partial layout form_layout
# views/layouts/shared/_form_layout.html.haml
= form_with(model: record, remote: true) do |form|
.fields
= yield
/// other stuff
# views/articles/_form.html.haml
# ?? want to access the form builder here
# views/articles/new.html.haml
= render partial: 'form', layout: 'layouts/shared/form_layout', locals: { record: Article.new }
How can I access the FormBuilder object inside the partial template?
You should try this-
= render layout: "layouts/shared/form_layout", locals: { record: Article.new} do
# block contents..
My model structure is pretty solid. I have MarketingDeliverySystem has_many MarketingSections. MarketingSections has_many MarketingVideos.
I have another segment: GroupDevelopment has_many GroupSections. GroupSections has_many GroupVideos.
I'm trying to use a partial to pass the variables, thus DRYing it all up.
I have the following that I'm trying to pass to the partial:
= render partial: '/sales_presentations/sales_presentation',
locals: { marketing_delivery_system: #marketing_delivery_system,
first_video: first_marketing_video(#marketing_delivery_system),
sales_presentation: #marketing_delivery_system}
Then in the partial I have the following:
.rounded-box-header.blue-bg #{sales_presentation.title}
ul
- sales_presentation.sections.ordered.each_with_index do |section, index|
- list_class = 'section show'
- list_class = 'section hide' if index != 0
li
= link_to section.title, '#', class: 'section', data: { id: section.id }
ul class="#{list_class}" data-section-id="#{section.id}"
- section.videos.ordered.each do |video|
li.video
= link_to video.title, '#',
class: 'video video-link',
data: { video: video.youtube_link,
sales_presentation: sales_presentation.title.parameterize }
.seven.columns
.row
div id="#{sales_presentation.title.parameterize}-container"
video {
id="#{sales_presentation.title.parameterize}-video-player"
class="video-js vjs-default-skin videos"
height=400
poster=""
controls preload='none'
data-default-url="#{first_video(sales_presentation)&.youtube_link}"
I previously had issues with sales_presentation.title at the top until I updated the locals.
My question/issue is how do I pass in through the locals to use for sales_presentation.sections instead to use #marketing_delivery_system.marketing.sections?
I thought I could just put that in through locals:
sales_presentation.sections: #marketing_delivery_system.marketing_sections but I end up with a massive syntax error.
I've also tried creating a partial view for these two and then changed sales_presentation throughout the view to mod. Then changed mod.sections to mod_section and setting that in the locals to mod_section: #marketing_delivery_system.marketing_section. The problem then gets into that I end up needing to hit video later in the iteration. So then that has the same issue.
You misunderstand the meaning of locals in partials.
Says we have
<%= render partial: 'image', locals: {size: #image.size, extension: #image.extension} %>
It means that in image partial now we can use local variable size and extension (keys) as #image.size and #image.extension (values).
Put in locals: {} all local variables you want.
So you can't write in locals sales_presentation.sections: #marketing_delivery_system.marketing.sections
But you can sales_presentation_sections: #marketing_delivery_system.marketing.section
Also you have problem with this code:
locals: { marketing_delivery_system: #marketing_delivery_system,
first_video: first_marketing_video(#marketing_delivery_system),
sales_presentation: #marketing_delivery_system }
marketing_delivery_system and sales_presentation will be with the same value.
I have STI models like this : Photo < Medium and Video < Medium.
Somewhere in a view, i would like to show them like that :
# app/views/albums/show.html.slim
ul
li= render #album.media
The render search for a albums/_photo or albums/_video partial :
# app/views/albums/_photo.html.slim
h3= photo.title
= image_tag photo.file.url
p= photo.description
# app/views/albums/_video.html.slim
h3= video.title
= video_tag video.file.url
p= video.description
Now, i would like to make a template to use in app/views/albums/show.html.slim for not repeat commons fields between media. Something like that :
# app/views/albums/_medium.html.slim
h3= medium.title
= yield(:medium_tag)
p= medium.description
= yield(:medium_additionnals)
# app/views/albums/_photo.html.slim
- content_for(:medium_tag) do
= image_tag photo.file.url
- content_for(:medium_additionnals) do
# any additionnals fields
# app/views/albums/_video.html.slim
- content_for(:medium_tag) do
= video_tag video.file.url
- content_for(:medium_additionnals) do
# any additionnals fields
But this give me in yields concatenate contents...
Someone has a solution / alternative to do this ?
[EDIT]
With this templates :
# app/views/albums/show.html.slim
= render #album.media
# app/views/albums/_medium.html.slim
div
h3= medium.title
= yield(:medium_tag)
# app/views/albums/_photo.html.slim
- content_for(:medium_tag) do
| TEST
The resulting HTML :
<div>
<h3>Photo1</h3>
TEST
</div>
<div>
<h3>Photo2</h3>
TESTTEST
</div>
<div>
<h3>Photo3</h3>
TESTTESTTEST
</div>
<div>
<h3>Photo4</h3>
TESTTESTTESTTEST
</div>
...
The yield result is concatened as many time as media count.
Your code seems really good, although I don't get how your render call is cycling through each medium item
You could use a helper to return the relevant data, although that wouldn't be the most efficient:
#app/helpers/application_helper.rb
module ApplicationHelper
output = Slim::Engine.new "h3={item.title}"
output += Slim::Engine.new "- eval(#{item.model_name.human}_tag) item.file.url"
output += Slim::Engline.new "p=item.description"
end
end
This would allow you to run:
#app/views/albums/_photo.html.slim
= media photo
#app/views/albums/_video.html.slim
= media video
-
Alternatively, you could just put it into a _medium partial:
#app/views/albums/_photo.html.slim
= render partial: "medium", locals: { item: photo }
#app/views/albums/_video.html.slim
= render partial: "medium", locals: { item: video }
_medium would then have the following:
#app/views/albums/_medium.html.slim
h3=item.title
- eval("#{item.model_name.human}_tag") item.file.url
p=item.description
contests/show.html.haml:
- if modal
- content_for(:modal_header) do
= render 'contests/contest_header'
- content_for(:modal_body) do
= render 'contests/contest_body'
- else
= render 'contests/contest_header'
= render 'contests/contest_body'
modal is a boolean local which indicates whether the view is being rendered in a modal template, vs the regular application template. The modal has content_for blocks while the main application template does not:
layouts/modal.html.haml:
-modal = true
.modal-header
.row
.col-xs-11
= yield(:modal_header)
.col-xs-1
%button{'type': 'button', 'class': 'close', 'data-dismiss': 'modal', 'aria-label': 'close'}
%span{'aria-hidden': 'true'} ×
.modal-body
= render 'layouts/messages'
- if content_for?(:modal_body)
= yield(:modal_body)
- else
=yield
What I'm looking for is something that can conditionally make the content_for blocks disable when modal is false. Rather than repeating my render statements.
Found a solution from another SO answer! https://stackoverflow.com/a/27398070/378622
Here's my implementation
# app/helpers/application_helper.rb
def modal_content_for(name, &block)
if params[:modal] == '1'
content_for 'modal_' + name.to_s, nil, &block
else
capture_haml(&block)
end
end
How can I write this code in haml without repeating the render line?
- if i % 2 == 0
%section.wrapper-md.list
= render partial: 'property'
- else
%section.wrapper-md.list.background-gray
= render partial: 'property'
Thanks!!
Try something like this
%section.wrapper-md.list{class: ('background-gray' if i.even?)}
= render partial: 'property'
Also you could try using the cycle helper and no need for counters
%section.wrapper-md.list{class: cycle('', 'background-gray')}
= render partial: 'property'