• Home
  • Why Erstwhile?
  • Getting Started
  • Learn Erstwhile
  • API Docs
  • Home
  • Why Erstwhile?
  • Getting Started
  • Learn Erstwhile
  • API Docs
  • API Documentation
  • ErstwhileApp
    • getDebug()
    • getConfig(property)
    • setLayout(layout)
    • getComponent(id)
    • getModel(model)
    • redirect(path, updateHistory: true, scrollTop: true)
    • defer(func, delay: 0, selector: null)
    • openModal(controller, modal, args)
    • setModalAttributes(args)
    • closeModal()
  • ErstwhileComponent
    • getCSS()
    • isHidden()
    • hide()
    • show()
    • setProperty(property, value)
    • getProperty(property)
    • isContainer()
    • initialize()
    • unload()
    • getHTML(innerDom)
    • receiveUpdate(key, value)
    • receiveGlobalUpdate(key, value)
    • getTag()
    • getClassName()
    • prepareAttributes()
  • ErstwhileForm
    • getControl(name)
    • showErrors(response)
    • clearErrors()
    • registerComponent(id)
    • deregisterComponent(id)
    • getValues()
  • ErstwhileControl
    • getKey()
    • getValue()
    • setValue(value)
    • setValid(validFlag, message)
  • ErstwhileLayout
  • ErstwhileTheme
    • getRequires()
    • getCSS(appRootDir, workingDir, themeConfig)
    • getFontFolder(appRootDir)
    • getCSSFolder(appRootDir)
    • getJSFolder(appRootDir)
    • getCSSLinks(rootDir)
    • getScripts(rootDir)
  • ErstwhileController
    • preAction(next)
    • postAction(next)
    • getControllerPath()
    • getRoutes()
  • ErstwhileModel
    • makeRequest(path, params, method: "get", data, headers)

ErstwhileLayout

23 views 0

Written by mike
August 3, 2023

ErstwhileLayout is the base class for layouts. In Erstwhile, layouts are essentially the “frame” of the page, the part of the page that stays (generally) consistent as the user moves around the application. This can include the header, navigation, footer, and similar elements to that.

Layouts are implmented just like other ErstwhileComponents, but typically contain a lot of HTML boilerplate due to the nature how web pages are constructed. We call these “Fat Layouts;” Erstwhile lets you place a lot of this non-elegant code in one place and hide it behind a simple component with well-defined integration points in attributes to access its functionality.

For example, the Mazer theme has a ErstwhileLayout component called <FullLayout> that isn’t very pretty:

<%
  function renderSidebarMenuItem( menuItem, submenu = false ) {
    %>
    <li class="<%= (submenu ? "submenu-item" : "sidebar-item") %> <%= (menuItem.id && menuItem.id == args.sidebarMenuActive ? "active" : "") %> <%= (menuItem.children ? "has-sub" : "") %>" <%= (menuItem.id ? `id="sidebar-menu-${menuItem.id}"` : "") %>>
      <a href="<%= (menuItem.link ? menuItem.link : "#") %>" class="<%= (submenu ? "submenu-link" : "sidebar-link") %>">
        <% if(menuItem.biIcon) { %><i class="<%= `bi bi-${menuItem.biIcon}` %>"></i><% } %>
        <span><%= (menuItem.label ? menuItem.label : "Item") %></span>
      </a>
      <% if(menuItem.children) { %>
        <ul class="submenu">
          <% for(let j in menuItem.children) {
            renderSidebarMenuItem(menuItem.children[j], true);
          } %>
        </ul>
      <% } %>
    </li>
    <%
  }

%>
<div id="app">
  <div id="sidebar">
    <div class="sidebar-wrapper active">
      <div class="sidebar-header position-relative">
        <div class="d-flex justify-content-between align-items-center">
          <div class="logo">
            <a href="/"
              ><img
                src="<%- (args.logo ? args.logo : "https://placeholder.pics/svg/500x200") %>"
                alt="Logo"
                srcset=""
            /></a>
          </div>
          
          <div class="sidebar-toggler x">
            <a href="#" class="sidebar-hide d-xl-none d-block"
              ><i class="bi bi-x bi-middle"></i
            ></a>
          </div>
        </div>
      </div>
      <div class="sidebar-menu">
        <ul class="menu">
          <% if(args.sidebarMenu && args.sidebarMenu.length > 0) { %>
            <% for(let i in args.sidebarMenu) {
              if(args.sidebarMenu[i].label) { %><li class="sidebar-title"><%= args.sidebarMenu[i].label %></li><% } %>
            <% 
              for(let j = 0; j < args.sidebarMenu[i].items.length; j++) { 
                renderSidebarMenuItem(args.sidebarMenu[i].items[j]);
              } 
            %>
          <% }} %>
        </ul>
      </div>
    </div>
  </div>
  <div id="main">
    <header class="mb-3">
      <a href="#" class="burger-btn d-block d-xl-none">
        <i class="bi bi-justify fs-3"></i>
      </a>
    </header>

    <div class="page-heading">
      <div class="page-title">
        <div class="row">
          <div class="col-12 col-md-6 order-md-1 order-last">
            <h3 id="page-title"><%- args.pageTitle %></h3>
            <p id="page-intro" class="text-subtitle text-muted">
              <%- args.pageIntro %>
            </p>
          </div>
          <div class="col-12 col-md-6 order-md-2 order-first">
              <nav
                aria-label="breadcrumb"
                class="breadcrumb-header float-start float-lg-end"
                id="breadcrumb-container"
              ><% if(args.breadcrumbs) { %>
                <ol class="breadcrumb">
                  <% for(let i in args.breadcrumbs) { %>
                    <li class="breadcrumb-item <%= (i == args.breadcrumbs.length - 1 ? 'active' : "") %>" <%= (i == args.breadcrumbs.length - 1 ? 'aria-current="page"' : "") %>>
                      <% if(args.breadcrumbs[i].link) { %>
                        <a href="<%- args.breadcrumbs[i].link %>"><%- args.breadcrumbs[i].label %></a>
                      <% } else { %>
                        <%- args.breadcrumbs[i].label %>  
                      <% } %>
                    </li>
                  <% } %>
                </ol>
                <% } %>
              </nav>
            
          </div>
        </div>
      </div>
      <pagecontent />
    </div>

    <footer>
      <div class="footer clearfix mb-0 text-muted">
        <div class="float-start">
          <% if(args.copyrightYear || args.copyrightName) {%>
            <p><%- args.copyrightYear %> &copy; <%- args.copyrightName %></p>
          <% } %>
          
        </div>
        <div class="float-end">
          <% if (args.footerMessage) { %>
            <p>
              <%- args.footerMessage %>
            </p>
          <% } %>
          
        </div>
      </div>
    </footer>
  </div>
</div>

Should you choose to include it within your application, though, you can consume it like this:

<FullLayout 
  logo="/assets/images/todos-logo.png" 
  sidebarMenu="@.session.sidebarMenu"
  sidebarMenuActive="@.page.sidebarMenuActive"
  breadcrumbs="@.page.breadcrumbs"
  copyrightYear="<%= (new Date()).getFullYear() %>"
  copyrightName="<a class='external' target='_blank' href='https://www.restlessdev.com'>RestlessDev</a>"
  footerMessage="Made with <span class='text-danger'><i class='bi bi-heart-fill icon-mid'></i></span> in New Orleans"
  pageTitle="@.page.title"
  pageIntro="@.page.intro"
  appName="Todos" 
  meta="@.page.meta"
  >
  <pagecontent />
</FullLayout>

You can ignore the unsightly parts of the code and just work with the wrapper.

At this time, ErstwhileLayout doesn’t have any specific methods that can be overwritten. When creating layouts, you can denote the place you’d like to insert the page content with a  <pagecontent /> tag.

Was this helpful?

Yes  No
Related Articles
  • getControllerPath()
  • getRoutes()
  • postAction(next)
  • preAction(next)
  • makeRequest(path, params, method: “get”, data, headers)
  • ErstwhileModel

Didn't find your answer? Contact Us

Previously
setValid(validFlag, message)
Up Next
ErstwhileTheme

loader

Join our Mailing List     

  • Privacy Policy
  • Terms of Use
  • © 2025 RestlessDev. Made in New Orleans.

Welcome to Erstwhile

Thank you for checking out Erstwhile. We’re just getting started, so if you’d like to keep up with our progress please register now and we’ll let you know when new releases come out.

loader

Email Address*

Name