Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Express Basics Parameters, Query Strings, and Modularizing Routes Randomize Cards

How can the template read the properties?

In the card.js, we render the object templateData to the template 'card' with this line of code: res.render('card', templateData);

and in card.pug, we used template literals to retrive templateData's properties: templateData.sideToShow and templateData.sideToShowDisplay. With this line of code: a(href=${id}?side=${sideToShow})= sideToShowDisplay

What confuses me is that how can the pug template understand that these template literals refer to templateData object?

In my understanding, it this line of code in card.pug should rather be: a(href=${templateData.id}?side=${templateData.sideToShow})= sideToShowDisplay

Anyone can explain to me how this works?

Thank you in advance.

1 Answer

Dane Parchment
MOD
Dane Parchment
Treehouse Moderator 11,077 Points

What you are asking is actually quite a complicated questions because it requires knowledge of how Pug's source code actually works. Luckily it is an open source project so if you have the knowledge you can go to their github repo and see how they do it themselves.

Now to be honest, I only briefly skimmed the code when i was looking over it but what I am guessing is happening is that the object that you provide is being merged with another object. If you actually look through the code and their API the render method actually takes three parameters 1 of which is required:

pug.render(source, ?options, ?callback) (the 2 optional parameters start with a question mark)

The ?options parameter is the important one here. It actually expects specific options in this case it is actually expecting the options object to contain these two specific attributes:

 * Options:
 *
 *   - `cache` enable template caching
 *   - `filename` filename required for `include` / `extends` and caching

The code above was taken directly from the source-code of pug which you can find here.


The API for the render method actually confirms this in it's explanation of the render method here, where it states that options is:

An options object, also used as the locals object

So what does this mean? Basically they are expecting the object to contain 2 specific attributes, anything else it contains will be relegated to a locals object, which is the information that you specifically provide to the template. How? Well to be honest I only briefly skimmed the code, and so only have a minute understanding of it. From what I gather, they merge the expected options attributes and the attributes you provide into a new object:

Example:

// Object you provide:
let ob = {title: "Hiyas", content: "This is some content."}

// when you call the render method
pug.render('h1 #{title} p#{content}', ob);

// what it is doing behind the scenes
let newObj = {
    cache: null,
    filename: null,
    self: {
        title: "Hiyas",
        content: "This is some content."
    }
}

Notice how in the newObj that pug creates cache and filename are both null? This is because we didn't provide them as attributes in our object that we provided. So it assumes they are null when it merges them into the new object. The data we sent is relegated to an attribute called self which I believe occurs in this line of code here


So in our example pug will render:

<h1>Hiyas</h1>
<p>This is content.</p>

I think this is because when the parser sees the references you make in the code, what it is actually doing is passing in that data to the self attribute, and returning the values there:

Example:

<!-- What the data actually looks like -->
<h1>newObj.self[title]</h1>
<p>newObj.self[content]</p>

I know that was confusing, and again, maybe an instructor would know better, or someone who works on Pug itself can better answer you.

Very through explaination! Did not expect that one could take effort to look over the source code to find this answer. Thanks to your response, I can say I may understand the basic logic now, maybe I should look into the source code as well, seems a bit difficult for me though. Many thanks Dane.