Bootcamp > Week 3 > Day 3

Overview of the day

Today we will display the image of each restaurant and add an additional page to our restaurant website to display information about the restaurant's menus.

We will also install Postman - a tool for that makes it easy to create, share and test APIs.


Lesson 1 - Adding an image

Learning Objectives

Lesson

We want to display an image in our card. The issue we face is that our different images are different sizes, yet we want them all to fit in our card nicely regardless. The trick that lots of developers use to accomplish this is use the background-image property. Setting an image as a background image in CSS gives us flexible sizing and cropping capabilities. This is very useful when our content is dynamic and we have images of varying sizes to deal with. Background images aren't printed by default either.

Background-image

Update your card to display the background image of your restaurant. Adapt the example below.

<h1>Restaurants</h1>
<section>
    {{#each restaurants}}
        <article>
            <header style="background-image: url({{this.image}})"></header>
            <main>{{this.name}}</main>
            <footer>{{this.menus.length}} menus</footer>
        </article>
    {{/each}}
</section>

To display the image correctly, you need to modify the styles.css file and target the <header> element inside the <article> to set some background properties including the image height.

article header {
    height: 24rem;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center center;
}

You can read more about what these properties do in this tutorial.

Assignment


Lesson 2 - Route parameters

Learning Objectives

Lesson

We want to read what is on the menu for these lovely looking restaurants. For that level of detail we need to alter the view so we are just looking at one restaurant at a time. In this session we are going to create a page for each individual restaurant.

Dynamic links

To be able to click on a restaurant card and then view that restaurant's page we need to create a dynamic link. We are going to do this by wrapping our restaurant card in an 'anchor' tag. We then make the href point to a particular address on our server. Update your cards like this:

<h1>Restaurants</h1>
<section>
    {{#each restaurants}}
        <a href="/restaurants/{{this.id}}">
            <article>
                <header style="background-image: url({{this.image}});">
                <main>{{this.name}}</main>
                <footer>{{this.menus.length}} menus</footer>
            </article>
        </a>
    {{/each}}
</section>

As you hover over each card can you see the URL it links to in the bottom left-hand corner of your chrome browser. Clicking this link will cause a 404 error, as that page or resource does not exist yet.

Cannot GET /restaurants/2

New Route

To deal with this new request we need to add a new route on our server. Not just any route, the last part of our route is going to be different depending on which restaurant we are clicking on. We need a route that also has a route parameter. Add the new route below to your server.

app.get('/restaurants/:id', async (req, res) => {
    console.log("get restaurant with ID:", req.params.id)
    res.send()
})

Like before we add a new route, but in the string definition of the route we indicate a route parameter /:id called 'id'. We can now read that value in our route handler. What do you think we are going to do with this id?

New template

Before we get our data, lets just create the new template for this view. In the views folder add a file called restaurant.handlebars. Add some html so you know you have wired the route up to the template ok. Can you pass the correct arguments to your res.render()?

Now we can focus on getting our data for this view.

app.get('/restaurants/:id', async (req, res) => {
    const restaurant = await Restaurant.findByPk(req.params.id)
    const menus = await restaurant.getMenus({
        include: [{model: MenuItem, as: 'items'}],
        nest: true
    })
    res.render('restaurant', {restaurant, menus})
})

2 levels of iteration

This view of a restaurant requires us to iterate over the array of menus, and within each menu we iterate over that menus array of items. WOW!

<h1>{{restaurant.name}}</h1>
<section>
    {{#each menus}}
        <article>
            <h2>{{this.title}}</h2>
            <dl>
                {{#each this.items}}
                    <div>
                        <dt>{{this.name}}</dt>
                        <dd>£{{this.price}}</dd>
                    </div>
                {{/each}}
            </dl>
        </article>
    {{/each}}
</section>

Finally we have some menus, the fact we are using the same elements in the same order means our css is already being applied. The <dl> element is a 'description list' you can read more about it here. To get the item name and price to line up nicely like below I am using flexbox. More about flexbox later...

flexbox example

dl div{
    display: flex;
    justify-content: space-between;
    padding: 1rem;
}

Assignment


Lesson 3 - Postman

Learning Objectives

Lesson

Tomorrow & Day 5 you will be creating and updating restaurants. Therefore you will need a tool for sending your routes (APIs) form or JSON content. One of the most popular tools for this is Postman.

Assignment

TODO - move this content someone else

Flexbox is really powerful when styling smaller components. Once a parent element is display:flex its behaviour changes. Now items line up in a row. You can change this flex-direction to column. The beauty of flex is being able to have elements fill (or flex) arbitrary space. We can also position elements along the flex axis.

The Box Model

attendance log main|prev|next