Rendering a View for a Route
In this lesson, we'll learn how we can use the EdgeJS Template Engine to render HTML views and send them back as the response for our routes. We'll also see how we can pass dynamic data into our views from our route handler.
- Author
- Tom Gobich
- Published
- Jan 24
- Duration
- 6m 29s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
Rendering a View for a Route
-
[music]
-
Now if you were paying attention, you probably noticed that our movies page
-
looks different than our home page. Let's go ahead and compare.
-
So here we have a monospace font and a dark grey background
-
and our text is white. If we head back to our home page, our background is white,
-
our text is black, and it's quite large.
-
The difference here is how we're returning back the information.
-
So if we right-click on our browser, jump down to Inspect,
-
and head into the Network tab, this will allow us to inspect the network requests
-
that our browser sends to our server. So let's go ahead and give the page a refresh
-
to start capturing that, and there we go.
-
We see a number of different things show up. The one in particular that we care about, though,
-
is where the initiator is the document, because this is the request
-
to our home page, and it's what's sending back what we see
-
within the browser at this point in time. So let's go ahead and click on that,
-
and let's head into the response. Cool, so what we see in the response
-
matches exactly what we see within the browser, which is what you would expect,
-
because this is exactly what the browser is using to show us our page.
-
But if we click on Raw, this is where we start to see the HTML markup
-
that makes up the page. And if you recall back to our earlier lesson
-
whenever we were actually inspecting our page, let's dive into our resources,
-
Views, Pages, Home.Edge. The HTML markup that we see in our response
-
matches what we have defined within this page,
-
including the It Works text. The only thing that's different is this
-
fight declaration right here, which we'll get into at a later point in time.
-
So the underlying reason why we see something different here
-
as compared to our Movies page, so I'm going to go back to our Movies page now,
-
give it a refresh so that we see the underlying request,
-
let's click on the request for our document, and now we see the response.
-
We don't have a Raw option at all for this response, and it's just
-
sending back one single line that says "My Awesome Movie."
-
There is no HTML markup associated with it. And that's because
-
we're just sending back a plain text response for this particular request.
-
Within our request table here, that's even noted within the Type column.
-
You can see this one here is just plain, whereas if we go back
-
to our Home page, that type is HTML.
-
So how do we make our Movies page an HTML response?
-
Well, let's go ahead and hide our browser back away, jump back into our
-
Route definitions, and the primary difference between these two Route definitions
-
is that this one is using a render function to render out a specific page,
-
whereas with our Movies route, all that we're doing is returning back
-
a string. So by default, this will return back just a plain text response,
-
and instead, let's go ahead and get rid of our string,
-
reach for our CTX, and if you'll recall back earlier,
-
we have a View property within here. And that View property allows us
-
to work with the Edge template engine. So let's go ahead and try to dive into
-
the View. We can do . there, and look at that, we have a render method
-
that looks relatively similar to what we are calling for our Home page.
-
So let's go ahead and give that a try. So let's do Render.
-
Okay, and now it's asking for a template path. So the template path
-
is going to be the path to the file that we want to render
-
for this page from within the Views directory. By default,
-
Edge already knows to look within Resources and Views for our pages,
-
so all that we need to do is to find the path from that point onward,
-
which would be Pages, and then whatever page we make. So let's go ahead
-
and create a new page by right-clicking on Pages, New File, and let's call
-
this Movies.Edge. Let's jump into our Home page for right now,
-
select everything by hitting CMD/CTRL+A, CMD/CTRL+C
-
to copy it, jump back into our Movies page, and CMD/CTRL+V
-
to paste it in. Now let's change our It Works text
-
to "My Awesome Movie." We can give this a save,
-
jump back into our routes, and now we have a template path
-
to provide into our render function. So let's provide Pages,
-
and you'll even see an autocomplete pop up here.
-
This is thanks to the AdonisJS extension that we installed earlier,
-
and we can populate this with Pages/Movies.
-
Do note that you don't need to provide in the file extension of .edge,
-
EdgeJS will imply that. So let's give this a save, our server
-
will automatically pick up that change. We can dive back into our
-
browser, let's give our page a refresh, and look at that, now it looks
-
the exact same as our Home page, except the text says "My Awesome Movie."
-
We can verify that we're now sending back an HTML response
-
via the type right down here in our Network Inspector,
-
we can even give this a click, and now we have a raw option
-
where we see the underlying HTML. Awesome, so now we have an HTML
-
page, but just having static HTML pages isn't too useful
-
for a server that can serve up dynamic stuff.
-
So how do we pass in dynamic data into this page
-
and render it out? Well, let's go ahead and hide our browser back away,
-
and let's see first if our HTTP context has any additional options
-
for us. So let's do "ctx." We know that "view"
-
is primarily for EdgeJS, so let's try searching within there.
-
So we'll do "." again, we see "render raw," "render raw sync,"
-
"render sync," those are all rendering stuff,
-
but then lastly we have "share." That sounds like it might be useful, so let's give it a try.
-
This is a function, so we can call it, and it's going to ask for
-
data of a type "record string any."
-
This "record string any" is essentially asking for an object
-
with a key-value pair. So we can provide an object with a key,
-
let's call our key "movie," and let's call the value
-
"my awesome movie." We can jump back into our movies page
-
by following this underlying text right here
-
within our render function, and hitting "cmd" or "ctrl" click on it,
-
that will jump us straight into our page. And the way that we provide dynamic
-
data into our Edge files is by entering double curly braces.
-
And now we have access to stateful information
-
provided into this view page. Within our share method, we called
-
our key "movie," so let's go ahead and try typing in
-
"movie" to see if that works. Let's give this a save,
-
jump back into our browser, we can give our page a refresh,
-
and look at that, we still see "my awesome movie." Let's hide our browser
-
once more and give ourselves a sanity check just to make sure that it'll work.
-
So let's jump back into our routes, and let's do "another awesome movie."
-
Give that a save, jump back into our browser, give our page a refresh,
-
and voila, there's another awesome movie.
-
Cool, so now we have dynamic data coming into our page that we're now
-
rendering out, but we're not quite done yet. There's actually a more streamlined
-
way that we can do this exact same thing. So let's hide our browser back away.
-
If we take a look at the options that our render function has,
-
you'll see that the second argument is for state information.
-
Well, we're using those double curly braces to gain access to stateful information
-
provided into our EdgeJS files. So what if we tried
-
providing that state directly via this second argument? You'll notice
-
that the type is "record string any" or "undefined."
-
This means that we can either provide in an object with a key value
-
pair, or we could provide in "undefined" or "nothing," since this
-
also is completely optional. At this point, we're providing
-
a "nothing," but if we highlight our movie data,
-
cut it out with Command or Control X, get rid of our share call
-
altogether, let's provide in a comma, and let's paste this back in
-
as the stateful information to our render call.
-
Give this a save, let's jump back into our browser at this point.
-
We're still seeing another awesome movie, so we can imply that it works.
-
Let's hide our browser back away, give it another sanity check,
-
switch this back to "my," give this a save, jump back into our browser
-
once more, give the page a refresh, and voila!
-
There is my awesome movie again. So at this point, we know that we have
-
two different options to provide stateful information into our
-
EdgeJS files that we can render out as HTML.
-
Introduction
-
Fundamentals
-
2.0Routes and How To Create Them5m 23s
-
2.1Rendering a View for a Route6m 29s
-
2.2Linking Between Routes7m 51s
-
2.3Loading A Movie Using Route Parameters9m 17s
-
2.4Validating Route Parameters6m 6s
-
2.5Vite and Our Assets6m 38s
-
2.6Setting Up Tailwind CSS9m 5s
-
2.7Reading and Supporting Markdown Content4m 32s
-
2.8Listing Movies from their Markdown Files8m 51s
-
2.9Extracting Reusable Code with Services7m 4s
-
2.10Cleaning Up Routes with Controllers4m 52s
-
2.11Defining A Structure for our Movie using Models9m 38s
-
2.12Singleton Services and the Idea of Caching6m 11s
-
2.13Environment Variables and their Validation4m 16s
-
2.14Improved Caching with Redis10m 44s
-
2.15Deleting Items and Flushing our Redis Cache6m 46s
-
2.16Quick Start Apps with Custom Starter Kits6m 28s
-
2.17Easy Imports with NodeJS Subpath Imports8m 40s
-
-
Building Views with EdgeJS
-
3.0EdgeJS Templating Basics8m 49s
-
3.1HTML Attribute and Class Utilities6m 9s
-
3.2Making A Reusable Movie Card Component10m 24s
-
3.3Component Tags, State, and Props4m 53s
-
3.4Use Slots To Make A Button Component6m 56s
-
3.5Extracting A Layout Component5m 13s
-
3.6State vs Share Data Flow2m 59s
-
3.7Share vs Global Data Flow6m 7s
-
3.8Form Basics and CSRF Protection6m 13s
-
3.9HTTP Method Spoofing HTML Forms3m 3s
-
3.10Easy SVG Icons with Edge Iconify7m 57s
-
-
Database and Lucid ORM Basics
-
4.0Configuring Lucid and our Database Connection4m 3s
-
4.1Understanding our Database Schema9m 35s
-
4.2Introducing and Defining Database Migrations18m 35s
-
4.3The Flow of Migrations8m 28s
-
4.4Introducing Lucid Models5m 43s
-
4.5Defining Our Models6m 49s
-
4.6The Basics of CRUD11m 56s
-
4.7Defining Required Data with Seeders11m 11s
-
4.8Stubbing Fake Data with Model Factories13m 48s
-
4.9Querying Our Movies with the Query Builder15m 30s
-
4.10Unmapped and Computed Model Properties3m 24s
-
4.11Altering Tables with Migrations7m 6s
-
4.12Adding A Profile Model, Migration, Factory, and Controller2m 57s
-
4.13SQL Parameters and Injection Protection9m 19s
-
4.14Reusable Query Statements with Model Query Scopes8m 11s
-
4.15Tapping into Model Factory States9m 15s
-
4.16Querying Recently Released and Coming Soon Movies4m 59s
-
4.17Generating A Unique Movie Slug With Model Hooks7m 59s
-
-
Lucid ORM Relationships
-
5.0Defining One to One Relationships Within Lucid Models5m 49s
-
5.1Model Factory Relationships2m 54s
-
5.2Querying Relationships and Eager Vs Lazy Loading5m 17s
-
5.3Cascading and Deleting Model Relationships5m 16s
-
5.4Defining One to Many Relationships with Lucid Models6m 56s
-
5.5Seeding Movies with One to Many Model Factory Relationships5m 24s
-
5.6Listing A Director's Movies with Relationship Existence Queries8m 41s
-
5.7Listing and Counting a Writer's Movies8m 41s
-
5.8Using Eager and Lazy Loading to Load A Movie's Writer and Director5m 18s
-
5.9Defining Many-To-Many Relationships and Pivot Columns9m 48s
-
5.10Many-To-Many Model Factory Relationships4m 50s
-
5.11A Deep Dive Into Relationship CRUD with Models18m 5s
-
5.12How To Create Factory Relationships from a Pool of Data13m 55s
-
5.13How To Query, Sort, and Filter by Pivot Table Data9m 47s
-
-
Working With Forms
-
6.0Accepting Form Data12m 15s
-
6.1Validating Form Data with VineJS9m 29s
-
6.2Displaying Validation Errors and Validating from our Request7m 16s
-
6.3Reusing Old Form Values After A Validation Error2m 3s
-
6.4Creating An EdgeJS Form Input Component5m 28s
-
6.5Creating A Login Form and Validator5m 1s
-
6.6How To Create A Custom VineJS Validation Rule9m 7s
-
-
Authentication & Middleware
-
7.0The Flow of Middleware7m 49s
-
7.1Authenticating A Newly Registered User4m 14s
-
7.2Checking For and Populating an Authenticated User2m 10s
-
7.3Logging Out An Authenticated User2m 24s
-
7.4Logging In An Existing User6m 54s
-
7.5Remembering A User's Authenticated Session6m 55s
-
7.6Protecting Routes with Auth, Guest, and Admin Middleware5m 36s
-
-
Filtering and Paginating Queries
-
8.0Creating A Movie List Page3m 43s
-
8.1Filtering A Query By Pattern Likeness7m 9s
-
8.2Filtering Our List by Movie Status5m 47s
-
8.3How To Apply A Dynamic Sort Filter To Your Query7m 12s
-
8.4Joining SQL Tables To Order By A Related Column4m 49s
-
Validating Query String Filter Values7m 23s
-
How To Paginate Filtered Query Results9m 15s
-
Pagination First, Last, Next, and Previous Buttons4m 2s
-
-
User Watchlist
-
An Alternative Approach to Many-To-Many Relationships4m 56s
-
Toggling A Movie in an Authenticated User's Watchlist9m 56s
-
Listing and Filtering User Watchlist Items7m 34s
-
Allowing Users To Toggle A Movie As Watched4m 44s
-
Filtering By User's Watched Status6m 7s
-
Defining A Composite Unique Constraint4m 46s
-
Join The Discussion! (8 Comments)
Please sign in or sign up for free to join in on the dicussion.
frp
It would be cool to get some tutorials on using other output options, like pushing to a SPA or using a different templating engine.
Please sign in or sign up for free to reply
tomgobich
Agreed, and thank you for the suggestion! It'd be good to cover those things, and we will most certainly get to them! It won't be within this series though, as we want this series to be a good entry point for everyone coming to AdonisJS 6, and using EdgeJS is the most inclusive way to do that as it's a part of the framework.
We'll plan and add series for these into our schedule!
Please sign in or sign up for free to reply
frp
Thanks Tom. I imagine you also will be updating a lot of your v5 lessons to v6. I really like your style. I find you way easier to understand than most tutorialists
Please sign in or sign up for free to reply
tomgobich
Yeah, I've got quite a bit planned including additional focus on project-based series that'll cover updated topics we covered in v5! I'll be putting 100% of my focus on this series until we wrap it up, then we'll move onward from there 😄
Also, thank you very much that's very kind!! 😊
Please sign in or sign up for free to reply
frp
Hi Tom, can you tell me why when I inspect the request object the parsed url host, protocol, etc are always null? I'm not sure the difference between host and hostname (if they were not null I could figure it out haha), but I want to be able to key off of that value in my code. I could grab the host header and parse that, but I'd rather just use the parsedUrl property for everything.
Please sign in or sign up for free to reply
tomgobich
It looks like AdonisJS is using the
request.url
to parse these details out using theparse
method fromnode:url
and it looks like therequest.url
only contains the path for the request. So, it's being built without those details included and since theparsedUrl
object is just an instance ofURL
that'd be why they're still included despite being null.You can get a complete parse of the URL by doing:
Host and hostname will mostly be the same. The difference is, if the URL contains a port, host will include it and hostname will not.
Please sign in or sign up for free to reply
frp
Thanks! I followed the link to the source code and it looks like all I have to do to get what I want is request.hostname(), and that method just pulls the info out of the headers anyway.
Please sign in or sign up for free to reply
tomgobich
Anytime! Yep, that should do it! 😊
Please sign in or sign up for free to reply