Access content cell from external layout
The only way to communicate between an external layout and its content is through the yield call, while an internal layout can call all content cell methods.
This patch adds the @option[:content_cell] option to layout cells and provides the Cell::Viewmodel::Layout::External::Content interface for communication between an external layout cell and the content cell it wraps. This interface is convenient if you want to create standard components (e.g. for bootstrap) that have multiple content areas, such as a panel. With this interface, such a layout cell can be defined as follows:
module Layout
module Cell
class Panel < Trailblazer::Cell
include ::Cell::ViewModel::Layout::External::Content
def footer?
!content_block(:footer).nil?
end
end
end
end
The layout itself pretty straightforward (in this case, i'm using erb):
<div class="panel panel-default">
<div class="panel-heading">
<%= content_block(:title) { "Default title" } %>
</div>
<div class="panel-body"><%= yield %></div>
<% if footer? %>
<div class="panel-footer"><%= content_block(:footer) %></div>
<% end %>
</div>
The Cell::ViewModel::Layout::External interface provides thecontent_block(:method)method. This method checks if the content cell defines:method. You can provide a block that will be rendered if it doesn't. If you don'tnilwill be returned. You can render aSongCell` with this layout as follows:
class Song
module Cell
class SongCell < ::Trailblazer::Cell
include ::Cell::ViewModel::Layout::External
property :song_title
property :author
property :year
def title
song_title
end
def footer
render "song/footer"
end
end
end
end
song.erb:
<p><strong>Author:</strong> <%= author %></p>
<p><strong>Year:</strong> <%= year %>
song/footer.erb:
<a href="edit">Edit this song</a>
This patch is completely backwards compatible: all it does is providing the @option[:content_cell] option by default to layout cells. The content_block functionality is not provided by default; it is completely separated in the ::Cell::ViewModel::Layout::External module.
This interface is also useful for a full-page layout. Webpages often need a customized page title and footer. Without this patch, you could only customize this context by adding it to the @options[:context] option. With this patch, you can directly define this content in your cells.
What if other cells would simply write to the context object?
I thought again about this: why don't we simply provide the content cell instance in the :context object? That would save the new argument and utilize what's already there.
context[:content_cell] # set per default
What do you think, will that do the trick?
So, about this 8 years old change...
Long story short: the remote repository of this pull request is a company account, Scharrels does not work here anymore, and we've refactored our web framework so that we have no more need of this change. If anybody is still interested in adding the proposed updates to this change: please make a copy of the branch and do so. Otherwise' we'd rather remove our fork of this repository (which will close the PR).
No worries @herwinw, thanks for thinking of us :beers: