<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ #vue-router - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ #vue-router - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 28 Jul 2026 09:16:03 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/vue-router/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Migrate from Vue v.2 to Vue v.3 with a Simple Example Project ]]>
                </title>
                <description>
                    <![CDATA[ By Fabio Pacific What is Vue.js? Vue.js is a progressive JavaScript frontend framework written by Evan You. It's one of the most powerful and easy to learn frameworks, and it has over 9.5 million downloads per month. In September 2020, Vue 3 core was... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/migrate-from-vue2-to-vue3-with-example-project/</link>
                <guid isPermaLink="false">66d45eeb868774922c884fe2</guid>
                
                    <category>
                        <![CDATA[ Front-end Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ #vue-router ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 02 Jun 2021 19:14:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/Cover_migration_vue_2_3.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Fabio Pacific</p>
<h2 id="heading-what-is-vuejs">What is Vue.js?</h2>
<p>Vue.js is a progressive JavaScript frontend framework written by Evan You. It's one of the most powerful and easy to learn frameworks, and it has over 9.5 million downloads per month.</p>
<p>In September 2020, Vue 3 core was released. The new Vue.js release introduces some cool new features but also some breaking changes.</p>
<h2 id="heading-why-should-i-migrate-to-vue3">Why should I migrate to Vue3?</h2>
<p>As the tech industry evolves, so do libraries, languages, and frameworks. At each release, bugs are fixed and new features introduced. And often with any major release, your workflow is enhanced. New features can give you the opportunity to do things that were tedious before.</p>
<p>Vue 3 is still relatively new. You don't have to migrate all your projects over, but as time goes by, support for version 2 might end. Because of this it's a good idea to know the steps you'll need to take to migrate your projects.</p>
<p>In this guide, I'll walk you through the basic steps you will need to follow to approach the migration. We will take a simple project and migrate it to Vue 3.</p>
<p>The project that we will use is intentionally simple, and so anyone can follow along. The more complex your project is, the more carefully you'll want to plan for the migration.</p>
<h2 id="heading-intro">Intro</h2>
<p>The new Vue.js version does come with quite a few breaking changes and new features. Also, popular libraries like Vue Router have been updated to support the new Vue version.</p>
<p>If you already know Vue 2, the basics are quite the same. But before you can migrate a project to Vue 3 there are changes you need to take into account.</p>
<p>Depending on the size of the project you want to migrate, make sure to consider all the changes introduced with the new release so that your application will still work after the migration.</p>
<p>For this tutorial, I'll keep things simple and show you how to migrate a Vue.js project that currently uses the Vue 2 CDN.</p>
<p>I'm taking the project from the book I wrote for freeCodeCamp, which you can find <a target="_blank" href="https://www.freecodecamp.org/news/build-a-portfolio-with-vuejs/">here</a>. </p>
<p>In that project we used Vue Router, so we will also look at Vue router's changes in this article.</p>
<h2 id="heading-what-you-need-to-follow-along-with-this-article">What you need to follow along with this article</h2>
<p>To follow along you need a basic knowledge of Vue.js and Vue Router. If you don't have that. then I suggest you start by checking out my book available on <a target="_blank" href="https://www.freecodecamp.org/news/build-a-portfolio-with-vuejs/">freeCodeCamp</a>.</p>
<p>You can also find the playlist with the full 8 hour course available for free on my <a target="_blank" href="https://www.youtube.com/playlist?list=PL-qez5yxvgfjYZE_BP7WyxZuLyVPyWrF1">YouTube channel</a>.</p>
<h2 id="heading-what-well-cover-in-this-article">What we'll cover in this article</h2>
<p>This tutorial is organised into three main chapters. First, we will have a look at the changes in Vue.js v3.x then a quick overview of Vue Router v4.x. And finally, we will start planning the migration of a real project.</p>
<ul>
<li>Vue v3.x overview<ul>
<li>breaking changes</li>
</ul>
</li>
<li>Vue Router v4.x overview<ul>
<li>breaking changes</li>
</ul>
</li>
<li>Portfolio Project Migration<ul>
<li>Clone the Repo</li>
<li>Update CDN scripts</li>
<li>Update Vue instance</li>
<li>Update Vue Router instance</li>
</ul>
</li>
</ul>
<p>Here's the video version of this article if you want to follow along there:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/5y8-fKSY_Lg" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Watching the video will help you reinforce your learning while reading the steps below. Here you can find the final <a target="_blank" href="https://bitbucket.org/fbhood/advanced-vuejs/src/master/">repository</a> for the project.</p>
<h2 id="heading-vue-v3x-overview">Vue v3.x Overview</h2>
<p>Vue 3 introduces a few new features and a bunch of breaking changes. Let's see how these changes will affect our application and consider them before migrating.</p>
<h3 id="heading-vue-v3x-breaking-changes">Vue V3.x Breaking Changes</h3>
<p>In Vue 3 the breaking changes basically fall into seven categories:</p>
<ul>
<li>Global API
(responsible for how Vue behaves) - it's highly likely that you want to look at these changes.</li>
<li>Template Directives
(Changes made to how v- directives work) - it's highly likely that you want to look at these changes.</li>
<li>Components
(Changes to how components work) - if your application uses components it's highly likely that you want to look at these changes</li>
<li>Render Function (Lets you create HTML elements programmatically)</li>
<li>Custom Elements (Tells Vue about the creation of custom HTML elements)</li>
<li>Minor Changes (These might not affect you, but you'll still want to look into these)</li>
<li>Removed APIs (Things that are no longer available in Vue 3)</li>
</ul>
<p>Among all the changes there are some of them that any application will use, like the Global API and components. So you will need to take them into account if you want to start using the new Vue release.</p>
<p>And it's worth mentioning the following additional changes:</p>
<ul>
<li>The way you create Vue Applications and Component Instances has changed (Global API)</li>
<li>You should always declare the data option as a function (minor change)</li>
<li>Change of precedence when using v-if and v-for on the same element (template Ddrectives)</li>
<li>You should declare an emits option for component events (components)</li>
</ul>
<p>For a complete list of changes, you can head over to the <a target="_blank" href="https://v3.vuejs.org/guide/migration/introduction.html#breaking-changes">documentation</a></p>
<p>Let's look at some of these changes in more detail now.</p>
<h3 id="heading-how-to-create-application-and-component-instances-in-vue-3">How to Create Application and Component Instances in Vue 3</h3>
<p>In Vue 3 the way you create an app has changed. The Vue app now uses the new <code>.createApp()</code> method to create application instances. </p>
<p>The Vue application is now considered a root component, so the way you define its data options has changed as well.</p>
<p>The HTML root element hasn't changed, so inside an index.html file, you will still see something like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Inside the JavaScript file, there is an important change you need to understand: You will no longer use <code>new Vue()</code> to create a new app instance but instead you'll use a new method called <code>createApp()</code>:</p>
<pre><code class="lang-js">
<span class="hljs-comment">// Vue 3 syntax</span>

<span class="hljs-keyword">const</span> app = Vue.createApp({
    <span class="hljs-comment">// options object</span>
})
app.mounth(<span class="hljs-string">'#app'</span>) <span class="hljs-comment">// Vue Instance - Root component</span>

<span class="hljs-comment">// Vue 2 syntax</span>
<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-comment">// options object</span>
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>
})
</code></pre>
<h3 id="heading-how-to-define-a-component-in-vue-3">How to Define a Component in Vue 3</h3>
<p>To define a component in Vue 3, you no longer use <code>Vue.component()</code>. Instead you now use the application root component, like so:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Vue 3 syntax */</span>
<span class="hljs-keyword">const</span> app = Vue.createApp({
    <span class="hljs-comment">// options here</span>
})

app.component(<span class="hljs-string">'componenet-name'</span>, {
    <span class="hljs-comment">// component code here</span>
})


<span class="hljs-comment">/* Vue 2 syntax*/</span>
Vue.component(<span class="hljs-string">'component-name'</span>, {
    <span class="hljs-comment">// component code here</span>
})
</code></pre>
<h3 id="heading-how-to-use-the-data-options-object-in-vue-3">How to Use the Data Options Object in Vue 3</h3>
<p>Given that the main app instance is now considered a root component, you can no longer specify the data property as an object. Instead, you need to define it as a function that returns an object like you usually do in components.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Vue 3</span>
<span class="hljs-keyword">const</span> app = Vue.createApp({
    <span class="hljs-comment">// options object</span>
    data(){
        <span class="hljs-keyword">return</span> {
            <span class="hljs-attr">message</span>: <span class="hljs-string">'hi there'</span>
        }
    }
})
app.mounth(<span class="hljs-string">'#app'</span>) <span class="hljs-comment">// Vue Instance - Root component</span>

<span class="hljs-comment">// Vue 2 syntax</span>
<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-comment">// options object</span>
    <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">message</span>: <span class="hljs-string">'hi there'</span>
    }
})
</code></pre>
<h3 id="heading-change-of-precedence-for-v-ifv-for-in-vue-3">Change of Precedence for v-if/v-for in Vue 3</h3>
<p>In Vue 2 if you used both directives on the same element, the v-for directive would take precedence over v-if. But in Vue 3 v-if always takes precedence.</p>
<p>However, using both directives isn't a great idea. Make sure to visit the documentation <a target="_blank" href="https://v3.vuejs.org/guide/migration/v-if-v-for.html#overview">here</a> to learn more.</p>
<h3 id="heading-how-to-use-the-emits-property-on-component-events-in-vue-3-breaking-changenew-feature">How to Use the Emits Property on Component Events in Vue 3 (breaking change/new feature)</h3>
<p>Similar to the <code>props</code> property, now in Vue 3 there is also an <code>emits</code> property that a component can use to declare the events that it can emit to the parent component.</p>
<p>I strongly recommend using this property to avoid emitting events twice in components that need to re-emit native events, like a click event.</p>
<p>Here is an example from the official documentation:</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{ text }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">v-on:click</span>=<span class="hljs-string">"$emit('accepted')"</span>&gt;</span>OK<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/template&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
    <span class="hljs-attr">props</span>: [<span class="hljs-string">'text'</span>],
    <span class="hljs-attr">emits</span>: [<span class="hljs-string">'accepted'</span>]
  }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre>
<p>The emits property can also accept an object.  </p>
<p>I won't go in-depth into this just yet, but I'll tackle each of the features/changes in a dedicated video series sooner or later, I promise.</p>
<h2 id="heading-vue-router-v4x-overview">Vue Router v4.x Overview</h2>
<p>With the new release of Vue.js, we also have a new version of Vue Router. The new release v4.x has some breaking changes that you'll need to consider if you want to migrate a project to the new Vue release.</p>
<h3 id="heading-vue-router-v4-breaking-changes">Vue Router V4 Breaking Changes</h3>
<p>Two breaking changes are especially worth mentioning, since they are at the base of a Vue Router application. You will need to know about them to migrate your application later.</p>
<ul>
<li>The Vue Router instance has changed</li>
<li>Theres a new history option</li>
</ul>
<p>The full list of changes is available <a target="_blank" href="https://next.router.vuejs.org/guide/migration/index.html">here</a>.</p>
<p>Let's look at these two changes in depth.</p>
<h3 id="heading-the-vue-router-4-instance-has-changed">The Vue Router 4 Instance Has Changed</h3>
<p>To create a new Vue Router instance, you no longer use the VueRuter function constructor.</p>
<p>Here is the Vue Router v.3x <a target="_blank" href="https://router.vuejs.org/guide/#javascript">documentation</a> so you can compare.</p>
<p>The code changes from this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// 3. Create the router instance and pass the `routes` option</span>
<span class="hljs-comment">// You can pass in additional options here, but let's</span>
<span class="hljs-comment">// keep it simple for now.</span>
<span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> VueRouter({
  routes <span class="hljs-comment">// short for `routes: routes`</span>
})

<span class="hljs-comment">// 4. Create and mount the root instance.</span>
<span class="hljs-comment">// Make sure to inject the router with the router option to make the</span>
<span class="hljs-comment">// whole app router-aware.</span>
<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Vue({
  router
}).$mount(<span class="hljs-string">'#app'</span>)
</code></pre>
<p>To this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// 3. Create the router instance and pass the `routes` option</span>
<span class="hljs-comment">// You can pass in additional options here, but let's</span>
<span class="hljs-comment">// keep it simple for now.</span>
<span class="hljs-keyword">const</span> router = VueRouter.createRouter({
  <span class="hljs-comment">// 4. Provide the history implementation to use. We are using the hash history for simplicity here.</span>
  <span class="hljs-attr">history</span>: VueRouter.createWebHashHistory(), <span class="hljs-comment">// &lt;-- this is a new property and it is mandatory!</span>
  routes, <span class="hljs-comment">// short for `routes: routes`</span>
})

<span class="hljs-comment">// 5. Create and mount the root instance.</span>
<span class="hljs-keyword">const</span> app = Vue.createApp({})
<span class="hljs-comment">// Make sure to _use_ the router instance to make the</span>
<span class="hljs-comment">// whole app router-aware.</span>
app.use(router)

app.mount(<span class="hljs-string">'#app'</span>)
</code></pre>
<p>In the code above, to create a new Vue router instance you now have to use the VueRouter object and call the <code>createRouter()</code> method. </p>
<p>Also, the new history property is mandatory – <code>history: VueRouter.createWebHashHistory()</code>. You must define it or you will get a console error.</p>
<p>Next, you'll create the Vue instance using the <code>createApp()</code> method and use the variable <code>app</code> to call the <code>.use()</code> method. You pass the router instance there that you created in the previous step.</p>
<p>Finally, you can mount the root DOM element on the app instance using <code>app.mount('#app')</code>.</p>
<p>You can read the Vue router v4.x <a target="_blank" href="https://next.router.vuejs.org/guide/#javascript">documentation</a> for more details.</p>
<h2 id="heading-how-to-migrate-a-portfolio-project-from-vue-2-to-vue-3">How to Migrate a Portfolio Project from Vue 2 to Vue 3</h2>
<p>You can see how to do this in the video on <a target="_blank" href="https://youtu.be/5y8-fKSY_Lg">YouTube</a> if you'd like to follow along.</p>
<p>Considering all the above, and after a careful review of the breaking changes, let's try to upgrade one of our projects my Vue course. I'll use the Portfolio, the final project of the course.</p>
<p>We'll need to:</p>
<ul>
<li>Clone the repo</li>
<li>Update the CDN scripts</li>
<li>Update the Vue instance</li>
<li>Update the Vue Router instance</li>
</ul>
<p>To migrate our app to Vue 3 we will definitely need to update the following:</p>
<ul>
<li>Vue Application instance</li>
<li>Vue-Router instance</li>
<li>CDN Links</li>
</ul>
<p>Let's take it step by step.</p>
<h3 id="heading-clone-the-project-repository">Clone the Project Repository</h3>
<p>First, make sure you clone the repo inside the current folder:</p>
<pre><code class="lang-sh">git <span class="hljs-built_in">clone</span> https://bitbucket.org/fbhood/vue-folio/src/master/ vue-folio
</code></pre>
<p>Since our project still uses the CDN, the next step is to update its links.</p>
<h3 id="heading-update-the-projects-cdn">Update the Project's CDN</h3>
<p>In our project we're using both the Vue CDN and the Vue Router CDN, so let's update them both.</p>
<p>Open the index.html file and replace this:</p>
<pre><code class="lang-html">    <span class="hljs-comment">&lt;!-- VueJS 3 production version --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/vue@2.6.12"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Vue Router --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/vue-router@2.0.0/dist/vue-router.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>with this:</p>
<pre><code class="lang-html">    <span class="hljs-comment">&lt;!-- VueJS 3 --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/vue@3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Vue Router --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/vue-router@4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h3 id="heading-update-the-code">Update the Code</h3>
<p>Now if you open the project with the live server and open the inspector, you will notice that the application doesn't show up and there are two errors in the console. Both seem related to the Vue router:</p>
<pre><code class="lang-js">You are running a development build <span class="hljs-keyword">of</span> Vue.
Make sure to use the production build (*.prod.js) when deploying <span class="hljs-keyword">for</span> production.

Uncaught <span class="hljs-built_in">TypeError</span>: <span class="hljs-built_in">window</span>.Vue.use is not a <span class="hljs-function"><span class="hljs-keyword">function</span>
    <span class="hljs-title">at</span> <span class="hljs-title">vue</span>-<span class="hljs-title">router</span>.<span class="hljs-title">js</span>:1832
    <span class="hljs-title">at</span> <span class="hljs-title">vue</span>-<span class="hljs-title">router</span>.<span class="hljs-title">js</span>:9
    <span class="hljs-title">at</span> <span class="hljs-title">vue</span>-<span class="hljs-title">router</span>.<span class="hljs-title">js</span>:10

<span class="hljs-title">Uncaught</span> <span class="hljs-title">ReferenceError</span>: <span class="hljs-title">VueRouter</span> <span class="hljs-title">is</span> <span class="hljs-title">not</span> <span class="hljs-title">defined</span>
    <span class="hljs-title">at</span> <span class="hljs-title">main</span>.<span class="hljs-title">js</span>:185</span>
</code></pre>
<p>Vue router?! Why?</p>
<p>Well, remember that when Vue was rewritten, its libraries had to update their codebases, too. So don't forget those breaking changes related to Vue-router since our application uses it.</p>
<p>Let's first update the main Vue instance to use the new syntax. Then we will look at what changes we need to make so that Vue Router works.</p>
<p>Update this code inside the main.js file from this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// create and mount the Vue instance</span>

<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Vue({
    router
}).$mount(<span class="hljs-string">'#app'</span>)
</code></pre>
<p>to this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// create and mount the Vue instance</span>

<span class="hljs-keyword">const</span> app = Vue.createApp({
    router
})
app.mount(<span class="hljs-string">'#app'</span>)
</code></pre>
<h3 id="heading-vue-router-4-changes">Vue Router 4 Changes</h3>
<p>Above we saw the new syntax to define the root Vue instance component. But now, since we are using the Vue router, we need to take into account its <a target="_blank" href="https://next.router.vuejs.org/guide/migration/index.html">breacking changes</a> too.</p>
<h4 id="heading-the-way-vue-router-is-instantiated-has-changed">The way Vue Router is instantiated has changed</h4>
<p>It changed from this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// create the router instance</span>
<span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> VueRouter({
    routes
})
</code></pre>
<p>to this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// create the router instance</span>
<span class="hljs-keyword">const</span> router = VueRouter.createRouter({
    <span class="hljs-comment">// Provide the history implementation to use. We are using the hash history for simplicity here.</span>
    <span class="hljs-attr">history</span>: VueRouter.createWebHashHistory(),
    routes, <span class="hljs-comment">// short for `routes: routes`</span>
})
</code></pre>
<p>The code above deals with two major changes: <code>new VueRouter()</code> has been replaced by <code>VueRouter.createRouter()</code>, and the new <code>history</code> option now replaces <code>mode</code>.</p>
<p>Visit the <a target="_blank" href="https://next.router.vuejs.org/guide/#html">documentation</a> for Vue Router 4 to find out more.</p>
<p>Finally, let's make our app aware that we are using Vue Router. If we injected the router instance in the Vue app, now we need to instruct it to use the Vue router, use the <code>.use()</code> method to do so, and pass to it the router instance.</p>
<p>Change from this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// create and mount the Vue instance</span>

<span class="hljs-keyword">const</span> app = Vue.createApp({
    router
})
app.mount(<span class="hljs-string">'#app'</span>)
</code></pre>
<p>to this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// create and mount the Vue instance</span>

<span class="hljs-keyword">const</span> app = Vue.createApp({})
app.use(router)
app.mount(<span class="hljs-string">'#app'</span>)
</code></pre>
<p>And there you have it!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>It doesn't really matter how complex your Vue application is – if you want to migrate to a new major release you will still need to plan for it, read the release notes, and go over all the breaking changes to make sure that you understand what will break. </p>
<p>The more complex the application is and more carefully you should plan your migration.</p>
<p>For our simple application that's all there is to do. But it's not always like that. So get ready and plan in advance.</p>
<p>If you enjoyed this guide please share the article and remember to subscribe to my <a target="_blank" href="https://youtube.com/channel/UCTuFYi0pTsR9tOaO4qjV_pQ">YouTube channel</a>. Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to build a SPA using Vue.js, Vuex, Vuetify, and Firebase: adding authentication with Firebase ]]>
                </title>
                <description>
                    <![CDATA[ By Jennifer Bland Part 4: learn how to use Firebase to add authentication and a cart Meal Prep application Learn how to create a meal delivery website using Vue.js, Vuex, Vue Router, and Firebase. This is part four of my four-part series on building... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-spa-using-vue-js-vuex-vuetify-and-firebase-adding-authentication-with-firebase-d9932d1e4365/</link>
                <guid isPermaLink="false">66d460d8a326133d12440a6e</guid>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                    <category>
                        <![CDATA[ #vue-router ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Vuex ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 28 Nov 2018 01:13:39 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*_oxBC3QDl02cB2MDOzGXZg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jennifer Bland</p>
<h4 id="heading-part-4-learn-how-to-use-firebase-to-add-authentication-and-a-cart">Part 4: learn how to use Firebase to add authentication and a cart</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/OEAiRGPTXUXg4SP-gqbkQthWuYTwQrThqkdu" alt="Image" width="800" height="411" loading="lazy">
<em>Meal Prep application</em></p>
<p>Learn how to create a meal delivery website using Vue.js, Vuex, Vue Router, and Firebase.</p>
<p>This is part four of my four-part series on building a Vue application. Here is a list of all the parts:</p>
<p><a target="_blank" href="https://medium.com/p/838b40721a07">Part 1: Installing Vue and Building an SPA using Vuetify and Vue Router</a></p>
<p><a target="_blank" href="https://medium.com/p/fc5bd065fe18">Part 2: Using Vue Router</a></p>
<p><a target="_blank" href="https://medium.com/p/f8036aa464ad">Part 3: Using Vuex and accessing API</a></p>
<p><a target="_blank" href="https://medium.com/p/d9932d1e4365">Part 4: Using Firebase for Authentication &amp; Cart</a></p>
<h3 id="heading-recap">Recap</h3>
<p>In the first part of this series, we created our Vue application using the Vue CLI. Also, we added Vuetify to the app. We used Vuetify to style our home page.</p>
<p>In the second part, we used Vue Router to add navigation between the different pages of our app. We added components for all the pages in our application.</p>
<p>In the third part, we were introduced to Vuex. We signed up for an API to provide recipes and used axios to retrieve them. This data was stored in the Vuex store which made it accessible to every component in the application.</p>
<h3 id="heading-what-is-firebase">What is Firebase?</h3>
<p>Firebase is a real-time cloud infrastructure for client-side apps. Firebase can turn any <em>Frontend</em> application into a full-stack product capable of scaling infinitely in the cloud. It abstracts away most of your complex server-side features like user authentication, data persistence, file storage, and microservices, so you can focus on building an awesome experience for the end user.</p>
<p>The first step is to go to <a target="_blank" href="https://firebase.google.com">firebase and create a new account</a>. Log in to the account that you created. You will see this dashboard:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/nh3agjDtQIfZb5NsgLroWojeEEZ0Nm-uI614" alt="Image" width="800" height="649" loading="lazy">
<em>Firebase Demo</em></p>
<p>Click the <code>Add Project</code> button. Enter a name for your project. I entered “meal-prep” for the name of my project. Check all checkboxes. Then click the <code>create project</code> button.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/33vedZNLJ3WoqpIr7XzQRpXznXO8TOfQHY-Z" alt="Image" width="587" height="706" loading="lazy">
<em>Add new project dialog on Firebase</em></p>
<p>Once your project is created, Firebase will take you to your project’s home page.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/G80ee1kcRa8BJmt-ZjJp7yvrZEzpiply5seN" alt="Image" width="800" height="347" loading="lazy">
<em>Project Home Page</em></p>
<p>We need to integrate our project’s configuration into our meal-prep application. Click on the web button to add Firebase to your application. (NOTE: if you are not sure which button that is, it is the button with the <code>&lt;</code>;/&gt;. In the image above, the button is right above the words “get started.” Click the copy button to copy the snippet to your clipboard.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/nstMKziQenAP2sNjXnSyoPGKRNuVdEjTufzq" alt="Image" width="800" height="546" loading="lazy">
<em>Firebase config snippet</em></p>
<p>Next, we need to incorporate this snippet into our meal prep application. You can initialize your firebase application in the <code>main.js</code> file. You can do it in the <code>App.vue</code> file.</p>
<p>Instead, we are going to create a new directory called firebase in the src folder. Inside this new directory create a file called <code>index.js</code>. Paste the contents of your clipboard into this file. Remove the two lines with the <code>script</code> tags. In the first line of the file import firebase. On the last line initialize firebase. Your file should look like this:</p>
<pre><code><span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase'</span>;<span class="hljs-keyword">const</span> config = {    <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"&lt;youKeyHere&gt;"</span>,    <span class="hljs-attr">authDomain</span>: <span class="hljs-string">"&lt;youKeyHere&gt;"</span>,    <span class="hljs-attr">databaseURL</span>: <span class="hljs-string">"&lt;youKeyHere&gt;"</span>,    <span class="hljs-attr">projectId</span>: <span class="hljs-string">"&lt;youKeyHere&gt;"</span>,    <span class="hljs-attr">storageBucket</span>: <span class="hljs-string">"&lt;youKeyHere&gt;"</span>,    <span class="hljs-attr">messagingSenderId</span>: <span class="hljs-string">"&lt;youKeyHere&gt;"</span>};firebase.initializeApp(config);
</code></pre><p>We are importing firebase from an npm package that we have not installed yet. Let’s install it now. In your terminal, install firebase with this command:</p>
<pre><code>npm install firebase --save
</code></pre><p>Now that we have installed firebase and created a config file, we need to add this file to our application so Vue is aware of it. Open up the <code>main.js</code> file and import in the config file we created. Here is what my <code>main.js</code> file looks like:</p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-string">'@babel/polyfill'</span>;<span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>;<span class="hljs-keyword">import</span> <span class="hljs-string">'./plugins/vuetify'</span>;<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.vue'</span>;<span class="hljs-keyword">import</span> router <span class="hljs-keyword">from</span> <span class="hljs-string">'./router'</span>;<span class="hljs-keyword">import</span> store <span class="hljs-keyword">from</span> <span class="hljs-string">'./store'</span>;<span class="hljs-keyword">import</span> <span class="hljs-string">'@/firebase/'</span>;Vue.config.productionTip = <span class="hljs-literal">false</span>;<span class="hljs-keyword">new</span> Vue({    router,    store,    <span class="hljs-attr">render</span>: <span class="hljs-function"><span class="hljs-params">h</span> =&gt;</span> h(App)}).$mount(<span class="hljs-string">'#app'</span>);
</code></pre><p>Go back to your firebase console in the browser. Click on <code>Authentication</code>. Click on the <code>set up sign-in method</code> button.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/eKoTHvMZxWj28bIBc1vy18y4Q4fnSSypzEjD" alt="Image" width="800" height="368" loading="lazy">
<em>Setting up authentication in firebase</em></p>
<p>In the list of sign-in providers, click on Email/Password:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/yiS92UoxyI60pQDvGKkmeduz0cqML4qRBPuw" alt="Image" width="800" height="397" loading="lazy">
<em>List of sign-in providers</em></p>
<p>Enable the option to all users to sign up using their email address and password. Then click the <code>save</code> button.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/85suaEwdDT71E0k3QbSPegLPeABexqZGJ3ov" alt="Image" width="800" height="259" loading="lazy">
<em>Enable sign up using email and password</em></p>
<h4 id="heading-creating-sign-up-form">Creating Sign Up Form</h4>
<p>In a previous post, we stubbed out the Join.vue and Signin.vue files. These two files will have almost the same code. We will create the Join form first. When we are finished we will copy/paste it into the Signin form.</p>
<p>Open the Join.vue component. You can remove everything that is in the template. Vuetify has a default layout structure for components. It flows like this:</p>
<ul>
<li>v-container</li>
<li>v-layout</li>
<li>v-flex</li>
</ul>
<p>So let’s create that layout now in the component. The start of our file looks like this:</p>
<pre><code>&lt;template&gt;    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">v-container</span> <span class="hljs-attr">fill-height</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">v-layout</span> <span class="hljs-attr">align-center</span> <span class="hljs-attr">justify-center</span>&gt;</span>            <span class="hljs-symbol">&amp;lt;</span>v-flex xs12 sm8 md4&gt;            <span class="hljs-tag">&lt;/<span class="hljs-name">v-flex</span>&gt;</span>        <span class="hljs-tag">&lt;/<span class="hljs-name">v-layout</span>&gt;</span></span>    &lt;<span class="hljs-regexp">/v-container&gt;&lt;/</span>template&gt;
</code></pre><p>For the <code>v-container</code> we are adding <code>fill-height</code>. We add this so that it centers the form vertically in the window. For the <code>v-flex</code> we add <code>xs12</code> <code>sm8</code> and <code>md4</code> values. This is similar to Bootstrap’s column width definition. On extra-small devices, the form will take up all 12 columns meaning the whole screen. On small devices, the form will be 3/4 of the screen wide. On medium and large screens the form will be 1/3 of the screen.</p>
<p>Inside the <code>v-flex</code> we are going to use a <code>v-card</code>. We add <code>class=”elevation-12"</code> to the <code>v-card</code> so that it appears to be floating above the page. For the top of the form, we will use a <code>v-toolbar</code>. We give it a color of <code>primary</code>. For the default installation of Vuetify the primary color is blue. We want the text in the toolbar to be white text instead of the default black. To turn the text white we add <code>dark</code> to the <code>v-toolbar</code>.</p>
<p>Next, we have a <code>v-card-text</code>. Inside of it, we have a <code>v-form</code>. For the form we are giving it a reference with the name of <code>form</code>. We are assigning it to the <code>v-model</code> with a value of <code>valid</code>.</p>
<p>The last thing we add is <code>lazy-validation</code>. Our form needs to capture the user’s email and password. We will use two <code>v-text-field</code> to capture these values. To make things look better I have prepended an icon for each field. Each field has a <code>v-model</code> and <code>rules</code>.</p>
<p>Before the form is submitted the field will be validated against all rules that are defined. If they pass then you can submit the form. We will take advantage of this when the user clicks the Join button.</p>
<p>The last item to add to the form is a button. We add a <code>v-card-actions</code> and add a button. Here is what the template looks like for our component:</p>
<pre><code>&lt;template&gt;    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">v-container</span> <span class="hljs-attr">fill-height</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">v-layout</span> <span class="hljs-attr">align-center</span> <span class="hljs-attr">justify-center</span>&gt;</span>            <span class="hljs-symbol">&amp;lt;</span>v-flex xs12 sm8 md4&gt;                <span class="hljs-tag">&lt;<span class="hljs-name">v-card</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"elevation-12"</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">v-toolbar</span> <span class="hljs-attr">dark</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>&gt;</span>                        <span class="hljs-tag">&lt;<span class="hljs-name">v-toolbar-title</span>&gt;</span>Join Form<span class="hljs-tag">&lt;/<span class="hljs-name">v-toolbar-title</span>&gt;</span>                    <span class="hljs-tag">&lt;/<span class="hljs-name">v-toolbar</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">;v-card-text</span>&gt;</span>                        <span class="hljs-tag">&lt;<span class="hljs-name">v-form</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"valid"</span> <span class="hljs-attr">lazy-validation</span>&gt;</span>;                            <span class="hljs-symbol">&amp;lt;</span>v-text-field prepend-icon="person" name="email" label="Email" type="email"                                          v-model="email" :rules="emailRules" required&gt;                            <span class="hljs-tag">&lt;/<span class="hljs-name">v-text-field</span>&gt;</span>                            <span class="hljs-tag">&lt;<span class="hljs-name">v-text-field</span> <span class="hljs-attr">prepend-icon</span>=<span class="hljs-string">"lock"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">label</span>=<span class="hljs-string">"Password"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"password"</span>                                          <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">required</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">:rules</span>=<span class="hljs-string">"passwordRules"</span>&gt;</span>                            <span class="hljs-tag">&lt;/<span class="hljs-name">v-text-field</span>&gt;</span>                        <span class="hljs-tag">&lt;/<span class="hljs-name">v-form</span>&gt;</span>                    <span class="hljs-tag">&lt;/<span class="hljs-name">v-card-text</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">v-card-actions</span>&gt;</span>                        <span class="hljs-tag">&lt;<span class="hljs-name">v-spacer</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-spacer</span>&gt;</span>                        <span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">:disabled</span>=<span class="hljs-string">"!valid"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"submit"</span>&gt;</span>Join<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>                    <span class="hljs-tag">&lt;/<span class="hljs-name">v-card-actions</span>&gt;</span>                <span class="hljs-tag">&lt;/<span class="hljs-name">v-card</span>&gt;</span></span>            &lt;<span class="hljs-regexp">/v-flex&gt;        &lt;/</span>v-layout&gt;    &lt;<span class="hljs-regexp">/v-container&gt;&lt;/</span>template&gt;
</code></pre><p>We defined several models in our template. We need to add them to the <code>data</code> section of our script. In the script add a data object. We will add valid, email, password, emailRules and passwordRules.</p>
<p>Email and password will contain the values the user inputs into the two text fields. Valid will tell if our form has passed all the rules we have created. For email, we check to make sure that the field is not empty. We also check that the contents match a basic RegExp to validate the email address. For password, we check to make sure the field is not empty. We also check to make sure the password is at least six characters in length.</p>
<p>Here is what the data object looks like now:</p>
<pre><code>data() {    <span class="hljs-keyword">return</span> {        <span class="hljs-attr">valid</span>: <span class="hljs-literal">false</span>,        <span class="hljs-attr">email</span>: <span class="hljs-string">''</span>,        <span class="hljs-attr">password</span>: <span class="hljs-string">''</span>,        <span class="hljs-attr">emailRules</span>: [            <span class="hljs-function"><span class="hljs-params">v</span> =&gt;</span> !!v || <span class="hljs-string">'E-mail is required'</span>,            <span class="hljs-function"><span class="hljs-params">v</span> =&gt;</span> <span class="hljs-regexp">/.+@.+/</span>.test(v) || <span class="hljs-string">'E-mail must be valid'</span>        ],        <span class="hljs-attr">passwordRules</span>: [            <span class="hljs-function"><span class="hljs-params">v</span> =&gt;</span> !!v || <span class="hljs-string">'Password is required'</span>,            <span class="hljs-function"><span class="hljs-params">v</span> =&gt;</span>                v.length &gt;= <span class="hljs-number">6</span> ||                <span class="hljs-string">'Password must be greater than 6 characters'</span>        ]    };},
</code></pre><p>The last thing we need to add is methods. In methods, we have <code>submit()</code>. This method will validate our form first. If it passes validation then it will call an action in our Vuex store called <code>userJoin</code>. We pass it the email and password the user entered in the form.</p>
<p>Here is what the methods look like:</p>
<pre><code>methods: {    submit() {        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.$refs.form.validate()) {            <span class="hljs-built_in">this</span>.$store.dispatch(<span class="hljs-string">'userJoin'</span>, {                <span class="hljs-attr">email</span>: <span class="hljs-built_in">this</span>.email,                <span class="hljs-attr">password</span>: <span class="hljs-built_in">this</span>.password            });        }    }}
</code></pre><h4 id="heading-creating-userjoin-action-in-vuex">Creating userJoin Action in Vuex</h4>
<p>Open up the <code>store.js</code> file. We will create a new action called <code>userJoin</code>. By default the first parameter passed to this action is <code>context</code>. I will use object destructuring to get just <code>commit</code> from <code>context</code>. Commit is how I will call my mutation.</p>
<p>I will be using firebase to create the new user in the firebase database. To be able to use firebase in the store, I will need to import it. At the top of the file import firebase with this command:</p>
<pre><code><span class="hljs-keyword">import</span> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase'</span>;
</code></pre><p>Firebase authentication provides a method called <code>createUserWithEmailAndPassword</code>. We will pass the user’s email and password into this method. If it succeeds in registering the user it will return a user object. When it succeeds we will call two mutations: <code>setUser</code> and <code>setIsAuthenticated</code>. Here is what the action looks like:</p>
<pre><code>userJoin({ commit }, { email, password }) {    firebase        .auth()        .createUserWithEmailAndPassword(email, password)        .then(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {            commit(<span class="hljs-string">'setUser'</span>, user);            commit(<span class="hljs-string">'setIsAuthenticated'</span>, <span class="hljs-literal">true</span>);        })        .catch(<span class="hljs-function">() =&gt;</span> {            commit(<span class="hljs-string">'setUser'</span>, <span class="hljs-literal">null</span>);            commit(<span class="hljs-string">'setIsAuthenticated'</span>, <span class="hljs-literal">false</span>);        });}
</code></pre><p>This action calls two mutations. So let’s create then now. In mutations add a new mutation called <code>setUser</code>. Set the state value of user to the payload. Next, create a second mutation called <code>setIsAuthenticated</code>. Set the state value of isAuthenticated to the payload. Here is what the two mutations look like:</p>
<pre><code>setUser(state, payload) {    state.user = payload;},setIsAuthenticated(state, payload) {    state.isAuthenticated = payload;}
</code></pre><p>In state, we need to add two new value: <code>user</code> and <code>isAuthenticated</code>. Here is what state looks like now:</p>
<pre><code>state: {    <span class="hljs-attr">recipes</span>: [],    <span class="hljs-attr">apiUrl</span>: <span class="hljs-string">'https://api.edamam.com/search'</span>,    <span class="hljs-attr">user</span>: <span class="hljs-literal">null</span>,    <span class="hljs-attr">isAuthenticated</span>: <span class="hljs-literal">false</span>},
</code></pre><h4 id="heading-test-adding-a-new-user">Test Adding a New User</h4>
<p>Start your server with the command <code>npm run serve</code>. Click on the <code>Join</code> button in the navigation. Enter your email and a password and click the join button. When you click the button nothing visible happens. To verify that the user was registered, go the firebase console in your browser. Click on <code>Authentication</code>. You should see a list of users that have been registered for your application. Here you can see that the user I just registered was created.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/vYkETdpPAbqno517wwsXH-g6tHJWZQXcQnrj" alt="Image" width="800" height="162" loading="lazy">
<em>User has been registered</em></p>
<p>We need to notify the user that they have been successfully created. We will do this but later. First, we are going to copy and paste the contents of the Join.vue component into the <code>Signin.vue</code> component. There are only two changes you will need to make in the template. Change the title to “Login Form.” For the button make the text say “Login.” In the submit method have it dispatch to <code>userLogin</code>. Just to make sure you have it correct, here is what my entire Signin.vue file looks like:</p>
<pre><code>&lt;template&gt;    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">v-container</span> <span class="hljs-attr">fill-height</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">v-layout</span> <span class="hljs-attr">align-center</span> <span class="hljs-attr">justify-center</span>&gt;</span>            <span class="hljs-symbol">&amp;lt;</span>v-flex xs12 sm8 md4&gt;                <span class="hljs-tag">&lt;<span class="hljs-name">v-card</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"elevation-12"</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">v-toolbar</span> <span class="hljs-attr">dark</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span>&gt;</span>                        <span class="hljs-tag">&lt;<span class="hljs-name">v-toolbar-title</span>&gt;</span>Login Form<span class="hljs-tag">&lt;/<span class="hljs-name">v-toolbar-title</span>&gt;</span>                    <span class="hljs-tag">&lt;/<span class="hljs-name">v-toolbar</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">;v-card-text</span>&gt;</span>                        <span class="hljs-tag">&lt;<span class="hljs-name">v-form</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"valid"</span> <span class="hljs-attr">lazy-validation</span>&gt;</span>;                            <span class="hljs-symbol">&amp;lt;</span>v-text-field prepend-icon="person" name="email" label="Email" type="email"                                          v-model="email" :rules="emailRules" required&gt;                            <span class="hljs-tag">&lt;/<span class="hljs-name">v-text-field</span>&gt;</span>                            <span class="hljs-tag">&lt;<span class="hljs-name">v-text-field</span> <span class="hljs-attr">prepend-icon</span>=<span class="hljs-string">"lock"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">label</span>=<span class="hljs-string">"Password"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"password"</span>                                          <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">required</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">:rules</span>=<span class="hljs-string">"passwordRules"</span>&gt;</span>                            <span class="hljs-tag">&lt;/<span class="hljs-name">v-text-field</span>&gt;</span>                        <span class="hljs-tag">&lt;/<span class="hljs-name">v-form</span>&gt;</span>                    <span class="hljs-tag">&lt;/<span class="hljs-name">v-card-text</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">v-card-actions</span>&gt;</span>                        <span class="hljs-tag">&lt;<span class="hljs-name">v-spacer</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-spacer</span>&gt;</span>                        <span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">:disabled</span>=<span class="hljs-string">"!valid"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"submit"</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>                    <span class="hljs-tag">&lt;/<span class="hljs-name">v-card-actions</span>&gt;</span>                <span class="hljs-tag">&lt;/<span class="hljs-name">v-card&amp;gt;</span>            &lt;/<span class="hljs-attr">v-flex</span>&amp;<span class="hljs-attr">gt</span>;        &lt;/<span class="hljs-attr">v-layout</span>&gt;</span></span>    &lt;<span class="hljs-regexp">/v-container&gt;&lt;/</span>template&gt;<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {    <span class="hljs-attr">name</span>: <span class="hljs-string">'Signin'</span>,    data() {        <span class="hljs-keyword">return</span> {            <span class="hljs-attr">valid</span>: <span class="hljs-literal">false</span>,            <span class="hljs-attr">email</span>: <span class="hljs-string">''</span>,            <span class="hljs-attr">password</span>: <span class="hljs-string">''</span>,            <span class="hljs-attr">emailRules</span>: [                <span class="hljs-function"><span class="hljs-params">v</span> =&gt;</span> !!v || <span class="hljs-string">'E-mail is required'</span>,                <span class="hljs-function"><span class="hljs-params">v</span> =&gt;</span> <span class="hljs-regexp">/.+@.+/</span>.test(v) || <span class="hljs-string">'E-mail must be valid'</span>            ],            <span class="hljs-attr">passwordRules</span>: [                <span class="hljs-function"><span class="hljs-params">v</span> =&gt;</span> !!v || <span class="hljs-string">'Password is required'</span>,                v =&amp;gt;                    v.length &gt;= <span class="hljs-number">6</span> ||                    <span class="hljs-string">'Password must be greater than 6 characters'</span>            ]        };    },    <span class="hljs-attr">methods</span>: {        submit() {            <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.$refs.form.validate()) {                <span class="hljs-built_in">this</span>.$store.dispatch(<span class="hljs-string">'userLogin'</span>, {                    <span class="hljs-attr">email</span>: <span class="hljs-built_in">this</span>.email,                    <span class="hljs-attr">password</span>: <span class="hljs-built_in">this</span>.password                });            }        }    }};</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre><p>That’s it. You have now created both the Join and Login forms.</p>
<p>We need to create the action for Login. Open up the <code>store.js</code> file. Create a new action called userLogin. We will use firebase to login the user. Firebase provides a method called <code>signInWithEmailAndPassword</code>. We will call this method and pass in the user’s email and password they entered into the form. If the user entered their email and password correctly then we will call the two mutations <code>setUser</code> and <code>setIsAuthenticated</code>. Here is what the <code>userLogin</code> action looks like:</p>
<pre><code>userLogin({ commit }, { email, password }) {    firebase        .auth()        .signInWithEmailAndPassword(email, password)        .then(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {            commit(<span class="hljs-string">'setUser'</span>, user);            commit(<span class="hljs-string">'setIsAuthenticated'</span>, <span class="hljs-literal">true</span>);        })        .catch(<span class="hljs-function">() =&gt;</span> {            commit(<span class="hljs-string">'setUser'</span>, <span class="hljs-literal">null</span>);            commit(<span class="hljs-string">'setIsAuthenticated'</span>, <span class="hljs-literal">false</span>);        });},
</code></pre><h4 id="heading-redirecting-to-profile">Redirecting to Profile</h4>
<p>When a user successfully registers or login, we want to redirect them to their profile. When we created our app initially the Vue CLI 3 it created two routes for us. Those routes were <code>/</code> and <code>/about</code>. Eventually, the profile will contain a list of all recipes that the user has ordered from the <code>menu</code> page. Remember the button we put at the bottom of every recipe? That button will add the recipe to the user’s profile and store it in the database in firebase.</p>
<p>To redirect the user to the profile we will first import router at the top of the store.js file. The router is imported with the command:</p>
<pre><code><span class="hljs-keyword">import</span> router <span class="hljs-keyword">from</span> <span class="hljs-string">'@/router'</span>;
</code></pre><p>Next, in both actions we redirect the user to /about if they successfully register or login. You can do the redirection with this command:</p>
<pre><code>router.push(<span class="hljs-string">'/about'</span>);
</code></pre><p>If the user fails to register an account or login successfully we will redirect the user to the home page. <em>(NOTE: in a perfect scenario we will provide some notice to the user why the registration or login failed).</em> You can redirect them to the home page with this command:</p>
<pre><code>router.push(<span class="hljs-string">'/'</span>);
</code></pre><p>To test the redirection, start your server and click on the Login button. Enter the email and password you used when you created your user account. Click the Join button. If everything worked successfully you should be redirected to the About page.</p>
<h4 id="heading-updating-the-navigation">Updating the navigation</h4>
<p>The navigation has buttons for <code>Sign In</code> and <code>Join</code>. When a user successfully registers or login we would like to hide these two buttons. In their place, we want to show a <code>Logout</code> button.</p>
<p>Open up the <code>AppNavigation</code> component. We are going to group the two current buttons in a div. We are going to remove the class to hide the buttons on small and extra-small devices. Instead, we will place this class on the div. We add a <code>v-if</code> to the div to only show if the user is currently not authenticated. Below the <code>div</code> we will add a new button for Logout. This new button will have a style of outline with a color of white. When you click on this button it will call the method <code>logout</code>. We add a v-else to this button to show when the user is authenticated.</p>
<p>Next, add a method called <code>logout</code>. This method will call an action in our store called <code>userSignOut</code>.</p>
<p>We also need to add a new computed property called <code>isAuthenticated</code>. This property returns the value of isAuthenticated in the state of our store.</p>
<p>Here is what your AppNavigation should look like:</p>
<pre><code>&lt;template&gt;    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">v-navigation-drawer</span> <span class="hljs-attr">app</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"drawer"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"brown lighten-2"</span> <span class="hljs-attr">dark</span> <span class="hljs-attr">disable-resize-watcher</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">v-list</span>&gt;</span>                <span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(item, index) in items"</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">v-list-tile</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span>&gt;</span>                        <span class="hljs-tag">&lt;<span class="hljs-name">v-list-tile-content</span>&gt;</span>                            {{item.title}}                        <span class="hljs-tag">&lt;/<span class="hljs-name">v-list-tile-content</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">;</span>/<span class="hljs-attr">v-list-tile</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">v-divider</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"`divider-${index}`"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-divider</span>&gt;</span>                <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>            <span class="hljs-tag">&lt;/<span class="hljs-name">v-list</span>&gt;</span>        <span class="hljs-tag">&lt;/<span class="hljs-name">v-navigation-drawer</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">v-toolbar</span> <span class="hljs-attr">app</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"brown darken-4"</span> <span class="hljs-attr">dark</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">v-toolbar-side-icon</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-md-and-up"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"drawer = !drawer"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-toolbar-side-icon</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">v-spacer</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-md-and-up"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-spacer</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&amp;<span class="hljs-attr">gt</span>;                &lt;<span class="hljs-attr">v-toolbar-title</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>{{appTitle}}<span class="hljs-tag">&lt;/<span class="hljs-name">v-toolbar-title</span>&gt;</span>;            <span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">;v-btn</span> <span class="hljs-attr">flat</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-sm-and-down"</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/menu"</span>&gt;</span>Menu<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">v-spacer</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-sm-and-down"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-spacer</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">;div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!isAuthenticated"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-sm-and-down"</span>&gt;</span>                <span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">flat</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/sign-in"</span>&gt;</span>SIGN IN<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>                <span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"brown lighten-3"</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/join"</span>&gt;</span>JOIN<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">v-else</span> <span class="hljs-attr">outline</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"white"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"logout"</span>&gt;</span>Logout<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span></span>        &lt;<span class="hljs-regexp">/v-toolbar&gt;    &lt;/</span>span&gt;&lt;<span class="hljs-regexp">/template&gt;&lt;script&gt;export default {    name: 'AppNavigation',    data() {        return {            appTitle: 'Meal Prep',            drawer: false,            items: [{ title: 'Menu' }, { title: 'Sign In' }, { title: 'Join' }]        };    },    computed: {        isAuthenticated() {            return this.$store.getters.isAuthenticated;        }    },    methods: {        logout() {            this.$store.dispatch('userSignOut');        }    }};&lt;/</span>script&gt;<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css"><span class="hljs-selector-tag">a</span> {    <span class="hljs-attribute">color</span>: white;    <span class="hljs-attribute">text-decoration</span>: none;}</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre><p>We need to add the getter and action we just defined. Open up the <code>store.js</code> file. Create a new action called <code>userSignout</code>. This action will use firebase.auth() to sign the user out. After signing the user out, it sets the state variables <code>user</code> to null and <code>isAuthenticated</code> to false. Here is the <code>userSignout</code> method in the store:</p>
<pre><code>userSignOut({ commit }) {    firebase        .auth()        .signOut()        .then(<span class="hljs-function">() =&gt;</span> {            commit(<span class="hljs-string">'setUser'</span>, <span class="hljs-literal">null</span>);            commit(<span class="hljs-string">'setIsAuthenticated'</span>, <span class="hljs-literal">false</span>);            router.push(<span class="hljs-string">'/'</span>);        })        .catch(<span class="hljs-function">() =&gt;</span> {            commit(<span class="hljs-string">'setUser'</span>, <span class="hljs-literal">null</span>);            commit(<span class="hljs-string">'setIsAuthenticated'</span>, <span class="hljs-literal">false</span>);            router.push(<span class="hljs-string">'/'</span>);        });}
</code></pre><p>Next, we need to add a <code>getters</code> section to the store object. The <code>isAuthenticated</code> getters method will return true or false based on user authentication. Here is what the <code>getters</code> section of the store looks like:</p>
<pre><code>getters: {    isAuthenticated(state) {        <span class="hljs-keyword">return</span> state.user !== <span class="hljs-literal">null</span> &amp;&amp; state.user !== <span class="hljs-literal">undefined</span>;    }}
</code></pre><h3 id="heading-adding-recipes-to-database">Adding Recipes to Database</h3>
<p>Once a user is logged in they can click on any recipe to add it to their account. Their recipes will be shown in their profile which is the <code>/about</code> route. We need a database to store these recipes. Go to your firebase console in the browser. Click on <code>database</code> in the left side navigation panel. On the next screen you will see buttons to create a realtime database or a cloud firestore database. Make sure you create a new realtime database. In the dialog make sure you select to <code>start in test mode</code>. Then click the <code>enable</code> button.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/nHYgB0KpSgNkOE49AhvBos0IHr3mWw35ZJQJ" alt="Image" width="736" height="461" loading="lazy">
<em>Start database in test mode</em></p>
<p>Now we want to store the user’s recipes in the database. Open up the MealRecipes component. If a user tries to order a recipe and they are not logged in then we should redirect them to the login page. So let’s take care of that now. On the <code>Order</code> button add an @click that calls the method orderRecipe. Be sure to pass in <code>item</code> as an argument to the method. Your button should look like this:</p>
<pre><code>&lt;v-card-actions&gt;    &amp;lt;v-btn color=<span class="hljs-string">"green"</span> dark @click=<span class="hljs-string">"orderRecipe(item)"</span>&gt;Order&lt;<span class="hljs-regexp">/v-btn&gt;&lt;/</span>v-card-actions&gt;
</code></pre><p>Before we create our method, we will create a computed value for isAuthenticated. This is the exact same code we used in <code>AppNavigation</code> earlier to show and hide the login and logout button correctly. Add a computed isAuthenticated. It should look like this:</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {    <span class="hljs-attr">name</span>: <span class="hljs-string">'MealRecipes'</span>,    <span class="hljs-attr">computed</span>: {        recipes() {            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.$store.state.recipes;        },        isAuthenticated() {            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.$store.getters.isAuthenticated;        }    }};
</code></pre><p>Now we are ready to create our orderRecipe method. Add this method and its parameter. In this method, we want to first check if the user is logged in or not. If they are not we want to redirect them to <code>/sign-in</code> . If they are signed in then we want to call an action in the Vuex store that will append the recipe to the user account in the database. Here is what our method looks like:</p>
<pre><code>methods: {    orderRecipe(item) {        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isAuthenticated) {            <span class="hljs-built_in">this</span>.$store.dispatch(<span class="hljs-string">'addRecipe'</span>, item);        } <span class="hljs-keyword">else</span> {            <span class="hljs-built_in">this</span>.$router.push(<span class="hljs-string">'/sign-in'</span>);        }    }}
</code></pre><p>Open up the store.js file. We need to create a new action to add recipes. In this action, we are going to use firebase to add the recipe to a database called <code>users</code>. When the user was registered in firebase they were assigned a unique userid. We will be using this <code>uid</code> to store the name of the recipe in the database.</p>
<p>In this action, we will be using <code>state</code> to get the value of the currently selected user. The <code>user</code> in <code>state</code> is an object. That object has a key called user. In that object, we will find the <code>uid</code>. We use that to push the title of the selected recipe into the database. Here is the action:</p>
<pre><code>addRecipe({ state }, payload) {    firebase        .database()        .ref(<span class="hljs-string">'users'</span>)        .child(state.user.user.uid)        .push(payload.recipe.label);}
</code></pre><p>Now start your server and log in. Select a diet from the menu page. Then order a couple of recipes. The recipes you ordered should be shown in the database in firebase.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/SBJUuIRCRWT2Fu3iAiZeEERyYXPTfeLaSLwt" alt="Image" width="800" height="273" loading="lazy">
<em>Recipes added to the database</em></p>
<p>Now that we have the recipes added to the database, we actually need to display them on the profile page for the user. Open up the <code>About.vue</code> file. Whenever this page is loaded it should fetch all the user’s recipes. To do this we add <code>mounted()</code> in our script. This will call a method called <code>getRecipes</code>.</p>
<p>Let’s create that method now. In the method, we are going to call an action in our Vuex store that will get all the user’s recipes. We have not created this action in the store yet but in simple terms, this action will get the user’s recipes. Then it will store them in a variable in <code>state</code> called <code>userRecipes</code>.</p>
<p>Before we leave About.vue, add a computed property for <code>userRecipes</code>. This will return the <code>userRecipes</code> from <code>state</code> in our store. This is what About.vue script should look like:</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {    <span class="hljs-attr">name</span>: <span class="hljs-string">'About'</span>,    <span class="hljs-attr">computed</span>: {        userRecipes() {            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.$store.state.userRecipes;        }    },    mounted() {        <span class="hljs-built_in">this</span>.getRecipes();    },    <span class="hljs-attr">methods</span>: {        getRecipes() {            <span class="hljs-built_in">this</span>.$store.dispatch(<span class="hljs-string">'getUserRecipes'</span>);        }    }};
</code></pre><p>Next, open up your <code>store.js</code> file. We need to create the <code>getUserRecipes</code> action. When the user logins we store a variable in <code>state</code> called user. This variable will have the unique user ID assigned to that user when it was registered in firebase. We want to get all the recipes in the users database that have this user ID. Once we get all the recipes we want to set userRecipes to contain them. Here is the getUserRecipes action:</p>
<pre><code>getUserRecipes({ state, commit }) {    <span class="hljs-keyword">return</span> firebase        .database()        .ref(<span class="hljs-string">'users/'</span> + state.user.user.uid)        .once(<span class="hljs-string">'value'</span>, <span class="hljs-function"><span class="hljs-params">snapshot</span> =&gt;</span> {            commit(<span class="hljs-string">'setUserRecipes'</span>, snapshot.val());        });}
</code></pre><p>In our mutations, we need to add a <code>setUserRecipes</code>. It looks like this:</p>
<pre><code>setUserRecipes(state, payload) {    state.userRecipes = payload;}
</code></pre><p>We also need to add a <code>userRecipes</code> in <code>state</code>. We set its initial value to an empty array. Here is my entire state object:</p>
<pre><code>state: {    <span class="hljs-attr">recipes</span>: [],    <span class="hljs-attr">apiUrl</span>: <span class="hljs-string">'https://api.edamam.com/search'</span>,    <span class="hljs-attr">user</span>: <span class="hljs-literal">null</span>,    <span class="hljs-attr">isAuthenticated</span>: <span class="hljs-literal">false</span>,    <span class="hljs-attr">userRecipes</span>: []},
</code></pre><p>Now that we are getting the recipes we need to display them on the page to the user. So go back to your <code>About.vue</code> file. In the template, we are going to loop through all the user’s recipes and display them. I am going to show you my code for the template first then explain what I have done:</p>
<pre><code>&lt;template&gt;    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">v-container</span> &gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">v-layout</span> <span class="hljs-attr">column</span>&gt;</span>;            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title my-3"</span>&gt;</span>My Recipes<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(item, idx) in userRecipes"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"subheading mb-2"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"idx"</span>&gt;</span>                {{item}}            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>        <span class="hljs-tag">&lt;/<span class="hljs-name">v-layout</span>&gt;</span>    <span class="hljs-tag">&lt;/<span class="hljs-name">v-container</span>&gt;</span></span>&lt;/template&gt;
</code></pre><p>I have set the layout to be <code>column</code>. I did this because I want each recipe to be listed on the page. To make things look clearer I have added a title. I added my-3 to add margin-top and margin-bottom so that there is spacing between the title and the list of recipes. Next, I looped through each recipe and display it. This is what the user sees if they have recipes:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/AXzGqeL9LhTRcYHIFkQgEjQwRAW4UFRP4Enr" alt="Image" width="800" height="113" loading="lazy">
<em>List of my recipes</em></p>
<p>This is great, but when if a user logs in and they do not have any recipes? They see the title “My Recipes” and a blank page. This is not a user-friendly design. So let’s change it to display something more friendly.</p>
<p>We will display a button that will take the user to the <code>menu</code> page. In our template, we will add this button. To make the button redirect to the menu page we can add <code>to=”/menu”</code> to the button. Here is my final template for the <code>About.vue</code> component.</p>
<pre><code>&lt;template&gt;    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">v-container</span> &gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">v-layout</span> <span class="hljs-attr">column</span>&gt;</span>;            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title my-3"</span>&gt;</span>My Recipes<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(item, idx) in userRecipes"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"subheading mb-2"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"idx"</span>&gt;</span>                {{item}}            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>            <span class="hljs-symbol">&amp;lt;</span>v-flex mt-4&gt;                <span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/menu"</span>&gt;</span>Go To Menu<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>            <span class="hljs-tag">&lt;/<span class="hljs-name">v-flex</span>&gt;</span>        <span class="hljs-tag">&lt;/<span class="hljs-name">v-layout</span>&gt;</span></span>    &lt;<span class="hljs-regexp">/v-container&gt;&lt;/</span>template&gt;
</code></pre><h4 id="heading-showing-profile-in-navigation">Showing Profile in Navigation</h4>
<p>The last thing we need to add is the ability to show a link to the profile in the navigation. Just like the logout button, this should only be shown if the user is authenticated.</p>
<p>Open up the AppNavigation components. We are going to group the profile button and the logout button in a div. This is the same thing we did earlier for the <code>Sign In</code> and <code>Join</code> buttons. Add a div and move the logout button to be inside this div. Add another button for <code>profile</code>. This button will be flat just like the <code>Sign In</code> button.</p>
<p>Here is what my AppNavigation looks like now:</p>
<pre><code>&lt;template&gt;    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">v-navigation-drawer</span> <span class="hljs-attr">app</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"drawer"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"brown lighten-2"</span> <span class="hljs-attr">dark</span> <span class="hljs-attr">disable-resize-watcher</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">v-list</span>&gt;</span>                <span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(item, index) in items"</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">v-list-tile</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span>&gt;</span>                        <span class="hljs-tag">&lt;<span class="hljs-name">v-list-tile-content</span>&gt;</span>                            {{item.title}}                        <span class="hljs-tag">&lt;/<span class="hljs-name">v-list-tile-content</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">;</span>/<span class="hljs-attr">v-list-tile</span>&gt;</span>                    <span class="hljs-tag">&lt;<span class="hljs-name">v-divider</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"`divider-${index}`"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-divider</span>&gt;</span>                <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>            <span class="hljs-tag">&lt;/<span class="hljs-name">v-list</span>&gt;</span>        <span class="hljs-tag">&lt;/<span class="hljs-name">v-navigation-drawer</span>&gt;</span>        <span class="hljs-tag">&lt;<span class="hljs-name">v-toolbar</span> <span class="hljs-attr">app</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"brown darken-4"</span> <span class="hljs-attr">dark</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">v-toolbar-side-icon</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-md-and-up"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"drawer = !drawer"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-toolbar-side-icon</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">v-spacer</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-md-and-up"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-spacer</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&amp;<span class="hljs-attr">gt</span>;                &lt;<span class="hljs-attr">v-toolbar-title</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>{{appTitle}}<span class="hljs-tag">&lt;/<span class="hljs-name">v-toolbar-title</span>&gt;</span>;            <span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">;v-btn</span> <span class="hljs-attr">flat</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-sm-and-down"</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/menu"</span>&gt;</span>Menu<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">v-spacer</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-sm-and-down"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">v-spacer</span>&gt;</span>            <span class="hljs-tag">&lt;<span class="hljs-name">;div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!isAuthenticated"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-sm-and-down"</span>&amp;<span class="hljs-attr">gt</span>;                &lt;<span class="hljs-attr">v-btn</span> <span class="hljs-attr">flat</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/sign-in"</span>&gt;</span>SIGN IN<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>                <span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"brown lighten-3"</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/join"</span>&gt;</span>JOIN<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>                <span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">flat</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/about"</span>&gt;</span>PROFILE<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>                <span class="hljs-tag">&lt;<span class="hljs-name">v-btn</span> <span class="hljs-attr">outline</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"white"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"logout"</span>&gt;</span>Logout<span class="hljs-tag">&lt;/<span class="hljs-name">v-btn</span>&gt;</span>            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>        &lt;<span class="hljs-regexp">/v-toolbar&gt;    &lt;/</span>span&gt;&lt;/template&gt;
</code></pre><h3 id="heading-adding-route-guards">Adding Route Guards</h3>
<p>Currently, the user can navigate to the profile page by typing it into the URL of the browser We don’t want to let users do this if they are not logged in. Vue Router provides the ability to add route guards before navigating to a URL. We want to test if a user is authenticated before allowing them to redirect to the <code>/about</code> page.</p>
<p>Open up the <code>router.js</code> file. Route guards work in conjunction with meta tags. Find the <code>/about</code> route. We will add a <code>authRequired</code> meta tag to it. The route should look like this:</p>
<pre><code>{    <span class="hljs-attr">path</span>: <span class="hljs-string">'/about'</span>,    <span class="hljs-attr">name</span>: <span class="hljs-string">'about'</span>,    <span class="hljs-attr">component</span>: () =&amp;gt; <span class="hljs-keyword">import</span>(<span class="hljs-string">'./views/About.vue'</span>),    <span class="hljs-attr">meta</span>: {        <span class="hljs-attr">authRequired</span>: <span class="hljs-literal">true</span>    }},
</code></pre><p>Route guards are checked in a method called beforeEach that is part of Vue Router. This method is passed three parameters:</p>
<ul>
<li>the route you are going to</li>
<li>the route you came from</li>
<li>a next method that continues with the current route</li>
</ul>
<p>Our beforeEach method will check every route that we are going to to see if it contains the meta tag of authRequired. If it does, it will check to see if the user is Authenticated. If the user is not authenticated it will redirect them to the <code>/sign-in</code> page. If the user is logged in then it will allow the route to proceed. If a user routes to any page that does not have the authRequired meta tag then the route will proceed.</p>
<p>Here is the method I have added to my router to do this checking:</p>
<pre><code>router.beforeEach(<span class="hljs-function">(<span class="hljs-params">to, <span class="hljs-keyword">from</span>, next</span>) =&gt;</span> {    <span class="hljs-keyword">if</span> (to.matched.some(<span class="hljs-function"><span class="hljs-params">record</span> =&gt;</span> record.meta.authRequired)) {        <span class="hljs-keyword">if</span> (!store.state.user) {            next({                <span class="hljs-attr">path</span>: <span class="hljs-string">'/sign-in'</span>            });        } <span class="hljs-keyword">else</span> {            next();        }    } <span class="hljs-keyword">else</span> {        next();    }});
</code></pre><h3 id="heading-get-the-code">Get the Code</h3>
<p>Even though this is a 4-part series, you can get the <a target="_blank" href="https://github.com/ratracegrad/meal-prep">finished code in my GitHub account.</a> Please help me out and <strong>star the repo</strong> when you get the code.</p>
<h3 id="heading-summary">Summary</h3>
<p>In this part of this series, you have learned:</p>
<ul>
<li>What is firebase</li>
<li>Using firebase to authenticate users who sign in with email and password</li>
<li>Using firebase to store the recipes a user has ordered</li>
<li>Using route guards to not users access pages if they are not authenticated</li>
<li>Display user’s list of recipes from the database on firebase</li>
</ul>
<p>If you enjoyed this article please clap for it. If you think somebody else would benefit from this article please share it with them.</p>
<p>If you have any questions or find anything wrong with the code, please leave a comment. If there are other topics you would like for me to write about, please leave a comment.</p>
<h4 id="heading-other-articles">Other Articles</h4>
<p>Here are other articles I have written that you might want to read.</p>
<p><a target="_blank" href="https://medium.freecodecamp.org/how-to-add-internationalization-to-a-vue-application-d9cfdcabb03b"><strong>How to add Internationalization to a Vue Application</strong></a><br><a target="_blank" href="https://medium.freecodecamp.org/how-to-add-internationalization-to-a-vue-application-d9cfdcabb03b">_¡Hola! Bonjour. Ciao. 你好. Here is how you add internationalization to Vue._medium.freecodecamp.org</a><a target="_blank" href="https://medium.com/dailyjs/instantiation-patterns-in-javascript-8fdcf69e8f9b"><strong>Instantiation Patterns in JavaScript</strong></a><br><a target="_blank" href="https://medium.com/dailyjs/instantiation-patterns-in-javascript-8fdcf69e8f9b">_Instantiation patterns are ways to create something in JavaScript. JavaScript provides four different methods to create…_medium.com</a><a target="_blank" href="https://hackernoon.com/here-are-5-layouts-that-you-can-make-with-flexbox-6ca1e941f33d"><strong>Here are 5 Layouts That You Can Make With FlexBox</strong></a><br><a target="_blank" href="https://hackernoon.com/here-are-5-layouts-that-you-can-make-with-flexbox-6ca1e941f33d">_The CSS Flexible Box Layout — Flexbox — provides a simple solution to the design and layout problems designers and…_hackernoon.com</a></p>
<p><a target="_blank" href="https://twitter.com/ratracegrad"><strong>Follow Me On Twitter!</strong></a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
