When Loading Fails

The page in this exercise says Loading… and nothing more, however long you wait. The console says why:

[Vue warn]: Unhandled error during execution of mounted hook
  at <App>
SyntaxError: Failed to execute 'json' on 'Response': Unexpected token 'N', "Not Found" is not valid JSON
    at eval (App.vue:9)

There's a typo in the name of the file: menus.json. There's no such file, so the server answers with the status 404 Not Found, as you know from the JavaScript course, and sends the text Not Found instead of the menu. On line 9, response.json() can't read that as JSON and ends with an error, and the function in onMounted stops there. It never gets to loading.value = false, so the page keeps saying Loading….

Check response.ok before you read the data: it's false when the server answered with an error. Keep the message for the customer in a ref, and set loading to false in both cases:

const error = ref("");

onMounted(async () => {
    const response = await fetch("menu.json");
    if (!response.ok) {
        error.value = "The menu couldn't be loaded.";
    } else {
        menu.value = await response.json();
    }
    loading.value = false;
});

In the template, the message is a third case between the other two, with v-else-if, which you know from Conditions and Lists:

<template>
    <h1>Corner Café</h1>
    <p v-if="loading">Loading…</p>
    <p v-else-if="error" class="error">{{ error }}</p>
    <ul v-else>
        <li v-for="item in menu" :key="item.id">{{ item.name }}: €{{ item.price }}</li>
    </ul>
</template>

Empty text counts as false in a condition, and any other text as true, so the message shows only when there is one.

And what if the connection doesn't work at all? Then no answer comes, and fetch() itself ends with an error, TypeError: Failed to fetch, which you'd catch with try/catch, as in the JavaScript course. In the preview, an answer always comes, so here you'll check response.ok.

Instructions

  1. Add a ref error with empty text. In onMounted, check response.ok: when it's false, put The menu couldn't be loaded. into error, and otherwise read the menu. Set loading to false after both. Show the message with <p v-else-if="error" class="error"> between the paragraph and the list.

  2. Now fix the name of the file in fetch(), so that the page shows the menu.