Image

touring-vue-router

5 min read
Last update: December 19, 2021

Flash Messages

Although this lesson doesn’t teach you anything new with Vue Router, it’ll cover a common web app notification feature, and utilize some features of Vue 3 to create global storage. But first, let me show you the problem we’re trying to solve.

🛑 Problem: Delivering a Temporary Message

Often in our application we’ll want to flash onto the screen a message for the user that goes away after 5 seconds. There are different names for this functionality, but I’ve come to know it as a “Flash Message.” The first place it might be nice to have a flash message is after a user registers for an event, letting them know they’re registered as we deliver them back to the event page:

📄 /src/views/event/Register.vue

<template>
    <p>Regstration form here</p>
    <button @click="register">Register Me!</button>
</template>
<script>
    export default {
        props: ['event'],
        methods: {
            register() {
                // Assuming successful API call to register them

                // Set a flash message to appear on the next page loaded which says
                // 'You are successfully registered for ' + this.event.title

                this.$router.push({
                    name: 'EventDetails',
                    params: {
                        id: this.event.id
                    }
                })
            }
        }
    }
</script>

As you can see above, before we push our navigation back to the event details page, we’d like to set a flash message to appear on that page communicating that the user is successfully registered. This kind of flash message can also be useful when a user is successfully logged in or logged out.

✅ Solution: Global Storage & Provide / Inject

There are several ways to solve this problem, but as always I want to show you the simplest, cleanest solution. We have three steps with my solution:

  1. Create a global storage mechanism to store our flash message.
  2. Set the flash message for registration inside our Register.vue.
  3. Create a place where the flash message is displayed in our App.vue.

Step 1: Global Storage

You might be thinking, “Isn’t this what Vuex is for? To have a global storage mechanism which can be accessed from different parts of my Vue app?” The answer is yes, this is exactly the problem that Vuex solves. However, Vuex can be complex to understand (and you don’t need to know it yet if you’re just learning) and we can use a simpler (and still elegant) solution for now thanks to Vue 3.

Vue 3 decoupled reactivity from components. This allows us to declare a reactive object independent of our components, and then inject that reactive object to the components who need it. Back in our main.js where our Vue instance is created we can create a Global Store, we’ll call GStore.

📄 /src/main.js

import { createApp, reactive } from 'vue' // <--- importing reactive import App from './App.vue' import router from './router' import store from './store' // Create a reactive object const GStore=reactive({ flashMessage: '' }) createApp(App) .use(store) .use(router) .provide('GStore', GStore) // provide this object so others can inject it .mount('#app') ``` Be sure to read the comments in the code above. You can think of `GStore` as a JavaScript Object which has reactivity, meaning that when any properties get changed it will be updated on our webpage. You can learn more about the `reactive` syntax in my [Vue 3 Composition API course](https://www.vuemastery.com/courses/vue-3-essentials/why-the-composition-api/), so I won’t go into more detail here. `Provide` has been around since Vue 2, and it allows us to specify data that we want **inject** into other components. You can think of it as an alternative to using `props` and `events` for component communication. We’ll use inject next to access it. ## Step 2: Create the Flash Message Back inside our Register component, we can now inject our `GStore` and use it to store our flashMessage: 📄 **/src/views/event/Register.vue** ```html <script>
    export default {
    props: ['event'],
    inject: ['GStore'], // <---- Inject the Global Store methods: { register() { // Assuming successful API call to register them this.GStore.flashMessage='You are successfully registered for ' + this.event.title setTimeout(()=> { // After 3 seconds remove it
        this.GStore.flashMessage = ''
        }, 3000)

        this.$router.push({
        name: 'EventDetails',
        params: { id: this.event.id }
        })
        }
        }
        }
        </script>
        ```

        Two things to notice above. First the `inject` component option, which gives our component access to our `GStore`. Then we set our flash message, and set a Timeout so that the flashMessage is cleared after 4 seconds.

        ## Step 3: Displaying the Flash Message

        Many components in our application will be creating these user messages, so we need to display this in our main layout, which in our app is our `App.vue`:

        📄 **/src/views/App.vue**

        ```html
        <template>
            <div id="app">
                <div id="flashMessage" v-if="GStore.flashMessage">
                    {{ GStore.flashMessage }}
                </div>
                ...
        </template>
        <script>
            export default {
                inject: ['GStore'] // <---- 
            }
        </script>

        <style>
            @keyframes yellowfade {
                from {
                    background: yellow;
                }

                to {
                    background: transparent;
                }
            }

            #flashMessage {
                animation-name: yellowfade;
                animation-duration: 3s;
            }

            ...
        </style>
        ```

        Notice how we’re injecting and displaying the `flashMessage` if it exists, and I’ve added an animation so that it’s highlighted in yellow and fades away (see the style) when the div appears on the screen, so it’ll draw the user’s eyes. In the browser it looks like this:

        ![https://firebasestorage.googleapis.com/v0/b/vue-mastery.appspot.com/o/flamelink%2Fmedia%2Ffinished-1920.gif?alt=media&token=95664a0b-c470-4dda-b59b-05fbe55b4153](https://firebasestorage.googleapis.com/v0/b/vue-mastery.appspot.com/o/flamelink%2Fmedia%2Ffinished-1920.gif?alt=media&token=95664a0b-c470-4dda-b59b-05fbe55b4153)

        ## In ReVue

        Now we have a Flash Message we can use throughout our application. We also have a global store which we’ll need in upcoming lessons to store data fetched by our API. Why? Because sometimes we’ll want to make sure our API call is successful before our component is loaded. Right now we’re loading our component whether or not it’s successful and our API call is coupled with our component itself. This may not be what we want, and we’ll explain why in the next lesson.