plandevida
(Daniel Serrano)
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)
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)
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)
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)
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)
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)
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)
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