Playing Next Lesson In
seconds

Transcript

  1. So whenever we select the web starter kit with AdonisJS 6, it's going to come with the EdgeJS template engine alongside it.

  2. We've already worked with this a little bit. It's actually what's rendering out our page within our application so far. Additionally, if we dive back into our text editor and we head into our homepage,

  3. it's also what's allowing us to loop over our movies, declare an href for our route and build out the actual route from our route method, as well as plop the actual movie title

  4. directly into the HTML using interpolation. We've also already learned on our movie show page, by default, whenever we use two curly braces, it will encode anything that we plop into the HTML.

  5. But if we include three curly braces, we're telling it that we trust the underlying value that we're injecting into our HTML therein, and it will render it out raw. We've seen this already, but for example,

  6. if we remove our third curly brace and switch our movie abstract back to just two, and we dive into one of our movie show pages, we see the underlying HTML because it's being encoded.

  7. Whereas if we add that third curly brace back in, instead the HTML is directly applied into our HTML document, and this is now a valid paragraph. The EdgeJS template engine is doing all that work

  8. underneath the hood for us, and it's integrating deeply with AdonisJS to make that a seamless process. If we head into edgejs.dev, we'll see the documentations for EdgeJS itself.

  9. We see an example right off the bat for the interpolation that we've been using so far. And in addition to that, we can actually use valid JavaScript expressions within these interpolated curly braces here as well.

  10. Not only that, but we can define our own stateful variables within EdgeJS, apply conditionals, we've already seen loops, and then it has support for components as well.

  11. Additionally, whenever we use that inspect method to actually view the underlying properties of an object and all of its values, that was from EdgeJS as well. So let's slide back to our text editor here,

  12. and we can, underneath our movie abstract, inspect, call that as a method, and pass in our movie, give that a save, and we'll see once more, we see all of the different properties that are on our movie.

  13. Now, we can actually do that exact same thing for the entirety of our state that we have within EdgeJS as well. This is all held within a property called state. So let's go ahead and give this a save,

  14. and let's inspect our state. So out of the box, we're gonna see that this has quite a lot added to it. A lot of these that we see so far are all helper methods. We have the inspect method right here.

  15. We can truncate string, get an excerpt for a string, HTML helpers, JavaScript helpers, switch text to camel case, snake case, dash case,

  16. all the various cases, pretty print milliseconds. And then as we scroll down a little bit further, we start getting into app information, configuration, byte. We have our request information.

  17. So within our request, we can see the parse URL and see that we're at the path name movie slash another awesome movie. We have contextual information from our HTTP context. And we just keep scrolling and scrolling and scrolling.

  18. This is just gonna go on and on and on. Our state holds quite a bit, particularly within the request and response objects of our state. Lastly, down here at the bottom,

  19. we actually see the movie that's on our state, which matches exactly what we saw whenever we inspected just our movie. So if you ever do need to dive into your state

  20. and see what all is available to you, now you know how to do that. Just give it an inspect. So let's go ahead and get rid of this because it's taking up quite a bit of space and give this a save. There we go, that's better.

  21. Okay, so within our movie model, we made our movies abstract optional. So if we scroll up to where we have the properties defined, the abstract is actually optional,

  22. meaning it could be a string or it could be null. So if we dive into one of our movies, let's go into our resources, movies, and we're at another awesome movie. So we'll do this one for right now. We can get rid of this abstract altogether.

  23. And now all that we have is our YAML front matter data. We don't have any additional information within this file. We'll go ahead and give it a save. And so that we actually see this without having to deal with clearing out our cache,

  24. let's dive into our movie model once more. And let's actually just disable the cache check for right now. So we'll just give this a comment out, give this a save, jump back into our browser and give it a refresh.

  25. So presently this is working okay because ultimately we're reading the value from a file and that file is gonna return back some kind of a value, regardless of whether or not we've defined the value there.

  26. But if you see here, we have nothing additional within our HTML markup besides our H1. This could become problematic. So let's dive back into our show page.

  27. If we start wrapping this information within say a div class, margin Y eight, maybe we give it a background too.

  28. So background slate 100, rounded Excel, and maybe P8 as well. So if we start applying styling based around this content,

  29. let's give this a save, jump back into our browser. You'll see that we have nothing inside of it, but if we dive back to one of our other movies, there's our abstract. Okay, so let's dive back into another movie.

  30. So let's use a conditional to actually show this only when we have an abstract. So let's dive back into our markup and we can do @if movie.abstract,

  31. and then we can indent our div here, and then we can end our if by doing @endif. I'll get this line break there as well. We can give this a save, jump back into our browser.

  32. And now that background color is gone because we don't have an abstract on this particular movie. But if we jump back to our first movie, it's still there A-okay. And if you need to, you can do an if else as well.

  33. So let's dive back into this movie. Let's go ahead and get rid of our inspector, dive back into our code base, and let's do an @else. So if we have a movie abstract, our div with the background will be applied.

  34. Otherwise, let's just say no abstract. Give this a save, and there we see no abstract. Cool, so now we know how to do if else, and we had already previously covered loops

  35. with our homepage whenever we looped over all of the movies that we have to show them within our unordered list. Now for both of our pages here so far, we are including the navigation

  36. and we're redefining the navigation for each of our pages. So we have our full navigation here, and we have our full navigation on the movie show page as well. Well, we can actually extract this navigation out

  37. into what's called a partial, which is essentially just a partial markup file, allowing us to define the markup in one spot and reference it elsewhere throughout our EdgeJS files.

  38. So within our views directory, let's go ahead and right-click it, create a new file. We'll call this partials. And for this, we'll call our file nav.edge. Give that a save.

  39. And now our views directory has both the pages and partials directory within it. Within our pages directory, let's dive back to our homepage. Let's give our navigation here a copy.

  40. Within our nav partial, we can now paste this in, fix the indenting there, give that a save. And now we can jump back into our homepage. And instead of manually defining the navigation,

  41. now all that we need to do is add, include, and then specify the path to the partial from our views directory, which will be partials/nav.

  42. So partials/nav. Now we can give this a save. Let's go ahead and jump back to our browser, head to our homepage, and we still have our navigation here. So let's go ahead and do the same thing

  43. on our movie show page. So let's give our include a copy, jump into our movie show page, replace the navigation here with our include, give it a save, jump back into the browser.

  44. And now we should be able to see the exact same thing on each and every one of our pages, which we do. So now within our homepage, we can do one more thing. We can add in our movie summaries underneath the actual movie title.

  45. So let's go and jump back into our text editor, jump back into our homepage, scroll down to where we're looping over each of our files. And underneath our anchor,

  46. let's go and add in a paragraph and inject movie.summary using interpolation here with double curly braces. We can add in a class, text, slate,

  47. maybe six or 700 and give it a save. Let's jump back into our browser. And okay, so we have our movie summary showing up underneath there. Let's give this a little bit of spacing too.

  48. So let's bring our text editor back up on our UL. Maybe we'll do class flex, flex column, gap of four, and give that a save, jump back into here.

  49. Okay, it's looking a little bit better. Let's push this from 700 to 600 and let's make the movie title bold. So we'll do class font bold, give that a save. All right, so that's looking better.

  50. Now let's say that we wanted to truncate this text down a little bit. Maybe it's a little bit too long for our liking. We can do that using one of the helpers from EdgeJS.

  51. So we dive back into the documentation and scroll on down. There's a digging deeper section with helpers within it. For this in particular, we see two different helpers. We see truncate and we see excerpt, which is just below truncate.

  52. The primary difference here is that excerpt will also strip out HTML markup. Now we've already removed the HTML markup from our summaries. So we're a-okay there. But if we wanted to, we could use this excerpt

  53. to extract a summary from our abstract and strip out the paragraph markup that we have within it or any additional HTML that we have within our abstract. But since we already have a summary,

  54. we're a-okay to go ahead and just use truncate here. The first argument will be the value that we wanna pass in and shorten. The second argument will be the number of characters that we wanna include.

  55. And we could conditionally provide a third argument, which is a configuration. We can specify it to only truncate at complete words, so it won't cut a word in half. And we could also add in a suffix as well.

  56. Okay, so let's go ahead and dive back into our application. Let's jump back into our text editor. Within our summary, we'll call truncate here, provide our movie summary as the first argument. I'm not quite sure how many characters we have,

  57. so we'll just go ahead and cut it off at 25. I think we have a little bit more than that. So we should be good. And we'll say complete words and set that to true. And then let's also end our function call there.

  58. Okay, so we should be good to give this a save. Jump back into our browser. Oh yeah, 25's kinda short, but yeah. We can see it actually working here. So now we have just lorem ipsum doler sit emet,

  59. and it cuts off the rest of the text there. So maybe we switch that to 50 instead of 25. So let's switch this to 50, give that a save. There we go, that's a little bit better.

EdgeJS Templating Basics

@tomgobich
Published by
@tomgobich
In This Lesson

We'll learn the basics of AdonisJS's homegrown template engine EdgeJS. We'll cover interpolation, conditional statements, looping, variables, state, and more!

Join the Discussion 13 comments

Create a free account to join in on the discussion
  1. Having worked exclusively with Express and EJS on the backend - Edge somehow feels more natural and nice on the eyes, just having that if else loop would be a visual eye-sore in EJS.

    Tom, thank you for this amazing content. I am slowing working through the videos and coding along, I later plan to pay for the monthly access for the Inertia videos. You content has been nothing short of clear and amazing so far.

    Lots of subtle lessons as well from your coding style too.

    1
    1. Responding to vladimir-laskin
      @tomgobich

      That's awesome to hear, Vladimir! I'm really happy to hear you're finding the lessons early to follow and enjoying them, thank you for sharing!

      1
  2. @frp

    Hi, I am getting the Cannot lookup rote Edge error when I try to use an edge template with the route() helper in it.

          Error: Cannot lookup route "moms.join"
              at anonymous (D:\www\seeds\resources\views\moms\pages\home.edge:95:0)
    <a class='button' href="{{ route('moms.join') }}">

    That route shows up in list:routes:
    GET /join (moms.join) .................................................. #controllers/join_controller.join

    What am I doing wrong? Please let me know what additional information is needed.

    Thank you.

    0
    1. Responding to frp
      @frp

      I should probably add that the 'moms' at the start of that route name is for a domain:

      router
        .group(() => {
          router.get('/join', [JoinController, 'join']).as('join')
        })
        .domain('moms.test')
        .as('moms')
      
      1
      1. Responding to frp
        @tomgobich

        I haven't yet worked with subdomains in AdonisJS 6, but I believe they work the same as in v5. When building the route's url using the route() method, the third argument accepts the domain.

        <a href="{{ route('moms.join', {}, { domain: 'moms.test' }) }}">
          My Link
        </a>
        Copied!

        The subdomain behavior is siloed, so you can have the same route defined outside the subdomain as well, and they can also be dynamic. Due to these reasons, that's why the domain will need specified when you're specifically looking to build a route for that domain.

        Hope this helps!

        0
        1. Responding to tomgobich
          @frp

          Wow thanks. I did not get that from the documentation anywhere. Hey, question: Do you know of any full-featured V6 example site on Github? It would be soooo helpful to see a full example of all this stuff, service providers, the container, everything.

          0
          1. Responding to frp
            @tomgobich
            1
        2. Responding to tomgobich
          @frp

          So this still is not working. I tried it just like that, console.log confirmed it, and it still says it "cannot look up" the route.

          How can I recreate the route outside of an Edge template? I don't see a helper for that. Laravel had a route helper you could use anywhere in the app to craft a url string. If I had that I could just craft the string in the service and feed it into Edge. Failing that, I will just have to manually create the URL strings. I can, but for all the reasons you know, would rather not.

          Thanks for all your help.

          0
          1. Responding to frp
            @tomgobich

            I just pushed up a working example of subdomain usage you can find at the link below. If you're linking into your subdomain, you'll want to prefix the generated url with your subdomain and include the port if you're local.
            https://github.com/adocasts/lets-learn-adonisjs-6/blob/subdomain_example

            The specific files of interest here are the route definition and the url generation inside of EdgeJS. Within the route definition I also added examples for both the URL builder and the makeUrl method AdonisJS provides. The route method inside EdgeJS is the same as the router.makeUrl method, so the arguments should match 1:1. Apologies, my formatter went a little extreme with the makeUrl usage lol.

            Hope this helps!! :)

            0
            1. Responding to tomgobich
              @frp

              Thanks, I will check it out. I thought I had found the answer (I found "URL Builder" in the docs) but it still won't look up the routes inside Edge. And one clarification: I'm not doing subdomains, I'm doing different domains. It works fine on the routing end - everything routes correctly - but it's just inside Edge that it won't work. I will look at what you did and can probably kitbash it to my usage. I really appreciate all your time. You're a mensch.

              Just FYI, this is how I generate the routes in my routes.ts file:

              for (let site in Sites) {
               router
                .group(() => {
                  router.get('/welcome/:tab?', [WelcomeController, 'welcome']).as('welcome')
                  router.get('/join', [JoinController, 'join']).as('join')
                  router.get('/upgrade', [JoinController, 'upgrade']).as('upgrade')
                  router.resource('users', UsersController).as('users')
                })
                .domain(Sites[site].domain)
                .as(site)
              }
              
              0
              1. Responding to frp
                @tomgobich

                Ah - gotcha, so you're using one server to serve multiple sites? If the routes are shared by all site, then you could most likely omit the .domain() usage as that essentially just namespaces the routes.

                Anytime! Hope you were able to get things working! :)

                0
                1. Responding to tomgobich
                  @frp

                  The URL builder in Adonis works fine, so I generate the route strings in my publish service and put the strings in the Edge template. Works great. Thanks!

                  0
                  1. Responding to frp
                    @tomgobich

                    Oh good, happy to hear you got everything working! :)

                    0