plandevida
(Daniel Serrano)
March 26, 2024, 6:20pm
1
Hi there!
I am just starting my first project with vapor and leaf. All sound nice but I am running into some early issues when rendering embedded templates.
It just does not load the content of my child templates, tell me please if I am doing something wrong here:
layout.leaf (this is the main template)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>#(title)</title>
<!-- Styles -->
<link href="/styles/parallax.css" rel="stylesheet" type="text/css">
<link href="/styles/card.css" rel="stylesheet" type="text/css">
<link href="/styles/menu.css" rel="stylesheet" type="text/css">
</head>
<body>
#import("head")
#import("content")
</body>
</html>
head.leaf
#extend("layout"):
#export("head"):
<div class="header">
<div class="logo-head">
<a>
<div class="text-logo">
<p>A</p>
</div>
</a>
</div>
<div class="topnav">
<a href="/">Menu1</a>
<a>Menu2</a>
<a href="/about">About</a>
</div>
#endexport
#endextend
main.leaf
#extend("layout"):
#export("content"):
</div>
<div class="parallax-container parallax1">
<div class="card-container">
<div class="presentation-card" id="gradient-start">
<p>Lorem ipsum dolor sit amet</p>
</div>
</div>
</div>
<div class="parallax-container parallax1 parallax2"></div>
<div class="presentation-card" id="gradient-end">
<p>Lorem ipsum dolor sit amet</p>
<p>consectetur adipiscing elit</p>
<p>sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</p>
</div>
<div class="parallax-container parallax-align-content-top parallax1 parallax3">
<div class="card-container">
<div class="presentation-card" id="gradient-end">
<p>Lorem ipsum dolor sit amet</p>
<p>consectetur adipiscing elit</p>
<p>sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</p>
</div>
</div>
</div>
#endexport
#endextend
jagreenwood
(Jeremy Greenwood)
March 27, 2024, 4:47pm
2
Hello!
It’s interesting that both head and main extend layout. Which template are you returning in your route handler? What is the rendered html on the page?
plandevida
(Daniel Serrano)
March 28, 2024, 12:15pm
3
Hi!
I understand that the extension of these templates as modules, right? so I can contribute to several sections from different children templates. Do I understand this wrong?
Answering your questions:
I am returning the layout.leaf template. This is my route file
import Fluent
import Vapor
func routes(_ app: Application) throws {
app.get { req async throws in
try await req.view.render("layout", ["title": "CoatchingApp Prototype"])
}
try app.register(collection: TodoController())
}
This is the html rendered:
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<!-- Styles -->
<link href="/styles/parallax.css" rel="stylesheet" type="text/css">
<link href="/styles/card.css" rel="stylesheet" type="text/css">
<link href="/styles/menu.css" rel="stylesheet" type="text/css">
</head>
<body>
</body>
</html>
I have another example with just one import and one extension, and the result is the same, whenever the import is no html is included.
about.leaf
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>#(title)</title>
<!-- Styles -->
<link href="/styles/parallax.css" rel="stylesheet" type="text/css">
<link href="/styles/card.css" rel="stylesheet" type="text/css">
<link href="/styles/menu.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="header">
<div class="logo-head">
<a>
<div class="text-logo">
<p>A</p>
</div>
</a>
</div>
<div class="topnav">
<a href="/">Home</a>
<a>Coaching</a>
<a href="/about">About</a>
</div>
</div>
<div class="content">
<h1>Who we are</h1>
#import("team")
</div>
</body>
</html>
This is the children template, team.leaf
#extend("about"):
#export("team"):
<div class="team">
<h1>Team</h1>
</div>
#endexport
#endextend
This is the rendering
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<!-- Styles -->
<link href="/styles/parallax.css" rel="stylesheet" type="text/css">
<link href="/styles/card.css" rel="stylesheet" type="text/css">
<link href="/styles/menu.css" rel="stylesheet" type="text/css">
</head>
<body style="background-color: black; display: block; color: white;">
<div class="header">
<div class="logo-head">
<a>
<div class="text-logo">
<p>A</p>
</div>
</a>
</div>
<div class="topnav">
<a href="/">Home</a>
<a>Coaching</a>
<a href="/about">About</a>
</div>
</div>
<div class="content">
<h1>Who we are</h1>
</div>
</body>
</html>
As you can see where the imports are there is no html from the child template that's extending.
jagreenwood
(Jeremy Greenwood)
March 28, 2024, 1:56pm
4
Think about in similar terms as subclassing a class. With this analogy in mind, layout.leaf
is the "superclass" while head.leaf
and main.leaf
are each "subclasses".
So I believe you are thinking about backwards. Try returning main.leaf
from your handler and see what happens.
1 Like
plandevida
(Daniel Serrano)
March 29, 2024, 5:42pm
5
I got you!
Thanks very much, that worked like a charm.
I must say then either the documentation is misleading or I read it wrong at vapor.docs
Anyhow, much appreciated.
plandevida
(Daniel Serrano)
March 29, 2024, 7:17pm
6
I was thinking on this hierarchy and I have the next question:
What if I want to make a modular template? My idea was the next (when I understood this backwards):
layout.leaf (main template)
<!DOCTYPE html>
<html lang="en">
<head>
<title>#(title)</title>
<!-- Styles -->
#import("styles")
<!-- Scripts -->
#import("scripts")
</head>
<body>
#import("header")
#import("content")
#import("footer")
</body>
</html>
So other view (children) contribute layout.leaf:
header.leaf
#extend("layout"):
#export("header"):
<div class="header">
...
</div>
#endexport
#endextend
home.leaf
#extend("layout"):
#export("content"):
<div class="main">
...
</div>
#endexport
#endextend
footer.leaf
#extend("layout"):
#export("footer"):
<div class="footer">
...
</div>
#endexport
#endextend
How I can do this now?
I understand if I render home.leaf I won't see the content of either header.leaf or footer.leaf.
jagreenwood
(Jeremy Greenwood)
March 29, 2024, 7:47pm
7
What you might be looking for is #extend(<template>)
, note this does not have a closing #endextend
This will copy the content of the template inline.
layout.leaf
<!DOCTYPE html>
<html lang="en">
<head>
<title>#(title)</title>
<!-- Styles -->
#extend("styles")
<!-- Scripts -->
#extend("scripts")
</head>
<body>
#extend("header")
#import("content")
#extend("footer")
</body>
</html>
Then, for example in header.leaf
, you would simply define your html (no extends, exports, etc)
<div class="header">
...
</div>
The thing to remember is #export
and #import
store and retrieve content from the context whereas #extend
incorporates content from another template.
1 Like
plandevida
(Daniel Serrano)
April 12, 2024, 5:57pm
8
Thank @jagreenwood !
You helped me a lot, I couldn't see this way through the documentation.
I will play with it a see if the structure in my mind works.
Much appreciated.
1 Like