Openhouse Build the Show Page
Learning objective: By the end of this lesson, students will be able to build the functionality for displaying a single resource on its show page.
User story
Now that we are displaying all the listings on our index view, let’s take a look at the next user story:
As a user interested in a property, I want to view all details of a listing, including information about its owner, by following a link from the main listing page.
Based on our user story, the show page should include information on the owner of the listing. Once again, we’ll be utilizing the populate() method to join the referenced data.
Conceptualizing the route
Our route should listen for GET requests on /listings/:listingId.
| Action | What It Does | HTTP Verb | Route |
|---|---|---|---|
| Show | Display a single listing | GET |
/listings/:listingId |
Building the UI
Next we’ll need to make a small change in views/listings/index.ejs. The UI that issues our GET request will be an anchor tag that prompts the user to ‘View more details’ about a particular listing. We’ll also need to include the listing._id in the request URL. This will allow us to retrieve a specific listing in our controller.
Update the <li> with the anchor element as shown below:
<!-- views/listings/index.ejs -->
<li>
A listing in <%= listing.city %> owned by <%= listing.owner.username %>.
<a href="/listings/<%= listing._id %>">View more details.</a>
</li>
Scaffolding the function
Next, let’s build the scaffolding for our controller function.
This scaffolding will help us confirm a few things:
- The route is responding to the request issued by the anchor tag in
views/listings/index.ejs. - Our function has access to the
listingIdbeing passed from the front end.
Add the following to controllers/listings.js:
// controllers/listings.js
router.get('/:listingId', async (req, res) => {
try {
console.log('listingId: ', req.params.listingId);
res.send(`Listings show page`);
} catch (error) {
console.log(error);
res.redirect('/');
}
});
After completing the steps above, click on the ‘View more details’ link on the listings landing page. In your browser, you should see the ‘Listings show page’ message. In your terminal, you should see the ObjectId for the listing that you clicked on.
Writing the controller action
Now that our function has access to the listingId, we can retrieve a specific listing and render it to the view.
Update the function as shown below:
// controllers/listings.js
router.get('/:listingId', async (req, res) => {
try {
const populatedListings = await Listing.findById(
req.params.listingId
).populate('owner');
res.render('listings/show.ejs', {
listing: populatedListings,
});
} catch (error) {
console.log(error);
res.redirect('/');
}
});
💡 In our application, we’ll need to
populate()theownerpath anytime we wish to display information about anownerbeyond anObjectId.
Rendering the view
Let’s outline some of the things we’ll need to accomplish in our show view.
We’ll want two sections here:
-
A details section with information on the listing, including its
city,size,price, andstreetAddress. -
An owner section displaying the
usernameof the listingowner, with a message indicating whether the user viewing the listing is the owner of the property.
Run the following command in your terminal to create a show.ejs file:
touch views/listings/show.ejs
Let’s address the boilerplate and listing details section first.
Add the following to the view:
<!-- views/listings/show.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= listing.owner.username %>'s listing</title>
</head>
<body>
<%- include('../partials/_navbar.ejs') %>
<h1>A listing in <%= listing.city %></h1>
<h2>Details</h2>
<p>House Size: <%= listing.size %> sq ft</p>
<p>Price: $<%= listing.price %></p>
<p>Street address: <%= listing.streetAddress %></p>
</body>
</html>
Finally, let’s add a section for information on the owner. We’ll make use of some conditional rendering here.
Add the following to the view:
<!-- views/listings/show.ejs -->
<h2>Owner</h2>
<% if (listing.owner._id.equals(user._id)) { %>
<p>You own this!</p>
<% } else { %>
<p>You don't own this, <%= listing.owner.username %> does!</p>
<% } %>
</body>
💡 Remember, thanks to the
populate()method, theownerproperty of alistingis now an object containing user data.