<?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 - 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 - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 25 May 2026 22:38:03 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/vue/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How Vue Composables Work – Explained with Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ Vue composables are a very helpful tool when developing Vue applications. They give developers an easy way to reuse logic across our applications. In addition to allowing for “stateless” logic (things like formatting or routine calculations), composa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-vue-composables-work/</link>
                <guid isPermaLink="false">684c58453ee20021234073af</guid>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Brian Barrow ]]>
                </dc:creator>
                <pubDate>Fri, 13 Jun 2025 16:56:37 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749830866913/e732db46-638b-42cd-aabf-ad51a54a3409.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Vue composables are a very helpful tool when developing Vue applications. They give developers an easy way to reuse logic across our applications. In addition to allowing for “stateless” logic (things like formatting or routine calculations), composables also give us the ability to reuse stateful logic throughout the app.</p>
<p>Before diving into the tutorial below, I want to mention that the documentation for Vue is <em>really</em> good. <a target="_blank" href="https://vuejs.org/guide/reusability/composables">The page on composables</a> explains the basics really well and will get you 90 percent of the way there. I am writing this article because I think the examples in the docs could go a little deeper in explaining how things can work inside of a composable. I will be reiterating some of the information from the docs, but I will also provide an example of a more complex composable.</p>
<h3 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-why-use-composables">Why Use Composables?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-simple-composable-example">Simple Composable Example</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-complex-composable-example">Complex Composable Example</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-util-function-for-fetch">Util function for fetch</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-useasyncstate-composable">useAsyncState Composable</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-usage-in-a-component">Usage in a component</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-why-use-composables">Why Use Composables?</h2>
<p>Composables let you reuse stateful logic across your apps. Whenever there is logic that is used in more than two places, we typically want to pull that logic into its own function. Most of the time, that logic is considered “stateless”, meaning that it takes an input and returns an output. The docs mention date formatting, but this could also include something like currency calculations or string validation.</p>
<p>In modern web applications, there are often pieces of logic that require managing state over time. Inside a typical component, we have the ability to adapt the application depending on the “state” of different variables within the component. Sometimes that logic, or at least pieces of that logic, are reused throughout the app.</p>
<p>For example, in an e-commerce application, you might have logic to increase and decrease the quantity of a product a person is adding to their cart. This logic could be used both on the product page, and inside the cart itself.</p>
<p>The look and feel of both those places will be different, so re-using a full component wouldn’t make sense – but we still want to centralize the logic to make the code easier to maintain. That is where Composables come in.</p>
<p>(It is worth noting that not everything needs to be a composable. Logic that is only used in a single component shouldn’t be refactored into a composable until necessary.)</p>
<h2 id="heading-simple-composable-example">Simple Composable Example</h2>
<p>Let’s take a look at a simple counter example. Here is some code for a very simple <code>Counter</code> component.</p>
<pre><code class="lang-typescript">&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
  <span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
  <span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { Ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>

  <span class="hljs-keyword">const</span> count: Ref&lt;<span class="hljs-built_in">number</span>&gt; = ref(<span class="hljs-number">0</span>)
  <span class="hljs-keyword">const</span> increment = <span class="hljs-function">() =&gt;</span> {
    count.value++
  }
  <span class="hljs-keyword">const</span> decrement = <span class="hljs-function">() =&gt;</span> {
    count.value--
  }
&lt;/script&gt;

&lt;template&gt;
  &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"bg-teal-100 border-2 border-gray-800 rounded-xl p-4 w-64"</span>&gt;
    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-center mb-4"</span>&gt;
      &lt;span <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-lg font-medium text-gray-800"</span>&gt;Count: {{ count }}&lt;/span&gt;
    &lt;/div&gt;

    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"flex gap-2 justify-center"</span>&gt;
      &lt;button
        <span class="hljs-meta">@click</span>=<span class="hljs-string">"decrement"</span>
        <span class="hljs-keyword">class</span>=<span class="hljs-string">"bg-red-100 border-2 border-gray-800 rounded px-4 py-0 text-gray-800 font-medium hover:bg-red-500 transition-colors"</span>
      &gt;
        -
      &lt;/button&gt;

      &lt;button
        <span class="hljs-meta">@click</span>=<span class="hljs-string">"count = 0"</span>
        <span class="hljs-keyword">class</span>=<span class="hljs-string">"bg-gray-100 border-2 border-gray-800 rounded px-4 py-0 text-gray-800 font-medium hover:bg-gray-300 transition-colors"</span>
      &gt;
        Reset
      &lt;/button&gt;

      &lt;button
        <span class="hljs-meta">@click</span>=<span class="hljs-string">"increment"</span>
        <span class="hljs-keyword">class</span>=<span class="hljs-string">"bg-green-100 border-2 border-gray-800 rounded px-4 py-0 text-gray-800 font-medium hover:bg-green-500 transition-colors"</span>
      &gt;
        +
      &lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre>
<p>The output of that component would look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748355723167/8c39759c-6fd9-4fcf-abdf-f67e672c172f.gif" alt="8c39759c-6fd9-4fcf-abdf-f67e672c172f" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>This works great, but if we end up needing this same counter logic in another component with a completely different look and feel, then we would end up repeating the logic. We can extract the logic into a composable and access the same stateful logic anywhere we need to.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// counter.ts</span>
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { Ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useCounter</span>(<span class="hljs-params"></span>): <span class="hljs-title">Readonly</span>&lt;</span>{
  count: Ref&lt;<span class="hljs-built_in">number</span>&gt;
  increment: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>
  decrement: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>
}&gt; {
  <span class="hljs-keyword">const</span> count: Ref&lt;<span class="hljs-built_in">number</span>&gt; = ref(<span class="hljs-number">0</span>)
  <span class="hljs-keyword">const</span> increment = <span class="hljs-function">() =&gt;</span> {
    count.value++
  }
  <span class="hljs-keyword">const</span> decrement = <span class="hljs-function">() =&gt;</span> {
    count.value--
  }
  <span class="hljs-keyword">return</span> { count, increment, decrement }
}
</code></pre>
<p>Then we update the script tag in the component to use the composable:</p>
<pre><code class="lang-typescript">&lt;script setup&gt;
<span class="hljs-keyword">import</span> { useCounter } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/counter.ts'</span>

<span class="hljs-keyword">const</span> { count, increment, decrement } = useCounter()
&lt;/script&gt;

&lt;template&gt;
  ...
&lt;/template&gt;
</code></pre>
<p>Now we can use this logic in multiple components throughout the app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748355833182/d90d000e-f309-4b22-9530-8e4614b450ec.gif" alt="d90d000e-f309-4b22-9530-8e4614b450ec" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You will notice that only the logic is copied and each component still has its own copy of the <code>count</code> state. Using a composable does not mean the state is shared across components, only the stateful logic.</p>
<h2 id="heading-complex-composable-example">Complex Composable Example</h2>
<p>In the Vue docs, they give an example of using a composable to handle async data fetching. There are a couple of issues I have with the example they give. The main one is that the error handling is not robust for real world applications. Given that they just want to showcase a straightforward use of composables, this is understandable. But I wanted to showcase a more realistic implementation.</p>
<h3 id="heading-util-function-for-fetch">Util function for <code>fetch</code></h3>
<p>Before getting into the composable, we need to set up a util function for the <code>fetch</code> API. This is because we want to make sure every request throws an error if it fails. The <code>fetch</code> API doesn’t throw an error if the request responds with an error status. We have to check the <code>response.ok</code> in order to verify the status, and then throw an error if necessary.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// utils.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleFetch</span>(<span class="hljs-params">url: <span class="hljs-built_in">string</span>, options: RequestInit = {}</span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">Response</span>&gt; </span>{
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(url, options)
  <span class="hljs-keyword">if</span> (!res.ok) {
    <span class="hljs-keyword">const</span> err = <span class="hljs-keyword">await</span> res.text()
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(err)
  }
  <span class="hljs-keyword">return</span> res
}
</code></pre>
<h3 id="heading-useasyncstate-composable">useAsyncState Composable</h3>
<p>When working with async state, the requests can be in a few different states:</p>
<ul>
<li><p>Pending</p>
</li>
<li><p>Resolved</p>
</li>
<li><p>Rejected</p>
</li>
</ul>
<p>In addition to these states, we want to track the data or the error that comes back from the request.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// useAsyncState.ts</span>
<span class="hljs-keyword">import</span> { shallowRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { Ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>

<span class="hljs-comment">// Specify a type for the response</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> AsyncState&lt;T&gt; = {
  data: Ref&lt;T | <span class="hljs-literal">null</span>&gt;
  error: Ref&lt;<span class="hljs-built_in">Error</span> | <span class="hljs-literal">null</span>&gt;
  isPending: Ref&lt;<span class="hljs-built_in">boolean</span>&gt;
  isResolved: Ref&lt;<span class="hljs-built_in">boolean</span>&gt;
  isRejected: Ref&lt;<span class="hljs-built_in">boolean</span>&gt;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useAsyncState</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">promise: <span class="hljs-built_in">Promise</span>&lt;T&gt;</span>): <span class="hljs-title">AsyncState</span>&lt;<span class="hljs-title">T</span>&gt; </span>{
  <span class="hljs-comment">// I used shallowRef instead of ref to avoid deep reactivity</span>
  <span class="hljs-comment">// I only care about the top-level properties being reactive</span>
  <span class="hljs-keyword">const</span> data = shallowRef&lt;T | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>)
  <span class="hljs-keyword">const</span> error = shallowRef&lt;<span class="hljs-built_in">Error</span> | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>)
  <span class="hljs-keyword">const</span> isPending = shallowRef(<span class="hljs-literal">false</span>)
  <span class="hljs-keyword">const</span> isResolved = shallowRef(<span class="hljs-literal">false</span>)
  <span class="hljs-keyword">const</span> isRejected = shallowRef(<span class="hljs-literal">false</span>)

  data.value = <span class="hljs-literal">null</span>
  error.value = <span class="hljs-literal">null</span>
  isPending.value = <span class="hljs-literal">true</span>
  isRejected.value = <span class="hljs-literal">false</span>
  isResolved.value = <span class="hljs-literal">false</span>

  promise.then(<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
    data.value = result
    isPending.value = <span class="hljs-literal">false</span>
    isResolved.value = <span class="hljs-literal">true</span>
  }).catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
    error.value = err
    isPending.value = <span class="hljs-literal">false</span>
    isRejected.value = <span class="hljs-literal">true</span>
  })

  <span class="hljs-keyword">return</span> { data, error, isPending, isResolved, isRejected }
}
</code></pre>
<p>This gives a few more explicit properties for the different states, rather than relying on the values in <code>data</code> and <code>error</code>. You’ll also notice that this composable takes in a promise rather than a URL string like the docs show. Different endpoints will have different response types and I wanted to be able to handle those outside of this composable.</p>
<h3 id="heading-usage-in-a-component">Usage in a component</h3>
<p>I have set up an endpoint that will wait a random number of seconds before responding either successfully or with an error. My component is calling this endpoint using the composable and using the data from the composable to update the template.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748364641116/304b8c08-5277-4243-b621-70a7c19edcfd.gif" alt="304b8c08-5277-4243-b621-70a7c19edcfd" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>With the error state showing like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748364674070/7d0c6923-85b9-4971-8f69-d127ffa6c1f4.png" alt="7d0c6923-85b9-4971-8f69-d127ffa6c1f4" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You can see a working example at <a target="_blank" href="https://understanding-composables.pages.dev/">https://understanding-composables.pages.dev/</a>.</p>
<p>To make this a bit easier to explain and understand, I am breaking up the <code>&lt;script&gt;</code> tag and the <code>&lt;template&gt;</code> sections of the component.</p>
<h4 id="heading-script">Script</h4>
<pre><code class="lang-typescript">&lt;script lang=<span class="hljs-string">"ts"</span> setup&gt;
<span class="hljs-keyword">import</span> { ref, unref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { Ref } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>
<span class="hljs-keyword">import</span> { useAsyncState } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/composables'</span>
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { AsyncState } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/composables'</span>
<span class="hljs-keyword">import</span> { handleFetch } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/utils'</span>

<span class="hljs-keyword">interface</span> RandomResponse {
  msg: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getRandomResponse</span>(<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">RandomResponse</span>&gt; </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> handleFetch(<span class="hljs-string">'https://briancbarrow.com/api/random'</span>)
  <span class="hljs-keyword">const</span> text = <span class="hljs-keyword">await</span> response.text()
  <span class="hljs-keyword">return</span> { msg: text }
}

<span class="hljs-keyword">const</span> randomResponseData: Ref&lt;AsyncState&lt;RandomResponse&gt; | <span class="hljs-literal">null</span>&gt; = ref(<span class="hljs-literal">null</span>)

<span class="hljs-keyword">const</span> handleMakeRequest = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> data = getRandomResponse()
    randomResponseData.value = useAsyncState(data)
}
&lt;/script&gt;
</code></pre>
<p>Here we have a method, <code>getRandomResponse</code> that calls an endpoint and returns a promise. That promise is then passed into the <code>useAsyncState</code> when <code>handleMakeRequest</code> is called. That puts the full return value into the <code>randomResponseData</code> ref which we can then use inside the template.</p>
<p>Rather than show the full template, I will just show a few portions of it.</p>
<p>Here you can see two different buttons being used depending on the state. I am using a separate button element to indicate the “loading” state, but in practice you can use the composable properties to set the <code>disabled</code> property of the button and change the text.</p>
<pre><code class="lang-xml">        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">v-if</span>=<span class="hljs-string">"
            !randomResponseData?.isPending &amp;&amp;
            !randomResponseData?.error &amp;&amp;
            !randomResponseData?.data
          "</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"</span>
          @<span class="hljs-attr">click</span>=<span class="hljs-string">"handleMakeRequest"</span>
        &gt;</span>
          Make Request
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- Loading State Button --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">v-if</span>=<span class="hljs-string">"randomResponseData?.isPending"</span>
          <span class="hljs-attr">disabled</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"px-6 py-3 bg-blue-600 text-white font-medium rounded-lg opacity-75 cursor-not-allowed flex items-center mx-auto"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
            <span class="hljs-attr">class</span>=<span class="hljs-string">"animate-spin -ml-1 mr-3 h-5 w-5 text-white"</span>
            <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
            <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>
            <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 24 24"</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">circle</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"opacity-25"</span>
              <span class="hljs-attr">cx</span>=<span class="hljs-string">"12"</span>
              <span class="hljs-attr">cy</span>=<span class="hljs-string">"12"</span>
              <span class="hljs-attr">r</span>=<span class="hljs-string">"10"</span>
              <span class="hljs-attr">stroke</span>=<span class="hljs-string">"currentColor"</span>
              <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"4"</span>
            &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">circle</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"opacity-75"</span>
              <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentColor"</span>
              <span class="hljs-attr">d</span>=<span class="hljs-string">"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"</span>
            &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">path</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
          Loading...
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>Here are a couple of the rows from the table:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"divide-x divide-gray-200"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"py-4 pr-4 pl-4 text-sm font-medium whitespace-nowrap text-gray-900 sm:pl-0"</span>&gt;</span>
    isPending
  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span>
    <span class="hljs-attr">class</span>=<span class="hljs-string">"p-4 text-sm whitespace-nowrap text-gray-500"</span>
    <span class="hljs-attr">:class</span>=<span class="hljs-string">"randomResponseData?.isPending ? 'bg-blue-500' : 'bg-gray-300'"</span>
  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-4 text-sm whitespace-nowrap text-gray-500"</span>&gt;</span>
    {{ randomResponseData?.isPending }}
  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"divide-x divide-gray-200"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"py-4 pr-4 pl-4 text-sm font-medium whitespace-nowrap text-gray-900 sm:pl-0"</span>&gt;</span>
    data
  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span>
    <span class="hljs-attr">class</span>=<span class="hljs-string">"p-4 text-sm whitespace-nowrap text-gray-500"</span>
    <span class="hljs-attr">:class</span>=<span class="hljs-string">"randomResponseData?.data ? 'bg-green-500' : 'bg-gray-300'"</span>
  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-4 text-sm whitespace-nowrap text-gray-500"</span>&gt;</span>
    {{ unref(randomResponseData?.data)?.msg }}
  <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
</code></pre>
<p>In those <code>tr</code> tags, you can see the template rendering different things depending on the state coming from the composable.</p>
<p>For a more complete look at the code, you can visit <a target="_blank" href="https://github.com/briancbarrow/understanding-composables">the GitHub repo</a>. You can also look at how VueUse, a collection of composables, handles similar functionality: <a target="_blank" href="https://vueuse.org/core/useAsyncState/">https://vueuse.org/core/useAsyncState/</a></p>
<p>In a future article, I’ll dive into their implementation.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Composables are an incredibly useful tool in Vue 3. As projects grow in size and scope, knowing how and when to use composables can improve the maintainability of the project over the long term.</p>
<p>The key is identifying when you have stateful logic that needs to be reused across components, then extracting it into a well-structured composable that handles edge cases properly.</p>
<p>For more real world examples you can check out the <a target="_blank" href="https://vueuse.org/">VueUse library</a> and <a target="_blank" href="https://github.com/vueuse/vueuse">repo</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Vue E-commerce App Using MSW ]]>
                </title>
                <description>
                    <![CDATA[ Building an e-commerce app can be a time-consuming task, but with the right tools, it becomes much more manageable. In this guide, we'll explore how to create a robust Vue.js e-commerce application using Mock Service Worker (MSW) to simulate backend ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-vue-ecommerce-app-using-msw/</link>
                <guid isPermaLink="false">66bb55013c8a48be917afce0</guid>
                
                    <category>
                        <![CDATA[ ecommerce ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abhijeet Dave ]]>
                </dc:creator>
                <pubDate>Mon, 08 Jul 2024 18:49:45 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/build-a-Vue-eCommerce-App-using-MSW.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Building an e-commerce app can be a time-consuming task, but with the right tools, it becomes much more manageable. In this guide, we'll explore how to create a robust Vue.js e-commerce application using Mock Service Worker (MSW) to simulate backend interactions. </p>
<p>Whether you're a seasoned developer or just starting out, this step-by-step tutorial will help you understand the fundamentals of integrating MSW into your Vue project, enabling you to build and test your application more effectively without relying on a real backend. </p>
<p>Let's dive in and bring your e-commerce vision to life!</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#what-is-a-mock-server">What is a Mock Server?</a></li>
<li><a href="#how-to-set-up-a-vue-e-commerce-app">How to Set Up a Vue E-commerce App</a></li>
<li><a href="#getting-started-with-vue-e-commerce-app">Getting Started With Vue E-commerce App</a></li>
<li><a href="#how-to-build-an-e-commerce-app-using-vue-3">How to Build an E-commerce App Using Vue 3</a></li>
<li><a href="#how-to-build-the-user-interface">How to Build the User Interface</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>

<p>In this article, we'll walk through the process of building an e-commerce app from scratch using <a target="_blank" href="https://vuejs.org/">Vue.js</a> and the power of MSW for mocking API calls.</p>
<p>Before we start with the project, let’s take an overview of the e-commerce pages that we are going to build for the app. It'll have mainly two pages:</p>
<ul>
<li>Shop page.</li>
<li>Product details page.</li>
</ul>
<p><strong>Shop page</strong>: This page will display all the products of the store.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/eCommerce-Products-Page.png" alt="Image" width="600" height="400" loading="lazy">
<em>Mock-up created using Pika Style</em></p>
<p><strong>Product details page</strong>: This page displays all the details regarding the product.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/eCommerce-product-details-page.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Before building an e-commerce app, let’s clarify some basics about the mock server.</p>
<h2 id="heading-what-is-a-mock-server">What is a Mock Server?</h2>
<p>A mock server simply mimics a real server by providing predefined responses for an API request. A mock server is useful for testing and development as it can generate different test cases without risking the integrity of real data. You can configure a mock server to return specific responses, error messages and timeouts.</p>
<p>There are various tools/libraries out there that you can use to set up a mock server. In this article, we will use MSW (Mock Service Worker) to set up a mock server. You can learn more about MSW from its official <a target="_blank" href="https://mswjs.io/">documentation</a>.</p>
<p>Now, let’s set up a mock server (using MSW) for our Vue e-commerce app.</p>
<h2 id="heading-how-to-set-up-a-vue-e-commerce-app">How to Set Up a Vue E-commerce App</h2>
<p>For our e-commerce app, we'll need two API endpoints. Below is a brief description of API endpoints.</p>
<ol>
<li><code>/api/apps/ecommerce/products</code>: This will fetch the data of all products we have in store.</li>
<li><code>/api/apps/ecommerce/product/:id</code>: This will fetch the product details of a specific product by its ID.</li>
</ol>
<p>We'll use a free Vue admin dashboard that offers essential features such as:</p>
<ul>
<li>Beautifully crafted components</li>
<li>Auto import capabilities</li>
<li>Premade layout, and so on.</li>
</ul>
<p>These features will make it easier and faster to develop the Vue e-commerce app.</p>
<h2 id="heading-getting-started-with-vue-e-commerce-app">Getting Started With Vue E-commerce App</h2>
<p>There are plenty of <a target="_blank" href="https://vuejs.org/ecosystem/themes">Vue.js themes</a> available that you can consider for creating an e-commerce  app. </p>
<p>Here, we'll use the Materio Vue.js admin free template<em>.</em> First, go to the <a target="_blank" href="https://github.com/themeselection/materio-vuetify-vuejs-admin-template-free">GitHub repo</a>.</p>
<p>To clone it, simply open your terminal. Navigate to the directory where you would like to clone the project and run the following command:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> &lt;https://github.com/themeselection/materio-vuetify-vuejs-admin-template-free.git&gt;
</code></pre>
<p>Open the project in your favorite IDE and run the command below in the terminal to install all the dependencies. </p>
<p>We'll use the <a target="_blank" href="https://pnpm.io/"><code>pnpm</code></a> package manager as recommended by the dashboard we're using. However, you are free to use your preferred package manager like npm or yarn.</p>
<pre><code class="lang-bash">pnpm install
<span class="hljs-comment"># npm install</span>
<span class="hljs-comment"># yarn</span>
</code></pre>
<p>Next, install MSW in your project directory:</p>
<pre><code class="lang-bash">pnpm add -D msw@latest
<span class="hljs-comment"># npm install msw@latest --save-dev</span>
<span class="hljs-comment"># yarn install -D msw@latest</span>
</code></pre>
<p>Run the theme using the following command:</p>
<pre><code class="lang-bash">pnpm run dev
<span class="hljs-comment"># npm run dev</span>
<span class="hljs-comment"># yarn run dev</span>
</code></pre>
<p>Next, initialize MSW using the command below. Running this command will create a <strong>mockServiceWorker.js</strong> file in a public directory.</p>
<pre><code class="lang-bash">npx msw init public
</code></pre>
<p>To manage all API endpoints and fake data, create a new folder called <strong>fake-server</strong> inside the <strong>plugins</strong> directory. We’ll set up our mock server in this <strong>fake-server</strong> directory. Create an <strong>index.ts</strong> file and paste the below code to register <code>MSW</code>.</p>
<pre><code class="lang-tsx">// file: src/plugins/fake-server/index.ts

import { setupWorker } from 'msw/browser'

const worker = setupWorker()

export default function () {
  const workerUrl = `${import.meta.env.BASE_URL ?? '/'}mockServiceWorker.js`

  worker.start({
    serviceWorker: {
      url: workerUrl,
    },
    onUnhandledRequest: 'bypass',
  })
}
</code></pre>
<p>Congratulations, you have now successfully set up <code>MSW</code> in the project. Now, we can start building an e-commerce app.</p>
<h2 id="heading-how-to-build-an-e-commerce-app-using-vue-3">How to Build an E-commerce App Using Vue 3</h2>
<p>In the <strong>fake-server</strong> directory, create a <strong>handlers</strong> directory for maintaining handlers. Inside the <strong>handlers</strong> directory, create an <strong>ecommerce</strong> directory for the e-commerce app’s handlers. Then, create a <strong>db.ts</strong> file inside <strong>ecommerce</strong> to store the fake data.</p>
<p>Your folder structure should look like this:</p>
<pre><code class="lang-tsx">.
└── fake-server/
    └── handlers/
        └── ecommerce/
            └── db.ts
</code></pre>
<p>I have generated some fake data for displaying products. Let’s place this fake data in <strong>db.ts</strong>:</p>
<pre><code class="lang-tsx">// file: src/plugins/fake-server/handlers/ecommerce/db.ts

import product5 from '@images/eCommerce/1.png'
import product3 from '@images/eCommerce/11.png'
import product6 from '@images/eCommerce/18.png'
import product1 from '@images/eCommerce/27.png'
import product4 from '@images/eCommerce/5.png'
import product2 from '@images/eCommerce/7.png'

export const db = {
  products: [
    {
      id: 1,
      productName: 'Gaming Mouse',
      category: 'Electronics',
      price: '$999',
      image: product1,
      rating: 5,
      productDescription: 'A mouse specifically designed for gamers.',
    },
    {
      id: 2,
      productName: 'Google Home',
      category: 'Electronics',
      price: '$25.50',
      image: product2,
      rating: 4,
      productDescription: 'A Smart speaker with Google Assistant.',
    },
    {
      id: 3,
      productName: 'INZCOU Running Shoes',
      category: 'Shoes',
      price: '$36.98',
      image: product3,
      rating: 5,
      productDescription: 'Lightweight Tennis Shoes Non Slip Gym Workout Shoes',
    },
    {
      id: 4,
      productName: 'MacBook Pro 16',
      category: 'Electronics',
      price: '$2648.95',
      image: product4,
      rating: 5,
      productDescription: 'Laptop M2 Pro chip with 12‑core CPU and 19‑core GPU',
    },
    {
      id: 5,
      productName: 'Apple Watch Series 7',
      category: 'Office',
      price: '$799',
      image: product5,
      rating: 5,
      productDescription: 'Starlight Aluminum Case with Starlight Sport Band.',
    },
    {
      id: 6,
      productName: 'Meta Quest 2',
      category: 'Office',
      price: '$299',
      image: product6,
      rating: 5,
      productDescription: 'Advanced All-In-One Virtual Reality Headset',
    },
  ],
}
</code></pre>
<p>As discussed in this app structure, we need to define two endpoints. Create an <strong>index.ts</strong> file in your e-commerce handler and define your endpoints in it:</p>
<pre><code class="lang-tsx">// file: src/plugins/fake-server/handlers/ecommerce/index.ts

import { HttpResponse, http } from 'msw'
import { db } from './db'

export const handlerEcommerce = [
  http.get('/api/ecommerce/products', () =&gt; {
    const products = db.products

    return HttpResponse.json(products, { status: 200 })
  }),

  http.get('/api/ecommerce/products/:id', ({ params }) =&gt; {
    const id = Number(params.id)

    const product = db.products.find(item =&gt; item.id === id)

    if (!product)
      return HttpResponse.error()

    return HttpResponse.json(product, { status: 200 })
  }),
]
</code></pre>
<p>Register the handler in the <strong>index.ts</strong> file in the <strong>fake-server</strong> direrctory. The updated <strong>index.ts</strong> file should look like this:</p>
<pre><code class="lang-tsx">// file: src/plugins/fake-server/index.ts

import { setupWorker } from 'msw/browser'

import { handlerEcommerce } from './handlers/ecommerce'

const worker = setupWorker(...handlerEcommerce)

export default function () {
  const workerUrl = `${import.meta.env.BASE_URL ?? '/'}mockServiceWorker.js`

  worker.start({
    serviceWorker: {
      url: workerUrl,
    },
    onUnhandledRequest: 'bypass',
  })
}
</code></pre>
<p>The setup of the mock server has been completed. Whenever you make an API call to your endpoint, MSW will intercept the HTTP request using the service worker and will provide a predefined response from the handlers.</p>
<p>Congratulations, you have successfully set up the mock server👍.🏻</p>
<h2 id="heading-how-to-build-the-user-interface">How to Build the User Interface</h2>
<p>Let's move on to the UI part of the e-commerce app. Create an <strong>apps</strong> directory in the <strong>pages</strong> directory. Inside <strong>apps</strong>, create a new directory called <strong>ecommerce</strong>. We'll place the e-commerce app in this directory.</p>
<p>The folder structure should look like this:</p>
<pre><code class="lang-tsx">.
└── pages/
    └── apps/
        └── ecommerce
</code></pre>
<p>The first page is a product listing page. Create a new directory of <strong>products</strong> inside <strong>ecommerce</strong>. Create an <strong>index.vue</strong> file in the <strong>products</strong> directory and paste the following code snippet:</p>
<pre><code class="lang-tsx">// file: src/pages/apps/ecommerce/products/index.vue

&lt;script setup lang="ts"&gt;
const router = useRouter()
const { data: products } = await useFetch('/api/ecommerce/products').json()
&lt;/script&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;div class="d-flex flex-wrap gap-6 justify-center"&gt;
      &lt;template
        v-for="(product, index) in products"
        :key="index"
      &gt;
        &lt;VCard width="300"&gt;
          &lt;VImg
            :src="product.image"
            cover
          /&gt;
          &lt;VCardItem&gt;
            &lt;VCardTitle&gt;{{ product.productName }}&lt;/VCardTitle&gt;
            &lt;VCardSubtitle&gt;Price: {{ product.price }}&lt;/VCardSubtitle&gt;
          &lt;/VCardItem&gt;
          &lt;VCardText&gt;
            &lt;p class="mb-0"&gt;
              {{ product.productDescription }}
            &lt;/p&gt;
            &lt;VRating
              :model-value="product.rating"
              readonly
              density="compact"
              class="my-3"
            /&gt;
            &lt;VBtn
              block
              @click="() =&gt; router.push({ path: `/apps/ecommerce/products/${product.id}` })"
            &gt;
              Buy Now
            &lt;/VBtn&gt;
          &lt;/VCardText&gt;
        &lt;/VCard&gt;
      &lt;/template&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre>
<p>In this product listing page, we made an API call to the <code>'/api/ecommerce/products'</code> endpoint. This endpoint returns the array of all products. We'll use this data to display products on the page.</p>
<p>The second page in this app is the product display page. On this page, we'll display all the details of the product. To do so, create a new file <strong>[id].vue</strong> inside the <strong>products</strong> directory. Below is the code for the product details page.</p>
<p>Note that I have used Lorem ipsum to keep it generic. You can replace it with your desired description. </p>
<pre><code class="lang-tsx">// file: src/pages/apps/ecommerce/products/[id].vue

&lt;script setup lang="ts"&gt;
const route = useRoute()
const router = useRouter()

const { data: product } = await useFetch(`/api/ecommerce/products/${route.params.id}`).json()
const quantity = ref(0)
&lt;/script&gt;

&lt;template&gt;
  &lt;VCard class="pa-10"&gt;
    &lt;VRow&gt;
      &lt;VCol
        md="4"
        cols="12"
      &gt;
        &lt;div class="py-10 bg-background d-flex justify-center"&gt;
          &lt;VImg
            :src="product.image"
            width="auto"
            max-height="40vh"
          /&gt;
        &lt;/div&gt;
      &lt;/VCol&gt;

      &lt;VCol
        md="8"
        cols="12"
      &gt;
        &lt;div&gt;
          &lt;div class="text-h3 mb-4"&gt;
            {{ product.productName }}
          &lt;/div&gt;

          &lt;div class="text-h4 mb-4"&gt;
            {{ product.price }}
          &lt;/div&gt;

          &lt;div&gt;
            &lt;p&gt;
              {{ product.productDescription }}
              Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolor eum quam dolore ratione aspernatur nobis. Assumenda dicta voluptatibus reiciendis repudiandae?
            &lt;/p&gt;
            &lt;VRating
              :model-value="product.rating"
              readonly
              density="compact"
              class="mb-2 d-block"
            /&gt;

            &lt;VList&gt;
              &lt;VListItem&gt;
                &lt;template #prepend&gt;
                  &lt;VIcon
                    icon="ri-circle-fill"
                    size="10"
                  /&gt;
                &lt;/template&gt;
                Lorem ipsum, dolor sit amet consectetur adipisicing elit. Culpa, deserunt!
              &lt;/VListItem&gt;
              &lt;VListItem&gt;
                &lt;template #prepend&gt;
                  &lt;VIcon
                    icon="ri-circle-fill"
                    size="10"
                  /&gt;
                &lt;/template&gt;
                Lorem ipsum, dolor sit amet consectetur adipisicing elit. Culpa, deserunt!
              &lt;/VListItem&gt;
              &lt;VListItem&gt;
                &lt;template #prepend&gt;
                  &lt;VIcon
                    icon="ri-circle-fill"
                    size="10"
                  /&gt;
                &lt;/template&gt;
                Lorem ipsum, dolor sit amet consectetur adipisicing elit. Culpa, deserunt!
              &lt;/VListItem&gt;
              &lt;VListItem&gt;
                &lt;template #prepend&gt;
                  &lt;VIcon
                    icon="ri-circle-fill"
                    size="10"
                  /&gt;
                &lt;/template&gt;
                Lorem ipsum, dolor sit amet consectetur adipisicing elit. Culpa, deserunt!
              &lt;/VListItem&gt;
            &lt;/VList&gt;

            &lt;VBtn
              prepend-icon="ri-shopping-cart-line"
              class="text-center"
              size="large"
              @click="quantity += 1"
            &gt;
              Add to Cart
            &lt;/VBtn&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/VCol&gt;
    &lt;/VRow&gt;
  &lt;/VCard&gt;
  &lt;div class="text-center"&gt;
    &lt;VBtn
      class="my-6 text-center"
      @click="() =&gt; router.push({ path: '/apps/ecommerce/products' })"
    &gt;
      Continue Shopping
    &lt;/VBtn&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre>
<p>On this page, we made an API request to our second API endpoint: <code>/api/ecommerce/products/:id</code>. This endpoint returns product details related to a given product ID. We will use this data on our page to display product details.</p>
<p>Let’s add routes for the e-commerce app. All the routes are located in the <strong>src/plugins/router/routes.ts</strong> file. In the file, add the e-commerce app’s routes.</p>
<pre><code class="lang-tsx">// file: src/plugins/router/routes.ts
{
  path: '/apps/ecommerce/products',
  component: () =&gt; import('@/pages/apps/ecommerce/products/index.vue'),
},
{
  name: 'apps-ecommerce-products-id',
  path: '/apps/ecommerce/products/:id',
  component: () =&gt; import('@/pages/apps/ecommerce/products/[id].vue'),
},
</code></pre>
<p>Now, let’s add an e-commerce app to our navigation menu. We'll list all our menu items and groups in <code>NavItems.vue</code> components. We'll use a <code>VerticalNavGroup</code> component for adding a nav group and a <code>VerticleNavLink</code> component for adding a nav item. For adding an e-commerce app in the navigation menu, add the code below in the <code>Apps &amp; Pages</code> section.</p>
<pre><code class="lang-tsx">//file: src/layouts/components/NavItems.vue

&lt;VerticalNavGroup
    :item="{
      title: 'e-commerce',
      icon: 'ri-shopping-cart-line',
    }"
  &gt;
    &lt;VerticalNavLink
      :item="{
        title: 'Shop',
        to: '/apps/ecommerce/products',
      }"
    /&gt;
    &lt;VerticalNavLink
      :item="{
        title: 'Product',
        to: { name: 'apps-ecommerce-products-id', params: { id: 1 } },
      }"
    /&gt;
&lt;/VerticalNavGroup&gt;
</code></pre>
<p>Congrats, you’ve built a Vue e-commerce app using Vue.js and MSW. You can visit the dev server to see the e-commerce app we just crafted.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you built an e-commerce app using Vue.js and MSW to mock API calls. We created two main pages: the shop page to display products and the product details page to show product information.</p>
<p>The mock server setup helped us to create a realistic development environment without building an actual backend. At the end of this guide, you had a working e-commerce app prototype. This setup provides a strong foundation for further customization and development.</p>
<p>For the complete implementation of the e-commerce app built in this article, please refer to this GitHub repository: <a target="_blank" href="https://github.com/themeselection/e-commerce-app">https://github.com/themeselection/e-commerce-app</a>.</p>
<p>I hope you all find this article helpful. In case you want to develop a full-fledged e-commerce app, you can use the pre-built <a target="_blank" href="https://themeselection.com/item/category/vuejs-admin-templates/">Vuejs admin template</a> as it offers many components and features that can be helpful in creating a professional e-commerce app.</p>
<p>I have prepared this article with help of <a target="_blank" href="https://x.com/me_jd_solanki">Jayendrasinh Solanki</a>. He is an expert in VueJS with over 7 years of experience. BTW, he is followed by Vue creator Evan You! Isn't it great?</p>
<h3 id="heading-some-helpful-guides-for-e-commerce-product-development">Some helpful guides for e-commerce product development:</h3>
<ul>
<li><a target="_blank" href="https://www.freecodecamp.org/news/develop-a-reusable-ecommerce-platform/">How to Develop a Reusable eCommerce Platform (freecodecamp.org)</a>.</li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-to-create-an-ecommere-website-using-woocomerce/">How to Create an eCommerce Website Using WooCommerce (freecodecamp.org)</a>.</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Front End JavaScript Development Handbook – React, Angular, and Vue Compared ]]>
                </title>
                <description>
                    <![CDATA[ Frontend frameworks are indispensable in web development. They provide structured approaches and pre-defined components to streamline the coding process. These tools can also help boost productivity by offering reusable components and abstracting com... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/front-end-javascript-development-react-angular-vue-compared/</link>
                <guid isPermaLink="false">66d45d5c3a8352b6c5a2a9f5</guid>
                
                    <category>
                        <![CDATA[ Angular ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Front-end Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Adekola Olawale ]]>
                </dc:creator>
                <pubDate>Thu, 08 Jun 2023 13:57:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/frontend-framework-cover.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Frontend frameworks are indispensable in web development. They provide structured approaches and pre-defined components to streamline the coding process.</p>
<p>These tools can also help boost productivity by offering reusable components and abstracting complex tasks like DOM manipulation and state management. This allows developers to focus on application logic rather than writing repetitive code.</p>
<p>Frameworks promote code maintainability through modular development, making it easier to modify or replace individual components. They also make collaboration easier as multiple developers can work simultaneously on different parts of an application.</p>
<h3 id="heading-benefits-of-using-libraries-and-frameworks">Benefits of Using Libraries and Frameworks</h3>
<p>With vibrant developer communities, these frameworks offer extensive support, tutorials, and documentation. Leveraging frontend frameworks empowers developers to create beautiful and highly functional web applications that meet modern user expectations.</p>
<p>Frontend frameworks provide numerous benefits for beginners in web development as well. They offer a structured approach and pre-built components, simplifying the development process and saving time.</p>
<p>Beginners can leverage the power of these frameworks to create visually appealing and interactive user interfaces without needing to start from scratch.</p>
<p>The extensive community support and resources available for popular tools like React, Angular, and Vue make it easier for beginners to learn and grow their skills. By embracing frontend frameworks, beginners can accelerate their learning curve, and build impressive web applications.</p>
<h3 id="heading-learn-vanilla-javascript-first">Learn Vanilla JavaScript First</h3>
<p>Before delving into JavaScript frameworks, it is crucial for you to grasp the basics of plain JavaScript. Understanding the fundamentals of JavaScript, such as variables, functions, and control structures lays a strong foundation for learning and utilizing frameworks effectively.</p>
<p>By learning the core concepts of JavaScript, you also gain insights into how the language works and can solve problems without relying solely on the abstractions provided by frameworks. This knowledge empowers you to write cleaner, more efficient code and arms you with the ability to customize and extend frameworks to suit their specific needs.</p>
<p>Understanding JavaScript also enables you to troubleshoot issues, comprehend error messages, and make informed decisions when working with frameworks. By mastering the basics, you can unlock the full potential of JavaScript frameworks and leverage their power to create dynamic, interactive web applications.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-react">What is React</a>?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-angular">What is Angular</a>?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-vuejs">What is Vue.js</a>?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-comparing-javascript-frameworks">Comparing JavaScript Frameworks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-choose-the-right-framework-for-your-project">How to Choose the Right Framework for Your Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#resources-for-learning-js-frameworks-and-getting-started">Resources for Learning JS Frameworks and Getting Started</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-react">What is React?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/React-Logo-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>React Logo</em></p>
<p>React is a popular JavaScript library used for building user interfaces. It follows a component-based architecture, where UI elements are divided into reusable components.</p>
<p>React utilizes a Virtual DOM, which is a lightweight representation of the actual DOM, to efficiently update and render components. This approach allows for fast and responsive user interfaces.</p>
<p>React promotes a one-way data flow, making it easier to manage application state and update UI components efficiently. It provides lifecycle methods that allow developers to perform actions at different stages of a component's lifecycle, such as fetching data, handling events, and updating the UI accordingly.</p>
<p>It has a robust ecosystem with various libraries and tools that extend its capabilities. These include React Router for routing, Redux for state management, and React Native for building native mobile applications. This ecosystem offers solutions to common development challenges and facilitates rapid development.</p>
<p>React's component-based architecture, Virtual DOM, JSX syntax, and extensive ecosystem make it a powerful choice for building dynamic and reusable user interfaces. Understanding the basics of React sets the foundation for exploring its features and capabilities in more depth.</p>
<h3 id="heading-react-setup-installation-project-creation-and-server-start">React Setup: Installation, Project Creation, and Server Start</h3>
<p>To get started with React, you need to set up your development environment by installing React, creating a new project, and starting the development server.</p>
<p>Below outlines the steps to install React, create a new React project, and start the development server:</p>
<p><strong>Step 1:</strong> Install Node.js and npm (if not already installed)</p>
<p><strong>Step 2:</strong> Open your terminal or command prompt.</p>
<p><strong>Step 3:</strong> Install the Create React App CLI globally by running the following command:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/install-react-app.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Install React App</em></p>
<pre><code class="lang-bash">npm install -g create-react-app
</code></pre>
<p><strong>Step 4:</strong> Create a new React project by running the following command:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/create-react-project.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Create React app project</em></p>
<pre><code class="lang-bash">npx create-react-app my-react-app
</code></pre>
<p><em>Note:</em> Replace <code>my-react-app</code> with the desired name of your project.</p>
<p><strong>Step 5:</strong> Once the project is created, navigate to the project directory by running the following command:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/cd-react-app.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Change Directory</em></p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-react-app
</code></pre>
<p><strong>Step 6:</strong> Start the development server by running the following command:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/react-npm-start.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Starting React Development Server</em></p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>This will start the development server, and you can view your React app by visiting <a target="_blank" href="http://localhost:3000">http://localhost:3000</a> in your browser.</p>
<p>These steps will install React, create a new React project with Create React App, and start the development server. You can then begin building your React application.</p>
<h3 id="heading-react-and-its-key-features">React and its Key Features</h3>
<p>React's many features make it one of the most popular choices among developers. Its range of powerful features empowers developers to build dynamic and interactive user interfaces in a flexible and efficient way.</p>
<h4 id="heading-component-based-architecture">Component-Based Architecture</h4>
<p>React follows a component-based approach, where UI elements are broken down into reusable and self-contained components. This modularity promotes code reusability, maintainability, and scalability.</p>
<p>In React, the component-based architecture is a fundamental concept that promotes code reusability and modular development. Components are the building blocks of a React application, and they can be thought of as self-contained, reusable pieces of code that encapsulate both the UI (User Interface) and the logic.</p>
<p>Check out this snippet of code that exemplifies the creation of a simple functional component in React:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Greeting</span>(<span class="hljs-params">props</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello, {props.name}!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Greeting;
</code></pre>
<p>In the code snippet above, we define a functional component called <code>Greeting</code>. This component takes in a prop called <code>name</code> and renders a greeting message with the value of the <code>name</code> prop.</p>
<p>The component-based architecture allows you to break down your application into smaller, reusable components. Each component can have its own state, props, and lifecycle methods, making it easier to manage and maintain your codebase. Components can be composed and nested together to create complex user interfaces.</p>
<p>By separating your application into components, you can achieve better organization, code reusability, and maintainability. You can easily reuse components across different parts of your application or even in different projects. This approach also enables a more efficient development workflow, as components can be developed and tested independently.</p>
<p>With the component-based architecture in React, you have the flexibility to build modular, scalable, and maintainable applications, making React a powerful tool for front-end development.</p>
<h4 id="heading-virtual-dom">Virtual DOM</h4>
<p>React utilizes a Virtual DOM, which is a lightweight representation of the actual DOM. By using the Virtual DOM, React efficiently updates and renders components, resulting in faster and smoother user interfaces.</p>
<p>One of the key features of React is its use of a Virtual DOM (Document Object Model). The Virtual DOM is a lightweight representation of the actual DOM, a tree-like structure that represents the HTML elements of a web page. It acts as an intermediary layer between the application's logic and the browser's rendering engine.</p>
<p>Dive into this code example to understand how the Virtual DOM works in React:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  <span class="hljs-keyword">constructor</span>(props) {
    <span class="hljs-built_in">super</span>(props);
    <span class="hljs-built_in">this</span>.state = {
      <span class="hljs-attr">count</span>: <span class="hljs-number">0</span>,
    };
  }

  handleClick() {
    <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">count</span>: <span class="hljs-built_in">this</span>.state.count + <span class="hljs-number">1</span> });
  }

  render() {
    <span class="hljs-keyword">return</span> (
      <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">h1</span>&gt;</span>Count: {this.state.count}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> this.handleClick()}&gt;Increment<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>
    );
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Counter;
</code></pre>
<p>In the code snippet above, we have a <code>Counter</code> component that displays a count value and a button to increment the count. Whenever the button is clicked, the <code>handleClick</code> function updates the component's state using <code>setState</code>, triggering a re-render of the component.</p>
<p>Behind the scenes, React creates a Virtual DOM representation of the component's UI structure. When a state change occurs, React efficiently calculates the difference between the previous Virtual DOM and the updated Virtual DOM. This process is known as reconciliation.</p>
<p>React then applies the necessary changes to the actual DOM, updating only the specific parts that have changed. This approach helps optimize performance by minimizing DOM manipulations and updates.</p>
<p>By using the Virtual DOM, React provides a more efficient way of updating the user interface. It reduces the number of direct manipulations on the actual DOM, resulting in faster rendering and improved application performance.</p>
<p>The Virtual DOM also enables a declarative programming model, where developers specify how the UI should look based on the application's state, and React takes care of updating the actual DOM accordingly.</p>
<h4 id="heading-jsx-syntax">JSX Syntax</h4>
<p>React introduced JSX, a syntax extension that combines JavaScript and XML-like syntax. It allows developers to write HTML-like code within JavaScript, making component templates more intuitive and readable.</p>
<p>JSX (JavaScript XML) is an important feature of React that allows developers to write HTML-like syntax directly within JavaScript code. It provides a concise and expressive way to define the structure and appearance of React components.</p>
<p>Let's explore a practical code snippet that demonstrates the usage of JSX in React:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Greeting</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  render() {
    <span class="hljs-keyword">const</span> name = <span class="hljs-string">'John Doe'</span>;

    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello, {name}!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Greeting;
</code></pre>
<p>In the code snippet above, we have a <code>Greeting</code> component that renders a heading element with a dynamic name value. Within the JSX syntax, we can embed JavaScript expressions using curly braces <code>{}</code>. In this case, the <code>name</code> variable is dynamically inserted into the rendered output.</p>
<p>JSX provides several advantages:</p>
<ol>
<li><p><strong>Readability</strong>: JSX resembles HTML syntax, making it easy to read and understand the structure of the component's UI.</p>
</li>
<li><p><strong>Expressiveness</strong>: JSX allows you to express complex UI structures and logic in a concise and declarative manner.</p>
</li>
<li><p><strong>Component composition</strong>: JSX enables the composition of multiple components, allowing you to build reusable and modular UI elements.</p>
</li>
<li><p><strong>Full power of JavaScript</strong>: Since JSX is essentially JavaScript, you can utilize the full power of the JavaScript language, including variables, functions, and control flow statements, within the JSX code.</p>
</li>
</ol>
<p>Under the hood, React's JSX code is transpiled into regular JavaScript code that creates and manipulates React elements. This transpilation process is typically handled by build tools like Babel.</p>
<p>By leveraging JSX, developers can build dynamic and interactive user interfaces with ease, combining the power of JavaScript with the familiar syntax of HTML. It simplifies the process of creating and maintaining complex UI structures, making React development more efficient and enjoyable.</p>
<h4 id="heading-one-way-data-flow">One-Way Data Flow</h4>
<p>React implements a one-way data flow, ensuring that data flows in a single direction. This makes it easier to manage application state and predict how changes will affect the UI. It promotes better control and maintainability of the application's data flow.</p>
<p>Another one of the key features of React is its one-way data flow, which ensures a predictable and efficient approach to managing data within components. In React, data flows in a unidirectional manner, from parent components to child components.</p>
<p>Here's a code snippet that illustrates the one-way data flow in React:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ParentComponent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  <span class="hljs-keyword">constructor</span>(props) {
    <span class="hljs-built_in">super</span>(props);
    <span class="hljs-built_in">this</span>.state = {
      <span class="hljs-attr">message</span>: <span class="hljs-string">'Hello from Parent'</span>,
    };
  }

  render() {
    <span class="hljs-keyword">return</span> (
      <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">ChildComponent</span> <span class="hljs-attr">message</span>=<span class="hljs-string">{this.state.message}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ChildComponent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  render() {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{this.props.message}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
  }
}
</code></pre>
<p>In the code snippet above, we have a <code>ParentComponent</code> that holds a state variable called <code>message</code>. This state is then passed down to the <code>ChildComponent</code> as a prop. The child component simply renders the value of the <code>message</code> prop.</p>
<p>The one-way data flow ensures that changes in the parent component's state propagate down to child components, triggering re-rendering only in the affected components. This approach helps to maintain the integrity and predictability of the application's data.</p>
<p>By enforcing one-way data flow, React promotes better code organization and makes it easier to reason about how data changes affect the UI. It also simplifies debugging and ensures better performance by minimizing unnecessary re-renders.</p>
<p>React's one-way data flow ensures a clear and predictable flow of data from parent to child components. This feature helps in maintaining the application's state consistency, improving code readability, and optimizing rendering performance.</p>
<h4 id="heading-component-lifecycle-methods">Component Lifecycle Methods</h4>
<p>React provides lifecycle methods that allow developers to hook into different stages of a component's lifecycle. These methods enable actions like fetching data, handling events, and updating the UI based on specific triggers.</p>
<p>By leveraging these key features, React empowers developers to build interactive and scalable user interfaces. Its component-based architecture, efficient rendering with the Virtual DOM, JSX syntax, one-way data flow, and lifecycle methods make React a versatile and powerful tool for creating modern web applications.</p>
<p>To fully understand and harness the power of React, it's essential to grasp the concept of component lifecycle methods. These methods provide opportunities to perform specific actions at different stages of a component's life cycle.</p>
<p>Let's take a look at an example code snippet that demonstrates the usage of lifecycle methods in React:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyComponent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  <span class="hljs-keyword">constructor</span>(props) {
    <span class="hljs-built_in">super</span>(props);
    <span class="hljs-built_in">this</span>.state = {
      <span class="hljs-attr">count</span>: <span class="hljs-number">0</span>,
    };
  }

  componentDidMount() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Component has mounted!'</span>);
  }

  componentDidUpdate() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Component has updated!'</span>);
  }

  componentWillUnmount() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Component will unmount!'</span>);
  }

  handleClick = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">this</span>.setState(<span class="hljs-function">(<span class="hljs-params">prevState</span>) =&gt;</span> ({ <span class="hljs-attr">count</span>: prevState.count + <span class="hljs-number">1</span> }));
  };

  render() {
    <span class="hljs-keyword">return</span> (
      <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">h1</span>&gt;</span>Count: {this.state.count}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.handleClick}</span>&gt;</span>Increment<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>
    );
  }
}
</code></pre>
<p>In the code snippet above, we have a <code>MyComponent</code> class-based component that showcases three essential lifecycle methods: <code>componentDidMount</code>, <code>componentDidUpdate</code>, and <code>componentWillUnmount</code>.</p>
<p><code>componentDidMount</code> is invoked immediately after the component is mounted in the DOM. It is an ideal place to fetch data from an API, set up event listeners, or perform other initialization tasks.</p>
<p><code>componentDidUpdate</code> is called after the component's state or props have been updated. It enables you to respond to changes and perform additional actions based on the updated data.</p>
<p><code>componentWillUnmount</code> is invoked just before the component is unmounted and destroyed. It allows you to clean up any resources, event listeners, or subscriptions to prevent memory leaks.</p>
<p>These lifecycle methods provide hooks into the various stages of a component's existence, enabling you to manage side effects, handle state updates, and maintain proper resource management.</p>
<p>By utilizing lifecycle methods effectively, you can enhance the behavior and functionality of your React components, ensuring optimal performance and seamless user experiences.</p>
<h3 id="heading-virtual-dom-and-component-based-architecture">Virtual DOM and Component-Based Architecture</h3>
<p>React's Virtual DOM and component-based architecture are foundational concepts that contribute to its efficiency and flexibility.</p>
<h4 id="heading-virtual-dom-1">Virtual DOM</h4>
<p>React introduces the concept of the Virtual DOM, which is a lightweight representation of the actual Document Object Model (DOM). The Virtual DOM serves as a virtual copy of the real DOM, allowing React to efficiently update and render components.</p>
<p>When there are changes in the application's state, React compares the Virtual DOM with the real DOM and applies only the necessary updates, minimizing the number of actual DOM manipulations. This approach significantly improves performance and makes React applications highly responsive.</p>
<p>Imagine you have a toy block tower. Instead of disassembling and reassembling each block to make changes, you take a picture of the tower. Then, you make the necessary modifications and refer to the picture to recreate the tower with the updated changes.</p>
<p>The toy block tower represents the web page or user interface of your application. The original tower is the initial state, and the picture is the Virtual DOM. When you make changes, the framework (like React) creates a new Virtual DOM, a lightweight copy of the actual DOM.</p>
<h4 id="heading-component-based-architecture-1">Component-Based Architecture</h4>
<p>React follows a component-based architecture, where UI elements are divided into reusable and independent components. Components are the building blocks of a React application, encapsulating their own state and behavior. This modular approach promotes reusability and maintainability.</p>
<p>Components can be composed together to create complex user interfaces. Changes made to one component do not affect other components unless explicitly specified. This separation of concerns simplifies development, testing, and code organization, making it easier to build and maintain large-scale applications.</p>
<p>Imagine you are building a LEGO house. Instead of building the entire house as one big piece, you break it down into smaller LEGO blocks, like walls, windows, and doors. Each block has its own unique features and functions.</p>
<p>Similarly, in component-based architecture, your web application is divided into smaller, self-contained building blocks called components. Each component represents a specific part of the user interface, such as a header, a navigation menu, or a button. These components are like the LEGO blocks that can be assembled and combined together to form the complete web application.</p>
<p>Just like LEGO blocks can be used in different structures, components can be reused across multiple pages or applications. This reusability saves time and effort as you don't need to recreate the same functionality or design from scratch. You can simply use the existing components and customize them as per your needs.</p>
<p>The combination of the Virtual DOM and component-based architecture makes React a powerful tool for building interactive and scalable user interfaces. The Virtual DOM enables efficient updates, while the component-based architecture promotes code reusability and modularity. Together, these concepts lay the foundation for creating robust and performant applications with React.</p>
<h3 id="heading-jsx-syntax-and-its-advantages">JSX Syntax and its Advantages</h3>
<p>JSX is a syntax extension used in React that allows developers to write HTML-like code within JavaScript. JSX plays a significant role in creating React components and has several advantages.</p>
<ol>
<li><p><strong>Readability and Familiarity:</strong> JSX combines the power of JavaScript with the familiarity of HTML-like syntax. It allows developers to write component templates in a declarative manner, making the code more readable and understandable. Developers can easily visualize the structure of the UI and the interactions between components, leading to more maintainable code.</p>
</li>
<li><p><strong>Component Composition:</strong> JSX facilitates the composition of components. Developers can nest components within each other, similar to how HTML tags are nested. This enables the creation of complex UI structures by assembling smaller, reusable components together. Component composition improves code organization, encourages reusability, and simplifies the management of application state.</p>
</li>
<li><p><strong>Inline JavaScript Expressions:</strong> JSX seamlessly integrates JavaScript expressions within curly braces <code>{}</code>. This enables dynamic content rendering and the execution of JavaScript code directly within the component template. Developers can embed variables, perform calculations, and handle conditional rendering, allowing for flexible and dynamic UI creation.</p>
</li>
<li><p><strong>Type Safety and Tooling:</strong> JSX enhances the development experience by providing improved tooling and type safety. Editors and IDEs can provide intelligent autocompletion and error checking for JSX syntax, helping to catch mistakes and improve productivity. Additionally, JSX can be statically analyzed for type checking, ensuring that the components receive the correct props and reducing runtime errors.</p>
</li>
</ol>
<p>JSX is a powerful feature that enables developers to build intuitive and dynamic user interfaces with React. By leveraging JSX syntax, React simplifies the creation of component templates, improves code readability, promotes component composition, and provides enhanced tooling support.</p>
<h2 id="heading-what-is-angular">What is Angular?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/2048px-Angular_full_color_logo.svg.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Angular Logo</em></p>
<p>The Angular framework has revolutionized web development by providing a comprehensive set of tools and features for building robust and scalable applications. Developed and maintained by Google, Angular has its roots in the original framework, <em>AngularJS</em>.</p>
<p>With a focus on modern web development practices, Angular has evolved into a versatile and widely adopted framework. In this section, we will explore Angular, its origins, and the key features that make it a popular choice among developers.</p>
<p>Whether you are new to Angular or seeking to deepen your understanding, this overview will serve as a solid foundation to navigate the world of Angular development.</p>
<h3 id="heading-angular-framework-and-its-origins">Angular Framework and its Origins</h3>
<p>The Angular framework, often referred to as <em>Angular</em> or <em>Angular 2+</em>, is a powerful front-end development platform created and maintained by Google.</p>
<p>It is the successor of AngularJS, which was the first version of Angular released in 2010. AngularJS introduced the concept of two-way data binding and gained popularity for its ability to build dynamic and interactive web applications.</p>
<p>However, AngularJS had limitations in terms of performance, scalability, and maintainability. This led the Angular team to re-envision the framework. Angular was introduced as a complete rewrite of AngularJS, incorporating modern web development practices and addressing the shortcomings of its predecessor.</p>
<p>Angular was built from the ground up to be more efficient, modular, and developer-friendly. It embraced a component-based architecture, where UI elements are divided into reusable components. This modular approach promotes code reusability, maintainability, and scalability, allowing developers to build complex applications with ease.</p>
<p>The release of Angular introduced significant changes and improvements, resulting in a more streamlined and performant framework. It incorporated features like a more efficient change detection mechanism, a powerful template syntax known as Angular Template Syntax (based on HTML with additional features), enhanced dependency injection, and a revamped command-line interface (CLI) for scaffolding and managing projects.</p>
<p>Over time, Angular has evolved into a comprehensive platform with a wide range of capabilities, including advanced routing, form handling, internationalization, and powerful testing tools. It has gained popularity among developers for its robustness, scalability, and the extensive ecosystem of libraries and tools that support Angular development.</p>
<p>Understanding the origins of Angular helps developers appreciate the design principles, improvements, and rationale behind the framework. It sets the stage for exploring Angular's key features and best practices, and leveraging its full potential to build modern web applications.</p>
<h3 id="heading-understanding-angulars-modular-structure">Understanding Angular's Modular Structure</h3>
<p>One of the core strengths of Angular is its modular structure, which promotes code organization, reusability, and maintainability.</p>
<p>Angular applications are composed of modules, components, services, and other building blocks that work together to create a cohesive application.</p>
<h4 id="heading-modules">Modules</h4>
<p>In Angular, modules act as containers that group related components, services, directives, and other features. Each Angular application typically has a root module, known as the <em>AppModule</em>, which serves as the entry point of the application.</p>
<p>Modules help in organizing the application's functionality into manageable units, making it easier to maintain and understand the codebase. They also provide a way to encapsulate dependencies and provide a clean separation of concerns.</p>
<p>Modules in Angular can be likened to different rooms in a house. Imagine you have a big house with multiple rooms, each serving a specific purpose. The living room is for relaxing, the kitchen is for cooking, and the bedroom is for sleeping. Each room has its own unique function and contains the necessary furniture and equipment.</p>
<p>In Angular, modules are used to organize and encapsulate different parts of your application. If we continue with the house analogy, think of each module as a separate room in the house.</p>
<p>For example, you may have a living room module that handles all the components, services, and resources related to displaying and interacting with the living room features. Similarly, you can have a kitchen module that manages all the functionality related to cooking and food preparation.</p>
<p>Now, let's bring in the AppModule, which is the root module of an Angular application. In our house analogy, the AppModule can be compared to the main entrance or foyer of the house. Just as the main entrance connects all the rooms in a house, the AppModule serves as the entry point to your Angular application, connecting all the modules together.</p>
<p>The AppModule plays a crucial role in Angular applications. It imports and aggregates all the other modules, making them accessible to the application. It also bootstraps the application by specifying the root component that will be loaded initially.</p>
<p>Essentially, the AppModule sets the foundation for your Angular application, ensuring that all the necessary modules and components are properly connected and initialized.</p>
<p>By utilizing modules in Angular, including the AppModule, you can achieve better organization, separation of concerns, and maintainability in your application. Each module focuses on a specific area or functionality, making it easier to manage and extend your application as it grows.</p>
<p>Here's a short code snippet in Angular to demonstrate the usage of modules:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { NgModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { BrowserModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/platform-browser'</span>;
<span class="hljs-keyword">import</span> { AppComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.component'</span>;

<span class="hljs-meta">@NgModule</span>({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [],
  bootstrap: [AppComponent]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule { }
</code></pre>
<p>In this example, we have an <code>AppModule</code> class decorated with the <code>NgModule</code> decorator. Inside the decorator, we define the metadata for our module.</p>
<p>The <code>declarations</code> array lists all the components, directives, and pipes that belong to this module. Here, we have a single component <code>AppComponent</code> declared.</p>
<p>The <code>imports</code> array specifies other modules that this module depends on. In this case, we're importing the <code>BrowserModule</code>, which provides essential features for running Angular applications in a web browser.</p>
<p>The <code>providers</code> array is used to provide any services or dependencies required by the components in this module.</p>
<p>The <code>bootstrap</code> array indicates the root component of the application, which will be instantiated when the application starts. Here, we have <code>AppComponent</code> specified as the bootstrap component.</p>
<h4 id="heading-components">Components</h4>
<p>Components are the building blocks of Angular applications. They represent specific sections of the user interface and encapsulate their own styles, templates, and logic.</p>
<p>Components can be composed together to create complex UI structures. By breaking the UI into smaller, reusable components, the application becomes more modular and easier to develop and maintain.</p>
<p>Components in Angular are like building blocks that make up the different parts of a house, just like the React components I talked about earlier.</p>
<p>Imagine you are building a house using Lego bricks. Each Lego brick represents a component, and when you put them together, they form different parts of the house, such as walls, doors, and windows.</p>
<p>Similarly, in Angular, components are the basic building blocks of an application's user interface. They encapsulate a specific functionality or part of the user interface, just like the Lego bricks forming specific parts of a house.</p>
<p>For example, you can have a component for displaying a navigation menu, another component for showing a list of products, and yet another component for handling user registration.</p>
<p>Components consist of three main parts: the template, the class, and the styles. The template defines the structure and layout of the component, similar to how the Lego bricks come together to form a specific shape. The class contains the logic and data that the component needs to function, like the instructions that guide you on how to assemble the Lego bricks. The styles define the appearance and design of the component, just like the colors and patterns you choose for your Lego house.</p>
<p>When you put all the components together, just like assembling Lego bricks, you create a complete and interactive user interface for your Angular application. Each component works independently, but they can also communicate and interact with each other, allowing you to build complex and dynamic applications.</p>
<p>Components in Angular are the basic building blocks of an application's user interface, encapsulating specific functionalities. By combining and arranging components, you can create a complete and interactive user interface for your Angular application, just like assembling Lego bricks to build a house.</p>
<p>A short code snippet in Angular to demonstrate the usage of components:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Component } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;

<span class="hljs-meta">@Component</span>({
  selector: <span class="hljs-string">'app-example'</span>,
  template: <span class="hljs-string">`
    &lt;h1&gt;Welcome to the Example Component!&lt;/h1&gt;
    &lt;p&gt;This is the content of the component.&lt;/p&gt;
  `</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ExampleComponent {
  <span class="hljs-comment">// Component logic goes here</span>
}
</code></pre>
<p>In this example, we have an <code>ExampleComponent</code> class decorated with the <code>@Component</code> decorator. Inside the decorator, we define the metadata for our component.</p>
<p>The <code>selector</code> property specifies the HTML selector used to render the component. In this case, the selector is <code>app-example</code>, which means the component will be rendered as <code>&lt;app-example&gt;&lt;/app-example&gt;</code> in the HTML.</p>
<p>The <code>template</code> property defines the component's view or template. It contains the HTML markup that will be rendered when the component is used. In this example, we have a simple heading and paragraph.</p>
<p>The <code>ExampleComponent</code> class represents the logic and behavior of the component. Here, you can define properties and methods, and handle events related to the component.</p>
<p>Components are the building blocks of Angular applications. They encapsulate HTML, CSS, and JavaScript functionality into reusable and self-contained units. This makes it easier to develop and maintain complex user interfaces.</p>
<h4 id="heading-services">Services</h4>
<p>Services are used for sharing data, logic, and functionality across multiple components. They encapsulate reusable business logic, data access, and communication with external APIs. Services can be injected into components or other services, enabling a clear separation of concerns and promoting code reusability.</p>
<p>Services in Angular can be likened to the helpers or assistants that make a house function smoothly. Imagine you are living in a house and you have different people helping you with specific tasks. For example, you might have a cleaning service to keep your house tidy, a plumber to fix any water-related issues, and an electrician to take care of electrical matters.</p>
<p>Same thing in Angular – services are like professionals that handle specific tasks and provide the functionality to different parts of your application. They are designed to perform common tasks or provide shared functionality that multiple components may need. Just like the helpers in a house, services can be called upon when needed and provide specialized assistance.</p>
<p>For example, you can have a data service that retrieves and stores data from an external source, such as a server or a database. This data service can be used by multiple components to fetch and update data, ensuring consistency across your application.</p>
<p>Another example is an authentication service that manages user authentication and authorization. This allows different components to verify user credentials and control access to certain features.</p>
<p>Services act as a central hub of functionality that can be shared and reused throughout your application. They help to organize your code and promote a modular structure, making it easier to maintain and update your application over time.</p>
<p>They act as centralized helpers, allowing different parts of your application to access and utilize their specialized capabilities. By using services, you can create a modular and efficient application structure, just like having dedicated helpers in a house to ensure everything runs smoothly.</p>
<p>Here's a short code snippet in Angular to demonstrate the usage of services:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> DataService {
  getData(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">'This is data retrieved from the DataService!'</span>;
  }
}
</code></pre>
<p>In this example, we have a <code>DataService</code> class decorated with the <code>@Injectable</code> decorator. This decorator marks the class as an injectable service, allowing it to be injected into other components or services.</p>
<p>Inside the <code>DataService</code> class, we define a <code>getData</code> method that returns a string. This method can be used to fetch data from an API, perform calculations, or any other logic related to data retrieval.</p>
<p>Services in Angular are responsible for handling data, business logic, and other shared functionality across components. They promote code reusability, separation of concerns, and provide a way to centralize common operations and data access within your application.</p>
<h4 id="heading-directives">Directives</h4>
<p>Directives are used to extend the behavior of HTML elements or create reusable custom elements. They allow developers to manipulate the DOM, add event listeners, apply dynamic styling, and perform other tasks to enhance the functionality and appearance of the application.</p>
<p>They can be compared to instructions or rules that you give to objects in your house. Imagine you have a set of toys or objects, and you want to assign certain behaviors or actions to them. You might use stickers or labels to indicate what each object should do.</p>
<p>Likewise, in Angular, directives are used to give instructions or behaviors to elements in your application's user interface. They are like special stickers that you can attach to HTML elements to define how they should behave or appear. Directives can control the visibility, style, and behavior of elements, allowing you to customize their functionality.</p>
<p>For example, you can have a <strong>highlight</strong> directive that adds a special effect to a specific HTML element, making it stand out with a different color or animation. This directive can be used to highlight important information or interactive elements on a web page.</p>
<p>Another example is the <strong>if</strong> directive, which conditionally shows or hides an element based on certain conditions. This can be used to dynamically display content based on user input or application state.</p>
<p>Directives help you create interactive and dynamic user interfaces by providing instructions to HTML elements. They are like labels that tell the elements how to behave and what to look like. By using directives, you can customize and control the behavior of elements in your application, making it more engaging and user-friendly.</p>
<p>In simple terms, directives in Angular are like special stickers that you can attach to objects in your house (HTML elements) to tell them how to behave or look. They allow you to add interactive features and customize the appearance of elements, making your application more engaging and enjoyable for users.</p>
<p>Here's a short code snippet in Angular to demonstrate the usage of a custom directive:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Directive, ElementRef, HostListener } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;

<span class="hljs-meta">@Directive</span>({
  selector: <span class="hljs-string">'[appHighlight]'</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> HighlightDirective {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> elementRef: ElementRef</span>) {}

  <span class="hljs-meta">@HostListener</span>(<span class="hljs-string">'mouseenter'</span>)
  onMouseEnter() {
    <span class="hljs-built_in">this</span>.highlight(<span class="hljs-string">'yellow'</span>);
  }

  <span class="hljs-meta">@HostListener</span>(<span class="hljs-string">'mouseleave'</span>)
  onMouseLeave() {
    <span class="hljs-built_in">this</span>.highlight(<span class="hljs-literal">null</span>);
  }

  <span class="hljs-keyword">private</span> highlight(color: <span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span>) {
    <span class="hljs-built_in">this</span>.elementRef.nativeElement.style.backgroundColor = color;
  }
}
</code></pre>
<p>In this example, we're creating a custom directive called <code>appHighlight</code>. This directive is applied to an HTML element using the selector <code>[appHighlight]</code>.</p>
<p>When the user hovers over the element, the <code>onMouseEnter</code> event listener is triggered, and it calls the <code>highlight</code> method to set the background color of the element to yellow.</p>
<p>Similarly, when the user moves the mouse away from the element, the <code>onMouseLeave</code> event listener is triggered, and it removes the highlight effect by setting the background color back to the default.</p>
<p>By attaching the <code>appHighlight</code> directive to an HTML element, we can dynamically control its appearance and behavior. This demonstrates the concept of directives in Angular, where you can define custom behaviors or instructions that can be applied to HTML elements to enhance their functionality and visual representation.</p>
<p>Here's an example of how you can apply the <code>appHighlight</code> directive to an HTML element in your template:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">appHighlight</span>&gt;</span>
  This is a highlighted element. Move your mouse over it to see the effect!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>In this case, we have a <code>&lt;div&gt;</code> element to which we apply the <code>appHighlight</code> directive using the directive selector <code>[appHighlight]</code>. When the user hovers over this <code>&lt;div&gt;</code> element, the directive's behavior is triggered, and the background color of the element will be set to yellow, as defined in the directive's code.</p>
<p>Understanding Angular's modular structure is crucial for building scalable and maintainable applications. By organizing functionality into modules, and leveraging reusable components, services, and directives, developers can create applications that are easier to develop, test, and extend.</p>
<p>This modular approach also facilitates collaboration among team members and enables better code organization. This leads to more efficient development workflows and better overall application architecture.</p>
<h3 id="heading-angular-cli-and-typescript-integration">Angular CLI and TypeScript Integration</h3>
<p>Angular CLI (Command Line Interface) is a powerful tool that simplifies the development process of Angular applications. It provides a command-line interface for creating, building, testing, and deploying Angular projects.</p>
<p>Additionally, Angular CLI seamlessly integrates with TypeScript, a statically typed superset of JavaScript, to enhance the development experience and enable advanced features.</p>
<h4 id="heading-creating-projects">Creating Projects</h4>
<p>With Angular CLI, creating a new Angular project is as simple as running a single command. The CLI generates a basic project structure, including configuration files, boilerplate code, and a development server. This saves time and eliminates the need for manual project setup, ensuring that developers can start coding right away.</p>
<p>To create a new project in Angular, you can use the Angular CLI (Command Line Interface). Follow these steps:</p>
<ul>
<li><p>Open your terminal or command prompt.</p>
</li>
<li><p>Navigate to the directory where you want to create your Angular project.</p>
</li>
<li><p>Run the following command:</p>
</li>
</ul>
<pre><code class="lang-bash">ng new project-name
</code></pre>
<p>Replace <code>project-name</code> with the desired name for your project (I choose frontend-frameworks). Make sure to avoid spaces or special characters.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/angular-creating-projects2-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Selecting options for Angular project</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/angular-creating-projects2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating Project</em></p>
<p>The Angular CLI will prompt you to choose additional options for your project, such as the stylesheet format (CSS, SCSS, Sass etc.) and whether you want to enable routing. Make your selections and press Enter.</p>
<p>Wait for the CLI to create the project. It will install the necessary dependencies and set up the basic structure.</p>
<p>Once the process is complete, navigate into the project directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> project-name
</code></pre>
<p>You can now start working on your Angular project. Use the <code>ng serve</code> command to run the development server and view your application in the browser:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/ng-serve.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>ng serve</em></p>
<pre><code class="lang-bash">ng serve
</code></pre>
<p>Your Angular project will be accessible at <code>http://localhost:4200</code>.</p>
<p>The <code>ng new</code> command is used to generate a new Angular project with the specified name. It sets up the initial project structure, installs the necessary dependencies, and configures the project files.</p>
<p>Using the Angular CLI simplifies the process of creating and managing Angular projects, allowing you to focus on development rather than boilerplate setup.</p>
<h4 id="heading-code-generation">Code Generation</h4>
<p>Angular CLI offers a variety of powerful code generation commands that help streamline the development process.</p>
<p>Developers can easily generate components, services, modules, and other Angular elements using the CLI, reducing the amount of manual coding required. This accelerates development speed and ensures consistent code patterns throughout the project.</p>
<p>Here are the commands for generating different Angular elements using the Angular CLI:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/code-generation-component-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Generating a component</em></p>
<ul>
<li><strong>Generating a Component:</strong></li>
</ul>
<pre><code class="lang-bash">ng generate component component-name
</code></pre>
<p>This command creates a new component with the specified name. It generates the component files, including the HTML template, CSS styles, TypeScript code, and the necessary component tests.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/code-generation-services.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Generating a service</em></p>
<ul>
<li><strong>Generating a Service:</strong></li>
</ul>
<pre><code class="lang-bash">ng generate service service-name
</code></pre>
<p>This command generates a new service with the specified name. Services are used for handling data, implementing business logic, and sharing functionality across components.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/code-generation-module.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Generating a module</em></p>
<ul>
<li><strong>Generating a Module:</strong></li>
</ul>
<pre><code class="lang-bash">ng generate module module-name
</code></pre>
<p>Use this command to create a new module with the specified name. Modules help organize and structure your Angular application by grouping related components, services, and other Angular elements.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/code-generation-directive.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Generating a directive</em></p>
<ul>
<li><strong>Generating a Directive:</strong></li>
</ul>
<pre><code class="lang-bash">ng generate directive directive-name
</code></pre>
<p>This command generates a new directive with the specified name. Directives allow you to modify the behavior or appearance of HTML elements in your Angular application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/code-generation-pipe.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Generating a pipe</em></p>
<ul>
<li><strong>Generating a Pipe:</strong></li>
</ul>
<pre><code class="lang-bash">ng generate pipe pipe-name
</code></pre>
<p>Use this command to create a new pipe with the specified name. Pipes are used for transforming data in your Angular templates, such as formatting dates, applying custom filters, or truncating or shortening an input text to a specified length.</p>
<p>These commands are executed in the terminal or command prompt, and Angular CLI will automatically generate the corresponding files and folder structure based on the specified name. Make sure to replace <code>component-name</code>, <code>service-name</code>, <code>module-name</code>, <code>directive-name</code>, or <code>pipe-name</code> with your desired names when using these commands.</p>
<h4 id="heading-development-server">Development Server</h4>
<p>Angular CLI includes a built-in development server that allows developers to run and test their applications locally.</p>
<p>The server automatically reloads the application whenever changes are made, providing a smooth development experience. It also offers features like hot module replacement, allowing developers to see the immediate effect of their code changes without the need for a full application reload.</p>
<h4 id="heading-typescript-integration">TypeScript Integration</h4>
<p>Angular is built using TypeScript, a <a target="_blank" href="https://www.freecodecamp.org/news/learn-typescript-with-this-crash-course/">statically typed superset of JavaScript</a>. TypeScript brings powerful features like static type checking, enhanced IDE support, better code navigation, and advanced refactoring tools.</p>
<p>Angular CLI seamlessly integrates with TypeScript, providing out-of-the-box support for compiling TypeScript code into JavaScript and handling TypeScript-specific configuration options.</p>
<p>By leveraging Angular CLI and TypeScript integration, developers can streamline their development workflow, enhance productivity, and benefit from the robustness and scalability of the Angular framework.</p>
<p>Angular CLI simplifies common tasks, automates repetitive processes, and provides a seamless TypeScript development experience, allowing developers to focus on building high-quality applications.</p>
<h2 id="heading-what-is-vuejs">What is Vue.js?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/Vue.js_Logo_2.svg.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Vue.js logo</em></p>
<p>Vue.js is a progressive JavaScript framework for building user interfaces. It is designed to be approachable, versatile, and easy to integrate into existing projects. Whether you're a beginner or an experienced developer, Vue.js offers a smooth learning curve and a flexible architecture that makes it a popular choice for web application development.</p>
<p>In this section, I'll teach you the fundamentals of Vue.js and help you get started with building your own Vue.js applications. We'll explore the core concepts, syntax, and key features that make Vue.js a powerful and intuitive framework.</p>
<p>If you're new to Vue.js, don't worry! I'll guide you step by step, starting from the basics and gradually diving into more advanced topics. By the end of this guide, you'll have a solid understanding of Vue.js and be well-equipped to start building your own dynamic and interactive web applications.</p>
<p>So, let's embark on this Vue.js journey together and unlock the full potential of this powerful JavaScript framework. Whether you're building a small personal project or a large-scale application, Vue.js has the tools and capabilities to bring your ideas to life.</p>
<h3 id="heading-vuejs-and-its-philosophy">Vue.js and its Philosophy</h3>
<p>Vue.js is built upon a set of guiding principles that shape its design and philosophy. Understanding these principles is crucial for effectively utilizing the framework and developing high-quality Vue.js applications.</p>
<ol>
<li><p><strong>Approachability:</strong> Vue.js prides itself on being an approachable framework, making it easy for beginners to get started. Its syntax is simple and intuitive, resembling plain HTML templates, which lowers the learning curve. Vue.js allows developers to gradually adopt its features, enabling them to integrate it into existing projects or start small and scale as needed.</p>
</li>
<li><p><strong>Versatility:</strong> Vue.js is a versatile framework that you can use for a wide range of applications. It offers a flexible architecture, allowing developers to choose the tools and libraries they prefer. Whether you want to build a single-page application (SPA), a progressive web app (PWA), or integrate Vue.js into a larger project, the framework provides the necessary flexibility to meet your specific needs.</p>
</li>
<li><p><strong>Component-Based Development:</strong> Vue.js promotes a component-based approach to development. Components are self-contained and reusable building blocks that encapsulate their own logic, styles, and templates. This modular structure facilitates code reuse, simplifies maintenance, and enables better collaboration among team members. Vue.js provides a clear and intuitive syntax for defining and using components, making it straightforward to create complex user interfaces.</p>
</li>
<li><p><strong>Reactivity:</strong> Vue.js leverages a reactive data model, which means that changes to the underlying data automatically update the corresponding views. This reactivity makes it easier to build interactive and responsive applications without the need for manual DOM manipulation. Vue.js tracks dependencies between data and views, ensuring efficient updates and optimized rendering performance.</p>
</li>
</ol>
<p>By embracing these principles, Vue.js empowers developers to build elegant, maintainable, and scalable applications. The philosophy of approachability, versatility, component-based development, and reactivity sets the foundation for creating exceptional user interfaces with Vue.js.</p>
<h3 id="heading-vues-reactivity-system-and-component-composition">Vue's Reactivity System and Component Composition</h3>
<p>Vue.js employs a powerful reactivity system that enables efficient and automatic updates to the user interface based on changes in the underlying data. This reactivity is achieved through Vue's reactive data model and makes it easy to create dynamic and responsive applications.</p>
<h4 id="heading-reactive-data-model">Reactive Data Model</h4>
<p>Vue.js uses a reactive data model, where data properties are automatically tracked for changes. When the data changes, Vue.js automatically updates the associated views, ensuring a synchronized and reactive user interface. This reactivity simplifies the development process as developers do not need to manually manipulate the DOM to reflect data changes.</p>
<p>In Vue.js, the reactive data model is like a magical connection between your data and the user interface. Imagine you have a magic box where you can put your data. Whenever the data inside the box changes, the UI automatically updates to reflect those changes. It's like having a real-time mirror of your data!</p>
<p>In this magical world of Vue.js, you define your data properties inside a Vue component, and Vue takes care of tracking those properties for you. Whenever a property changes, Vue automatically detects it and updates the corresponding parts of the UI. This means you don't have to manually update the UI elements every time the data changes. Vue does all the heavy lifting for you.</p>
<p>So, let's say you have a counter in your app. When you click a button to increase the counter value, Vue will instantly update the value in the UI without you having to write any extra code. It's as simple as that! The reactive data model in Vue.js makes it easy to keep your UI in sync with your data, saving you time and effort.</p>
<p>By embracing the reactive data model in Vue.js, you can build dynamic and interactive user interfaces with ease. It allows you to focus on manipulating the data, and Vue takes care of updating the UI accordingly. It's like having a superpower that simplifies your development process and brings your app to life.</p>
<p>So, remember, with Vue.js, you can harness the power of the reactive data model to create engaging and responsive user interfaces effortlessly.</p>
<h4 id="heading-computed-properties-and-watchers">Computed Properties and Watchers</h4>
<p>Vue.js provides computed properties and watchers to handle more complex logic and reactivity requirements.</p>
<p>Computed properties allow developers to define properties that are computed based on other reactive data properties. These computed properties are cached and updated only when their dependencies change, optimizing performance.</p>
<p>Watchers, on the other hand, allow developers to react to specific data changes and perform custom logic when those changes occur.</p>
<p>Computed properties and watchers are like special helpers that assist you in handling data transformations and reacting to changes. Imagine you have a friend who always keeps an eye on things for you and gives you updates whenever something changes. That's exactly what computed properties and watchers do in Vue.</p>
<p>Computed properties are like smart calculators that automatically compute and update values based on other data properties. It's like having a helper who can perform complex calculations for you.</p>
<p>For example, let's say you have the length and width of a rectangle, and you want to calculate its area. With computed properties, you can define a property called <code>area</code> that dynamically computes the area value whenever the length or width changes. This way, you always have the correct area value without manually recalculating it.</p>
<p>On the other hand, watchers are like attentive observers who keep an eye on specific data properties and perform actions when they change. It's like having a friend who notifies you whenever something important happens.</p>
<p>For example, let's say you have a form input field, and you want to perform some validation or execute a function whenever the input value changes. With watchers, you can define a watcher that watches the input value and triggers a function whenever it changes. This allows you to take immediate action and respond to user inputs or data changes.</p>
<p>By using computed properties and watchers in Vue.js, you can simplify complex data manipulations and react to changes effectively. They provide you with powerful tools to automate calculations, perform validations, and execute custom logic whenever necessary. It's like having reliable assistants who handle the heavy lifting for you, making your coding experience more efficient and enjoyable.</p>
<p>With computed properties and watchers in Vue.js, you have the power to automatically compute values and respond to changes effortlessly. They are your trusted companions in managing data transformations and handling dynamic behaviors in your Vue components.</p>
<h4 id="heading-component-composition">Component Composition</h4>
<p>Vue.js promotes component-based development and encourages the composition of smaller, reusable components to build larger and more complex user interfaces.</p>
<p>Components can be easily created, registered, and used throughout the application. Vue's reactivity system allows data to flow seamlessly between parent and child components, enabling a hierarchical and reactive structure.</p>
<p>Component composition, in Vue.js, is like playing with building blocks to create something amazing. Let's say you have different LEGO bricks, and each brick represents a specific part of your website or web app. With component composition in Vue, you can easily combine these bricks to build something much bigger and more powerful.</p>
<p>Think of each Vue component as a LEGO brick that has its own unique functionality and appearance. You can create components for a navigation bar, a button, an image gallery, or any other part of your web page. Now, when you want to build a complete web page, you can assemble these components together, just like stacking LEGO bricks on top of each other.</p>
<p>Component composition allows you to reuse components and nest them within each other to create complex and interactive web pages. It's like building a LEGO spaceship by combining different bricks, adding wings, a cockpit, and other parts.</p>
<p>Similarly, in Vue, you can nest components inside one another, passing data and interacting with each other to create dynamic and interactive user interfaces.</p>
<p>By using component composition in Vue.js, you can easily break down your web page into smaller, manageable parts, and then assemble them together to create a cohesive and functional whole. It's like having a box of LEGO bricks that you can use to build anything you imagine.</p>
<p>Component composition lets you create individual components for different parts of your web page and then combine them together to create a complete and interactive experience. It's a fun and creative way to build awesome websites and web apps.</p>
<h4 id="heading-props-and-events">Props and Events</h4>
<p>Vue.js facilitates communication between components through the use of props and events. Props allow data to be passed from parent components to child components, enabling a unidirectional flow of data. Events, on the other hand, allow child components to emit events and notify parent components about specific actions or changes.</p>
<p>In Vue.js, props and events are like passing messages between components, just like friends talking to each other. Think of it as you having two friends who want to share information with each other. One friend can send a message (prop) to the other friend, and the other friend can respond with a message (event) back.</p>
<p>In Vue, components can communicate with each other using props and events. Think of a prop as a message that a parent component sends to its child component. It's like a note passed from one friend to another, containing important information. The child component can receive the prop and use that information to display or modify its behavior. It's a way for components to share data with each other.</p>
<p>Now, events are like the response from the child component back to the parent component. It's the other friend replying to the message they received. The child component can emit an event to let the parent component know that something happened or that it needs to take action. It's like raising your hand and saying, <em>"Hey, something important just happened!"</em></p>
<p>With props and events in Vue.js, components can talk to each other, share information, and work together as a team. This communication between components allows you to build dynamic and interactive web pages where different parts can exchange data and work together seamlessly.</p>
<p>So, just like friends passing notes and responding with actions, props and events in Vue.js help components share information and work together as a team. It's a fun way to create interactive and collaborative web applications.</p>
<p>Vue's reactivity system and component composition provide a solid foundation for building flexible and modular applications. By leveraging the reactivity system, developers can create dynamic and responsive user interfaces, while component composition promotes code reuse, maintainability, and scalability.</p>
<p>With Vue.js, developers can easily manage complex application states and achieve a seamless and interactive user experience.</p>
<h3 id="heading-single-file-components-and-vue-cli">Single-File Components and Vue CLI</h3>
<p>Vue.js offers a convenient way to structure and organize components using Single-File Components (SFCs). SFCs encapsulate the template, script, and styles of a component into a single file, promoting better separation of concerns and improving code readability.</p>
<h4 id="heading-structure-and-organization">Structure and Organization</h4>
<p>With Single-File Components, each component is contained within a single file, which makes it easier to understand and manage.</p>
<p>The template section holds the HTML markup, the script section contains the component's logic written in JavaScript, and the style section holds the component's styles using CSS or pre-processors like SASS or LESS. This modular structure allows developers to work on different aspects of a component without navigating through multiple files.</p>
<p>Here's a short code snippet that demonstrates the structure and organization of a Vue single-file component:</p>
<pre><code class="lang-python">&lt;template&gt;
  &lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">my</span>-<span class="hljs-title">component</span>"&gt;
    &lt;!-- <span class="hljs-title">Component</span> <span class="hljs-title">HTML</span> <span class="hljs-title">template</span> --&gt;
    &lt;h1&gt;{{ message }}&lt;/h1&gt;
    &lt;button @click="increment"&gt;Click Me!&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  name:</span> <span class="hljs-string">'MyComponent'</span>,
  data() {
    <span class="hljs-keyword">return</span> {
      message: <span class="hljs-string">'Hello, Vue!'</span>,
      count: <span class="hljs-number">0</span>,
    };
  },
  methods: {
    increment() {
      this.count++;
    },
  },
};
&lt;/script&gt;

&lt;style scoped&gt;
.my-component {
  /* Component-specific styles */
}
&lt;/style&gt;
</code></pre>
<p>In this code snippet, you can see the structure of a Vue single-file component. It consists of three main sections: <code>&lt;template&gt;</code>, <code>&lt;script&gt;</code>, and <code>&lt;style&gt;</code>.</p>
<p>The <code>&lt;template&gt;</code> section contains the HTML template of the component. It defines the structure and layout of the component's content.</p>
<p>The <code>&lt;script&gt;</code> section contains the JavaScript code for the component. It includes the component's definition, which includes the component's name, data, and methods.</p>
<p>In this example, we have a <code>data</code> object that holds the component's state, including a <code>message</code> property and a <code>count</code> property. We also have a <code>methods</code> object that defines the <code>increment</code> method, which increments the <code>count</code> property when the button is clicked.</p>
<p>The <code>&lt;style&gt;</code> section contains the component-specific styles. By using the <code>scoped</code> attribute, the styles are only applied to the component's elements, ensuring encapsulation and preventing conflicts with styles from other components.</p>
<p>This structure helps in organizing and managing the code for your Vue components. It keeps the HTML, JavaScript, and styles related to a component in a single file, making it easier to understand and maintain your codebase.</p>
<h4 id="heading-scoped-styles">Scoped Styles</h4>
<p>Single-File Components provide built-in support for scoped styles. By default, styles defined within a component only apply to that component's template, preventing style conflicts with other components. This encapsulation makes it easier to style components without worrying about global style pollution.</p>
<p>Take a look at this code snippet that demonstrates the use of scoped styles in a Vue single-file component:</p>
<pre><code class="lang-python">&lt;template&gt;
  &lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">my</span>-<span class="hljs-title">component</span>"&gt;
    &lt;!-- <span class="hljs-title">Component</span> <span class="hljs-title">content</span> --&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  name:</span> <span class="hljs-string">'MyComponent'</span>,
};
&lt;/script&gt;

&lt;style scoped&gt;
.my-component {
  background-color: <span class="hljs-comment">#f1f1f1;</span>
  padding: <span class="hljs-number">20</span>px;
  border-radius: <span class="hljs-number">5</span>px;
}
&lt;/style&gt;
</code></pre>
<p>In this code snippet, you can see the use of scoped styles in Vue single-file components. The <code>&lt;style&gt;</code> section includes the component-specific styles, and the <code>scoped</code> attribute is added to the <code>&lt;style&gt;</code> tag.</p>
<p>Scoped styles mean that the styles defined within the component's <code>&lt;style&gt;</code> section only apply to the elements within that component.</p>
<p>In the example, the <code>.my-component</code> class is used to style the component's <code>&lt;div&gt;</code> element. The background color is set to <code>#f1f1f1</code>, there's padding around the component, and the border radius is set to <code>5px</code>.</p>
<p>The scoped styles ensure that these styles only affect the specific component they are defined in. This helps prevent style conflicts and allows for better encapsulation of styles within the component. It allows you to write component-specific styles without worrying about affecting other components or elements on the page.</p>
<p>Using scoped styles in Vue single-file components promotes code organization and separation of concerns, making it easier to manage and maintain your styles within your Vue project.</p>
<h4 id="heading-vue-cli">Vue CLI</h4>
<p>Vue CLI (Command Line Interface) is a powerful tool that simplifies the development of Vue.js applications. It provides a command-line interface for creating, configuring, and managing Vue projects.</p>
<p>Vue CLI includes features like project scaffolding, code generation, and an integrated development server, making it easy to set up and start building Vue applications.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/install-vue-cli.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Installing Vue CLI</em></p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install Vue CLI globally (if not already installed)</span>
npm install -g @vue/cli

<span class="hljs-comment"># Create a new Vue project</span>
vue create my-project
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/vue-create.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Create Vue Project</em></p>
<p>As you can see in code snippet above, we first install Vue CLI globally using the <code>npm install</code> command. This step is required only if you haven't installed Vue CLI before.</p>
<p>Once Vue CLI is installed, you can create a new Vue project using the <code>vue create</code> command. In the example, we're creating a project named "<em>my-project</em>". Vue CLI will prompt you to select a preset configuration for your project. You can choose from various options like default, manually select features, or use a saved preset.</p>
<p>After selecting the preset, Vue CLI will set up the project structure, install the necessary dependencies, and generate the initial files for your Vue project.</p>
<p>Using Vue CLI simplifies the process of setting up a new Vue project by providing a command-line interface and project scaffolding. It automates many common tasks, such as project configuration, dependency installation, and build setup.</p>
<p>Vue CLI also provides additional features like hot-reloading during development, ready-to-use templates, and easy project customization.</p>
<p>With Vue CLI, you can quickly start working on your Vue projects without worrying about the initial setup, allowing you to focus on writing code and building your application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/npm-build-vue.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><code>npm run build</code></p>
<h4 id="heading-build-and-deployment">Build and Deployment</h4>
<p>Vue CLI offers a streamlined build process that optimizes the application for production. It generates optimized bundles, minifies the code, and applies various optimizations to improve performance.</p>
<p>Additionally, Vue CLI supports easy deployment of Vue applications to various hosting platforms or content delivery networks (CDNs), simplifying the deployment process.</p>
<p>When it comes to building and deploying your Vue.js application, Vue CLI provides a simple and efficient way to handle this process. After you've developed your application locally, you'll need to generate a production-ready build that can be deployed to a web server.</p>
<p>Vue CLI offers a command called <code>npm run build</code> that compiles your Vue components, bundles your assets, and optimizes your code for production. It generates a <code>dist</code> directory containing all the necessary files for deployment. This process ensures that your application is optimized for performance and ready to be served to users.</p>
<p>Once you have your production build, you can deploy it to a web server or a hosting platform of your choice. You can simply upload the contents of the <code>dist</code> directory to your server, and your Vue.js application will be accessible to users over the internet.</p>
<p>Deploying your Vue.js application typically involves configuring your server to serve the static files correctly, setting up any necessary server-side routing or configurations, and ensuring that your server has the required dependencies installed.</p>
<p>It's important to choose a reliable and secure hosting solution that fits your application's requirements. Popular hosting options for Vue.js applications include platforms like <a target="_blank" href="https://www.netlify.com">Netlify</a>, <a target="_blank" href="https://vercel.com/">Vercel</a>, and <a target="_blank" href="https://pages.github.com/">GitHub Pages</a>, which offer seamless deployment workflows and robust infrastructure.</p>
<p>By leveraging the build and deployment features provided by Vue CLI, you can easily package and deploy your Vue.js application, making it accessible to users worldwide.</p>
<p>By utilizing Single-File Components (SFCs) and Vue CLI, developers can efficiently structure their Vue.js projects, enhance code organization, and leverage powerful development tools. This approach not only improves code maintainability but also allows for better collaboration among team members.</p>
<p>Vue's ecosystem provides a seamless development experience that empowers developers to build robust and scalable applications with ease.</p>
<h2 id="heading-comparing-javascript-frameworks">Comparing JavaScript Frameworks</h2>
<p>When it comes to choosing a frontend framework for web development, you'll need to consider your use case, the features you need, and your skillset, among other things.</p>
<p>React, Angular, and Vue are all widely adopted frameworks that offer different approaches and features. They call them "<em>The Big Three</em>". Understanding the similarities and differences between these frameworks can help you make an informed decision based on your project requirements and personal preferences.</p>
<p>In this section, we will compare React, Angular, and Vue across various aspects such as learning curve, performance, community support, ecosystem, and more. We will explore their strengths and weaknesses, highlighting the unique features and benefits they bring to the table.</p>
<p>By examining these frameworks side by side, you can gain a better understanding of their key characteristics and determine which one aligns best with your needs. Remember, there is no one-size-fits-all solution, and the right choice ultimately depends on the specific demands of your project.</p>
<p>So, let's dive into the comparison and discover the similarities and differences among the big three. This knowledge will equip you with the necessary insights to choose the frontend framework that will enhance your development workflow and enable you to create exceptional web applications.</p>
<h3 id="heading-similarities-and-differences-between-react-angular-and-vue">Similarities and Differences between React, Angular, and Vue</h3>
<p>React, Angular, and Vue are all powerful frontend frameworks, but they differ in their approach, syntax, and ecosystem. Let's explore the key similarities and differences between these frameworks:</p>
<ol>
<li><p><strong>Component-Based Architecture:</strong> React, Angular, and Vue all follow a component-based architecture, where applications are built by composing reusable components. This promotes code reusability, modularity, and scalability.</p>
</li>
<li><p><strong>Virtual DOM:</strong> React and Vue utilize a Virtual DOM, a lightweight representation of the actual DOM. This allows for efficient updates and ensures optimal rendering performance. Angular, on the other hand, uses a different change detection mechanism based on zones.</p>
</li>
<li><p><strong>Learning Curve:</strong> React and Vue are known for their gentle learning curves, making them more beginner-friendly. Angular, on the other hand, has a steeper learning curve due to its extensive feature set and complex concepts.</p>
</li>
<li><p><strong>Language and Syntax:</strong> React uses JavaScript, while Angular employs TypeScript, a superset of JavaScript. Vue supports both JavaScript and TypeScript, offering flexibility in language choice. The syntax and coding styles also differ across the frameworks, with React using JSX, Angular using a template-driven approach, and Vue utilizing a combination of template syntax and JavaScript.</p>
</li>
<li><p><strong>Ecosystem and Community Support:</strong> React, Angular, and Vue have vibrant ecosystems with active communities. React has a large and mature ecosystem with numerous libraries and tools available. Angular has strong corporate backing from Google, which ensures robust development and support. Vue has gained popularity in recent years, and although its ecosystem is smaller, it continues to grow rapidly.</p>
</li>
<li><p><strong>Popularity and Adoption:</strong> React has gained significant popularity and is widely adopted by large tech companies. Angular, being a full-fledged framework, is commonly used for enterprise-level applications. Vue has experienced rapid growth and has gained a strong following in the developer community.</p>
</li>
</ol>
<p>While these frameworks share some similarities, their differences in syntax, learning curve, and ecosystem can influence your choice. It's essential to evaluate your project requirements, team expertise, and personal preferences to determine which framework suits your needs best.</p>
<h3 id="heading-performance-considerations-and-scalability">Performance Considerations and Scalability</h3>
<p>Performance is a crucial aspect to consider when choosing a frontend framework for your web application. Let's explore the performance considerations and scalability of React, Angular, and Vue:</p>
<ol>
<li><p><strong>Rendering Performance:</strong> React, Angular, and Vue all employ different rendering approaches. React utilizes a Virtual DOM, which efficiently updates and renders only the necessary components. Angular uses its own change detection mechanism, while Vue leverages a combination of Virtual DOM and a reactive data model. These approaches aim to minimize unnecessary re-renders and enhance performance.</p>
</li>
<li><p><strong>Bundle Size:</strong> The size of the framework's bundle can impact the initial load time of your application. React and Vue have smaller footprints, allowing for faster initial loading. Angular, being a full-fledged framework, has a larger bundle size, which may require additional optimization techniques to improve load times.</p>
</li>
<li><p><strong>Optimization Techniques:</strong> All three frameworks offer various optimization techniques to improve performance. These include code splitting, lazy loading, tree shaking (also known as dead code elimination, it's a process used by modern JavaScript bundlers to remove unused code from a project), and caching strategies. By implementing these techniques correctly, you can minimize the overall bundle size, reduce network requests, and optimize the runtime performance of your application.</p>
</li>
<li><p><strong>Scalability:</strong> When it comes to scalability, all three frameworks can handle large-scale applications. However, Angular, with its opinionated structure and extensive features, is particularly suited for enterprise-level applications that require complex architecture and scalability. React and Vue, being more lightweight and flexible, can also scale well, but they may require additional setup and architectural decisions as the application grows.</p>
</li>
</ol>
<p>It's important to note that performance considerations and scalability depend on various factors, including the size and complexity of your application, the specific optimization techniques implemented, and the efficiency of your code.</p>
<p>Conducting performance testing, utilizing best practices, and staying updated with the latest optimizations can help ensure optimal performance and scalability regardless of the chosen framework.</p>
<p>Keep in mind that while performance is important, it should be balanced with other considerations such as developer productivity, community support, and project requirements. Evaluating these factors holistically will enable you to make an informed decision regarding the performance and scalability needs of your web application.</p>
<h3 id="heading-learning-curve-and-community-support">Learning Curve and Community Support</h3>
<p>The learning curve and community support are essential considerations when choosing a frontend framework like React, Angular, or Vue. Let's explore these aspects in more detail:</p>
<ol>
<li><strong>Learning Curve:</strong> The learning curve refers to the time and effort required to become proficient in a particular framework. React, Angular, and Vue have different learning curves based on their concepts, syntax, and ecosystem.</li>
</ol>
<ul>
<li><p><strong>React:</strong> React has a relatively gentle learning curve, especially for developers familiar with JavaScript. Its core concepts like components, state management, and JSX syntax are easy to grasp. But mastering advanced topics like React Hooks and state management libraries may require additional effort.</p>
</li>
<li><p><strong>Angular:</strong> Angular has a steeper learning curve (especially a difficult initial learning process) compared to React and Vue. It is a full-fledged framework with a comprehensive set of features and a specific way of doing things. Angular's learning curve stems from its powerful dependency injection system, TypeScript integration, and the extensive use of decorators.</p>
</li>
<li><p><strong>Vue:</strong> Vue strikes a balance between React and Angular in terms of learning curve. Its straightforward API, clear documentation, and gradual adoption approach make it beginner-friendly. Vue's simplicity and intuitive syntax make it relatively easy to get started with, even for developers new to frontend frameworks.</p>
</li>
</ul>
<ol start="2">
<li><strong>Community Support:</strong> The strength of the community around a framework can greatly impact your learning experience and development journey. React, Angular, and Vue all have vibrant communities with active support channels, forums, and online resources.</li>
</ol>
<ul>
<li><p><strong>React:</strong> React has a large and robust community, with countless tutorials, documentation, and third-party libraries available. The React community is known for its responsiveness and continuous innovation, making it easier to find solutions to common problems.</p>
</li>
<li><p><strong>Angular:</strong> Angular has solid community support, backed by Google. It has extensive documentation, official guides, and a dedicated team maintaining the framework. The Angular community is known for its focus on best practices, architectural patterns, and enterprise-level support.</p>
</li>
<li><p><strong>Vue:</strong> Although Vue's community is relatively smaller compared to React and Angular, it is rapidly growing and gaining momentum. Vue has a friendly and supportive community that actively contributes to its development. The Vue community is known for its inclusivity, helpfulness, and emphasis on simplicity.</p>
</li>
</ul>
<p>Considering the learning curve and community support is crucial, especially for beginners. It's important to choose a framework with a learning curve that aligns with your current skill level and project requirements. Plus, a strong and active community can provide valuable resources, guidance, and collaboration opportunities, helping you overcome challenges and stay up-to-date with the latest trends and best practices.</p>
<h2 id="heading-how-to-choose-the-right-framework-for-your-project">How to Choose the Right Framework for Your Project</h2>
<p>Selecting the most suitable frontend framework for your project requires careful consideration of several factors. Here are some key points to keep in mind when making your decision:</p>
<h3 id="heading-project-requirements">Project Requirements</h3>
<p>Start by evaluating your project's specific requirements. Consider factors such as the complexity of the application, the size of the development team, scalability needs, and performance requirements. You should also think about any existing technical constraints such as the technology stack being used, integration with existing systems or libraries, and compatibility with specific platforms or frameworks.</p>
<p>Understanding these requirements will help you determine which framework aligns best with your project goals.</p>
<h3 id="heading-learning-curve">Learning Curve</h3>
<p>Assess your team's skillset and experience level. If you have a team of developers who are already proficient in a particular framework, it may be more efficient to leverage their existing expertise.</p>
<p>On the other hand, if you have a team of beginners or developers with a broad range of skills, opting for a framework with a gentler learning curve can facilitate a smoother onboarding process.</p>
<h3 id="heading-community-and-ecosystem">Community and Ecosystem</h3>
<p>Consider the size and vibrancy of the framework's community and ecosystem. A robust community provides access to a wealth of resources, tutorials, libraries, and support channels.</p>
<p>A thriving ecosystem ensures that you have a wide range of tools, plugins, and extensions to enhance your development process. It also indicates the long-term viability and sustainability of the framework.</p>
<h3 id="heading-compatibility-and-integration">Compatibility and Integration</h3>
<p>Evaluate how well the framework integrates with your existing technology stack. Consider factors such as compatibility with backend frameworks, support for APIs, and the availability of plugins or packages that can facilitate integration with other tools and services you may be using.</p>
<h3 id="heading-flexibility-and-customization">Flexibility and Customization</h3>
<p>Each framework has its own conventions and patterns. Assess whether the framework's structure and design principles align with your development preferences and project requirements.</p>
<p>Consider the flexibility and extensibility of the framework, as well as the ease with which you can customize and adapt it to suit your specific needs.</p>
<p>By carefully evaluating these factors, you can make an informed decision and select the right frontend framework that will empower you to build scalable, performant, and maintainable web applications that meet your project requirements and developer team's expertise.</p>
<h2 id="heading-resources-for-learning-and-getting-started">Resources for Learning and Getting Started</h2>
<p>When embarking on your journey to learn and master frontend frameworks like React, Angular, or Vue, it's important to have access to high-quality learning resources.</p>
<p>Here are some recommended resources to help you get started:</p>
<h3 id="heading-official-documentation">Official Documentation</h3>
<p>The official documentation of each framework is an invaluable resource. It provides comprehensive guides, tutorials, and examples that cover the core concepts, features, and best practices.</p>
<p>Start by exploring the official documentation of React (<a target="_blank" href="https://react.dev/">react.dev</a>), Angular (<a target="_blank" href="https://angular.io/">angular.io</a>), and Vue (<a target="_blank" href="https://vuejs.org/">vuejs.org</a>) to gain a solid foundation.</p>
<h3 id="heading-online-courses-and-tutorials">Online Courses and Tutorials</h3>
<p>Online courses and tutorials offer structured learning paths and hands-on exercises that can accelerate your understanding of frontend frameworks.</p>
<p>Platforms like <a target="_blank" href="https://www.udemy.com/">Udemy</a>, <a target="_blank" href="https://www.coursera.org/">Coursera</a>, <a target="_blank" href="https://www.udacity.com/">Udacity</a>, and <a target="_blank" href="https://www.pluralsight.com/">Pluralsight</a> offer a wide range of courses taught by industry experts. Look for courses that cater to beginners and offer practical projects to apply your knowledge.</p>
<h3 id="heading-youtube-channels-and-video-series">YouTube Channels and Video Series</h3>
<p>YouTube is a treasure trove of tutorial videos and in-depth explanations of frontend frameworks. Channels like <a target="_blank" href="https://www.youtube.com/@TraversyMedia">Traversy Media</a>, <a target="_blank" href="https://www.youtube.com/@NetNinja">The Net Ninja</a>, <a target="_blank" href="https://www.youtube.com/@freecodecamp">freeCodeCamp</a>, and <a target="_blank" href="https://www.youtube.com/@academind">Academind</a> provide comprehensive video series that cover various aspects of React, Angular, and Vue, from basics to advanced topics. These videos offer a visual and interactive learning experience.</p>
<h3 id="heading-online-communities-and-forums">Online Communities and Forums</h3>
<p>Joining online communities and forums dedicated to frontend development can greatly enhance your learning experience.</p>
<p>Platforms like <a target="_blank" href="https://stackoverflow.com/">Stack Overflow</a>, <a target="_blank" href="https://www.reddit.com/">Reddit</a>, <a target="_blank" href="https://forum.freecodecamp.org/">freeCodeCamp</a>, <a target="_blank" href="https://hashnode.com/">Hashnode</a>, <a target="_blank" href="https://hackernoon.com/">Hackernoon</a>, and <a target="_blank" href="https://dev.to/">Dev.to</a> have active communities where you can ask questions, seek guidance, and engage in discussions with fellow developers. The supportive nature of these communities can help you overcome challenges and expand your knowledge.</p>
<h3 id="heading-books-and-ebooks">Books and eBooks</h3>
<p>Books are another valuable resource for in-depth learning. Look for recommended books on React, Angular, and Vue that cater to beginners and cover the fundamental concepts.</p>
<p>Some popular titles include <em>React Up and Running</em> by Stoyan Stefanov, <em>Angular: Up and Running</em> by Shyam Seshadri and Brad Green, and <em>Vue.js 2 Cookbook</em> by Andrea Passaglia.</p>
<p>By utilizing these resources, you can access a variety of learning materials that cater to different learning styles and preferences.</p>
<p>Remember to combine theory with hands-on practice to reinforce your understanding of the frameworks. As you progress, keep exploring additional resources, attending workshops, and contributing to the community to further enhance your skills and stay up-to-date with the latest developments in frontend development.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Frontend frameworks such as React, Angular, and Vue play a crucial role in modern web development. They provide powerful tools and abstractions that simplify the creation of interactive and dynamic user interfaces. Throughout this guide, we've explored the key features and benefits of these frameworks, as well as their similarities and differences.</p>
<p>Understanding the core concepts of each framework, such as React's component-based architecture, Angular's modular structure, and Vue's reactivity system will allow to make informed decisions on which framework suits your project requirements and personal preferences.</p>
<p>It's important to consider factors like performance, scalability, learning curve, and community support when choosing the right framework for your development endeavors.</p>
<p>Remember, learning a frontend framework is an ongoing process. It's essential to continuously expand your knowledge, stay updated with the latest trends and best practices, and keep honing your skills.</p>
<p>Explore the abundance of resources available, such as official documentation, online courses, tutorials, and community forums, to deepen your understanding and proficiency in using these frameworks.</p>
<p>As you delve deeper into the world of frontend development, don't limit yourself to just one framework. Familiarize yourself with multiple frameworks to broaden your skill set and adapt to different project requirements. Embrace the opportunities for collaboration and learning from other developers within the vibrant communities surrounding these frameworks.</p>
<p>Frontend frameworks have revolutionized web development, empowering developers to create immersive, responsive, and highly interactive web applications. By harnessing the power of React, Angular, Vue, or other frameworks, you can unlock endless possibilities and bring your ideas to life on the web. So, continue exploring, experimenting, and pushing the boundaries of frontend development to achieve remarkable results.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create and Publish a Vue Component Library – Update ]]>
                </title>
                <description>
                    <![CDATA[ Back in 2020, I wrote a post about building a Vue Component library. Since then the package I used has been deprecated, and the recommended way to build a library/package is to use Vite. Getting Started I started off the project by running npm create... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-and-publish-a-vue-component-library-update/</link>
                <guid isPermaLink="false">66bb92e15d242388375d388c</guid>
                
                    <category>
                        <![CDATA[ components ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vite ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Brian Barrow ]]>
                </dc:creator>
                <pubDate>Tue, 30 May 2023 20:11:28 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/pexels-pixabay-159711.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Back in 2020, I <a target="_blank" href="https://www.freecodecamp.org/news/how-to-create-and-publish-a-vue-component-library/">wrote a post</a> about building a Vue Component library. Since then the package I used has been deprecated, and the recommended way to build a library/package is to use Vite.</p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>I started off the project by running <code>npm create vite@latest</code> and naming my project <code>brian-component-lib</code> to stay consistent with my previous post. I also chose to use TypeScript and Vue when those options came up.</p>
<h2 id="heading-the-component">The Component</h2>
<p>The component I built is a clone of the buttons used on freeCodeCamp.org</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-160.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Button component we are building</em></p>
<p>Here is the code for that component. Note that it is using TypeScript and the <code>script setup</code> format available in Vue 3.</p>
<pre><code class="lang-js">&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;

defineProps&lt;{ <span class="hljs-attr">text</span>: string }&gt;()

&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn-cta"</span>&gt;</span>{{ text }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</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="css">
<span class="hljs-selector-class">.btn-cta</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#d0d0d5</span>;
  <span class="hljs-attribute">border-width</span>: <span class="hljs-number">3px</span>;
  <span class="hljs-attribute">border-color</span>: <span class="hljs-number">#1b1b32</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">border-style</span>: solid;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#1b1b32</span>;
  <span class="hljs-attribute">display</span>: block;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">font-weight</span>: normal;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">-ms-touch-action</span>: manipulation;
  <span class="hljs-attribute">touch-action</span>: manipulation;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">white-space</span>: nowrap;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">6px</span> <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.42857143</span>;
}

<span class="hljs-selector-class">.btn-cta</span><span class="hljs-selector-pseudo">:active</span><span class="hljs-selector-pseudo">:hover</span>,
<span class="hljs-selector-class">.btn-cta</span><span class="hljs-selector-pseudo">:focus</span>,
<span class="hljs-selector-class">.btn-cta</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#1b1b32</span>;
  <span class="hljs-attribute">border-width</span>: <span class="hljs-number">3px</span>;
  <span class="hljs-attribute">border-color</span>: <span class="hljs-number">#000</span>;
  <span class="hljs-attribute">background-image</span>: none;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#f5f6f7</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>Then we need to expose this component in the library. We do that by exporting it from an <code>index.ts</code> file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> FccButton <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/FccButton.vue"</span>;

<span class="hljs-keyword">export</span> { FccButton };
</code></pre>
<h2 id="heading-config">Config</h2>
<p>With the component code ready to go, we need to make sure Vite and the <code>package.json</code> file are configured properly.</p>
<p>Vite has a lot of options when building code. We are interested in the <a target="_blank" href="https://vitejs.dev/guide/build.html#library-mode">"Library Mode"</a>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">"vite"</span>;
<span class="hljs-keyword">import</span> { resolve } <span class="hljs-keyword">from</span> <span class="hljs-string">"path"</span>;
<span class="hljs-keyword">import</span> vue <span class="hljs-keyword">from</span> <span class="hljs-string">"@vitejs/plugin-vue"</span>;

<span class="hljs-comment">// https://vitejs.dev/config/</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  <span class="hljs-attr">plugins</span>: [vue()],
  <span class="hljs-attr">build</span>: {
    <span class="hljs-attr">lib</span>: {
      <span class="hljs-comment">// src/indext.ts is where we have exported the component(s)</span>
      <span class="hljs-attr">entry</span>: resolve(__dirname, <span class="hljs-string">"src/index.ts"</span>),
      <span class="hljs-attr">name</span>: <span class="hljs-string">"BrianComponentLibrary"</span>,
      <span class="hljs-comment">// the name of the output files when the build is run</span>
      <span class="hljs-attr">fileName</span>: <span class="hljs-string">"brian-component-lib"</span>,
    },
    <span class="hljs-attr">rollupOptions</span>: {
      <span class="hljs-comment">// make sure to externalize deps that shouldn't be bundled</span>
      <span class="hljs-comment">// into your library</span>
      <span class="hljs-attr">external</span>: [<span class="hljs-string">"vue"</span>],
      <span class="hljs-attr">output</span>: {
        <span class="hljs-comment">// Provide global variables to use in the UMD build</span>
        <span class="hljs-comment">// for externalized deps</span>
        <span class="hljs-attr">globals</span>: {
          <span class="hljs-attr">vue</span>: <span class="hljs-string">"Vue"</span>,
        },
      },
    },
  },
});
</code></pre>
<p>Here is the <code>package.json</code> file. We need to make sure we have the properties necessary for pointing to our built files. For more information on what each property does, you can hover over them in VS Code.</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"brian-component-lib"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
  <span class="hljs-attr">"type"</span>: <span class="hljs-string">"module"</span>,
  <span class="hljs-attr">"files"</span>: [<span class="hljs-string">"dist"</span>],
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"./dist/brian-component-lib.umd.cjs"</span>,
  <span class="hljs-attr">"module"</span>: <span class="hljs-string">"./dist/brian-component-lib.js"</span>,
  <span class="hljs-attr">"exports"</span>: {
    <span class="hljs-attr">"."</span>: {
      <span class="hljs-attr">"import"</span>: <span class="hljs-string">"./dist/brian-component-lib.js"</span>,
      <span class="hljs-attr">"require"</span>: <span class="hljs-string">"./dist/brian-component-lib.umd.cjs"</span>
    },
    <span class="hljs-attr">"./style.css"</span>: <span class="hljs-string">"./dist/style.css"</span>
  },
  <span class="hljs-attr">"types"</span>: <span class="hljs-string">"./dist/index.d.ts"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"vite"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"vite build &amp;&amp; vue-tsc --emitDeclarationOnly"</span>,
    <span class="hljs-attr">"types"</span>: <span class="hljs-string">"vue-tsc "</span>,
    <span class="hljs-attr">"preview"</span>: <span class="hljs-string">"vite preview"</span>
  },
  <span class="hljs-attr">"dependencies"</span>: {
    <span class="hljs-attr">"vue"</span>: <span class="hljs-string">"^3.2.47"</span>
  },
  <span class="hljs-attr">"devDependencies"</span>: {
    <span class="hljs-attr">"@types/node"</span>: <span class="hljs-string">"^20.2.5"</span>,
    <span class="hljs-attr">"@vitejs/plugin-vue"</span>: <span class="hljs-string">"^4.2.3"</span>,
    <span class="hljs-attr">"typescript"</span>: <span class="hljs-string">"^5.0.2"</span>,
    <span class="hljs-attr">"vite"</span>: <span class="hljs-string">"^4.3.9"</span>,
    <span class="hljs-attr">"vue-tsc"</span>: <span class="hljs-string">"^1.4.2"</span>
  }
}
</code></pre>
<p>In order for the <code>vue-tsc --emitDeclarationOnly</code> to work when building, we need to add the following properties to the <code>compilerOptions</code> section of the tsconfig.json file:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"outDir"</span>: <span class="hljs-string">"dist"</span>,
<span class="hljs-string">"declaration"</span>: <span class="hljs-literal">true</span>,
</code></pre>
<p>We will also need to remove the <code>noEmit: true</code> property. This will make it so our types are available in the package, so a project using TypeScript with Vue doesn't yell at us for not having declared types.</p>
<p>I also added this line to make sure my <code>App.vue</code> and <code>main.ts</code> file aren't included in the component library built files.</p>
<p><code>"exclude": ["src/App.vue", "src/main.ts"],</code></p>
<h2 id="heading-test-the-library">Test the Library</h2>
<p>We can now run <code>npm run build</code> and then test out our library. To do this, open up a Vue project (you can open a current Vue 3 project you have, or create a blank one).</p>
<p>Inside the package.json file for the project you just opened add the following to the dependencies:</p>
<p><code>"brian-component-lib": "file:../brian-component-library"</code></p>
<p>Make sure the file path you put in points to the correct folder where the component library lives.</p>
<p>Run <code>npm install</code> and you should now have the component library in your <code>node_modules</code>.</p>
<p>Import the component into one of the pages to test that it is working.</p>
<p>Note: You will need to also import the CSS because it gets built to its own file during the build process.</p>
<pre><code class="lang-js">&lt;script setup lang=<span class="hljs-string">"ts"</span>&gt;
<span class="hljs-keyword">import</span> { FccButton } <span class="hljs-keyword">from</span> <span class="hljs-string">'brian-component-lib'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"brian-component-lib/style.css"</span>
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">FccButton</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"Run the Tests"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span></span>
</code></pre>
<p>You should now see the button when you run the project.</p>
<h2 id="heading-how-to-publish-to-npm">How to Publish to NPM</h2>
<p>If you haven't signed into NPM inside your terminal you can do that by running the <code>npm adduser</code> command.</p>
<p>Then just run the <code>npm publish</code> command and the package should be pushed up and made available on NPM.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Vite makes it pretty easy to get a component library published. Hopefully this helped. <a target="_blank" href="https://twitter.com/the_brianb">Let me know on Twitter</a> if it did or if you'd like to see something else from me in the future.</p>
<p>You can see the repository for this code here: <a target="_blank" href="https://github.com/briancbarrow/vue-component-library-2023">https://github.com/briancbarrow/vue-component-library-2023</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Modern Documentation Site with VitePress ]]>
                </title>
                <description>
                    <![CDATA[ By Victor Eke Documentation is a crucial aspect of software development. But developers often neglect it because it can be a hassle to maintain. This is why it's important to use tools that help simplify this process.  In this tutorial, you'll learn ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-modern-documentation-site-with-vitepress/</link>
                <guid isPermaLink="false">66d4617738f2dc3808b79115</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vite ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 16 Nov 2022 17:01:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/How-to-build-a-modern-documentation-site-with-vitepress-by-Victor-Eke.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Victor Eke</p>
<p>Documentation is a crucial aspect of software development. But developers often neglect it because it can be a hassle to maintain. This is why it's important to use tools that help simplify this process. </p>
<p>In this tutorial, you'll learn how to build a complete docs site quickly by utilizing a modern tool called VitePress.</p>
<h2 id="heading-what-is-vitepress">What is VitePress?</h2>
<p><a target="_blank" href="https://vitepress.vuejs.org/">VitePress</a> is a simple and performant static site generator built on top of <a target="_blank" href="https://vitejs.dev">Vite</a> that lets you create docs in a matter of minutes. It is powered by V<a target="_blank" href="https://vuejs.org/">uejs</a> and Vite with built-in customizable components. </p>
<p>VitePress powers some popular documentation sites like Vuejs, V<a target="_blank" href="https://vitest.dev/">itest</a>, <a target="_blank" href="https://faker.js/dev">faker.js</a>, and Vite itself.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial, you need to have a basic understanding of the following:</p>
<ul>
<li><a target="_blank" href="https://daringfireball.net/projects/markdown/">Markdown</a> syntax</li>
<li>Basic understanding of NPM and Vite</li>
</ul>
<p>Here's a screenshot of what you'll build by the end of this tutorial:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/final-works-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Want to play around with it? Check out the <a target="_blank" href="http://adocs.vercel.app/">live demo</a>. Also, the source code for this can be found on <a target="_blank" href="https://github.com/Evavic44/adocs">GitHub</a>.</p>
<h2 id="heading-step-1-create-a-new-project">Step 1: Create a New Project</h2>
<p>If you already have a folder created, you can skip this step and go on to the next one. If not, use the following command to create a project folder and move into the folder.</p>
<pre><code class="lang-bash">mkdir project-name
<span class="hljs-built_in">cd</span> project-name
</code></pre>
<p>Next you need to initialize the project with your preferred package manager. I'll be using NPM for the rest of this guide.</p>
<pre><code class="lang-js">npm init
<span class="hljs-comment">// or use this command if you want to skip all the questions</span>
npm init -y
</code></pre>
<p>If you used the first command, you'll be prompted with certain questions, so just complete them as appropriate. </p>
<p>After a successful operation, you should have a <code>package.json</code> file in your root directory. This is where the VitePress dev dependency will be installed.</p>
<h2 id="heading-step-2-install-vitepress">Step 2: Install VitePress</h2>
<p>The next step is to add VitePress and Vue as dev dependencies to your project, like this:</p>
<pre><code class="lang-bash">npm install --dev vitepress vue
</code></pre>
<p>You've successfully installed VitePress and Vue and added them as dev dependencies. Now you can start creating creating your respective doc files. </p>
<p>But before you do that, I believe it's essential to explain how VitePress works.</p>
<h2 id="heading-how-does-vitepress-vork">How Does VitePress Vork?</h2>
<p>VitePress makes use of Markdown <code>.md</code> files for its markup which is automatically converted into static HTML. In other for this to work, a special folder called <code>docs</code> gets created in the root directory.</p>
<p>This folder behaves similarly to the <code>pages</code> folder in NextJS, where any <code>.js</code> file created in the directory is automatically treated as a web page. In this case a file called <code>index.md</code> will be the treated as <code>index.html</code> and serve as the root of your docs template.</p>
<p>Now that you understand how that works, you can create your respective doc files.</p>
<h2 id="heading-step-3-create-the-respective-doc-files">Step 3: Create the Respective Doc Files</h2>
<p>You can create the docs folder and the <code>index.md</code> file manually, or you can do it with the terminal like a hacker.</p>
<pre><code class="lang-bash">mkdir docs &amp;&amp; <span class="hljs-built_in">echo</span> <span class="hljs-string">'# Hello VitePress'</span> &gt; docs/index.md
</code></pre>
<p>This command simply creates a folder called <code>docs</code> and adds an <code>index.md</code> file containing a <code>h1</code> element that says "Hello World". </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/create-respective-files.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>With this, you can boot up your dev environment to see what has been created so far.</p>
<h2 id="heading-step-4-boot-up-your-dev-environment">Step 4: Boot Up Your Dev Environment</h2>
<p>In order to run your docs locally, you need to add the following scripts inside the <code>package.json</code> file. Simply copy the code below and replace the <code>"script"</code> object with it:</p>
<pre><code class="lang-js"><span class="hljs-comment">// package.json</span>
<span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"docs:dev"</span>: <span class="hljs-string">"vitepress dev docs"</span>,
    <span class="hljs-string">"docs:build"</span>: <span class="hljs-string">"vitepress build docs"</span>,
    <span class="hljs-string">"docs:serve"</span>: <span class="hljs-string">"vitepress serve docs"</span>
  },
</code></pre>
<p>Finally, the documentation site can be served on a local server by running the command below:</p>
<pre><code class="lang-bash">npm run docs:dev
</code></pre>
<p>This will start a hot-reloading development server at <code>http://localhost:5173</code>, and you can visit it to see your docs site.</p>
<p>Here's the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/boot-dev-server.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>All you had to do was add the markup and VitePress handled the appearance from its template engine. In the next session, you'll learn how you can customize the docs to fit your needs.</p>
<h2 id="heading-how-to-customize-your-docs-with-vitepress">How to Customize Your Docs with VitePress</h2>
<p>First create a <code>.vitepress</code> folder inside the docs directory you created earlier on. This is where all VitePress-specific files will be placed. </p>
<p>Inside this new directory, you need a <code>config.js</code> file. Again, you can use the terminal command like so:</p>
<pre><code class="lang-bash">mkdir .vitepress &amp;&amp; touch .vitepress/config.js
</code></pre>
<p>To test this config file, you can start by changing the meta title and description of your docs site. Copy this markup and paste into the <code>config.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-comment">// .vitepress/config.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">title</span>: <span class="hljs-string">'Adocs'</span>,
  <span class="hljs-attr">description</span>: <span class="hljs-string">'An awesome docs template built by me'</span>
}
</code></pre>
<p>If you check the dev tools, you should see the changes in the meta title and description.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/title-and-description.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-update-the-title-and-logo">How to Update the Title and Logo</h3>
<p>In order to change the logo title and add an image, copy the markup below and paste it into a new object called <code>themeConfig</code> inside the same <code>config.js</code> file. This will overwrite the current title and add a logo to your docs site.</p>
<pre><code class="lang-js"><span class="hljs-comment">// config.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">themeConfig</span>: {
    <span class="hljs-attr">logo</span>: <span class="hljs-string">"/logo.svg"</span>,
    <span class="hljs-attr">siteTitle</span>: <span class="hljs-string">"Adocs"</span>,
  },
};
</code></pre>
<p>For the image source, you can pass in an image URL or specify the path to a local image. To do it locally, make sure you place the image within the <code>public</code> directory.</p>
<p>Here's the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/logo-and-title.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Note that files in the public directory are served at the root path. So instead of ../public/logo.svg, just use /logo.svg.</p>
<h3 id="heading-how-to-customize-the-navbar">How to Customize the Navbar</h3>
<p>Customizing the <code>Navbar</code> is a pretty straightforward process as well. Inside your <code>themeConfig</code> file, paste the markup below. Here we have an object that contains two properties: the anchor text <code>text</code>, and the path <code>link</code> defines the URL path.</p>
<pre><code class="lang-js"><span class="hljs-comment">// .vitepress/config.js</span>
{  
  <span class="hljs-comment">// ...</span>
   <span class="hljs-attr">nav</span>: [
    { <span class="hljs-attr">text</span>: <span class="hljs-string">"About"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/about"</span> },
    { <span class="hljs-attr">text</span>: <span class="hljs-string">"Contact"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/contact"</span> },
    { <span class="hljs-attr">text</span>: <span class="hljs-string">"Guide"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/guide"</span> },
    { <span class="hljs-attr">text</span>: <span class="hljs-string">"Configs"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/configs"</span> },
    { <span class="hljs-attr">text</span>: <span class="hljs-string">"Changelog"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"https://github.com/..."</span> },
  ],
  <span class="hljs-comment">// ...     </span>
}
</code></pre>
<p>Essentially navigating to <a target="_blank" href="http://localhost:5173/about">localhost:5173/about</a> should take you to an about page (though we haven't created that yet).</p>
<p>Here's the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/navigaiton-menu.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Navigation links can also be dropdown menus, too. To add one, simply replace any of the <code>links</code> property with the items object which contains an array of links.</p>
<pre><code class="lang-js"><span class="hljs-comment">// .vitepress/config.js</span>
{
  <span class="hljs-attr">text</span>: <span class="hljs-string">"Changelog"</span>,
  <span class="hljs-attr">items</span>: [
   { <span class="hljs-attr">text</span>: <span class="hljs-string">"v0.0.1"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/item-1"</span> },
   { <span class="hljs-attr">text</span>: <span class="hljs-string">"v0.0.2"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/item-2"</span> },
   { <span class="hljs-attr">text</span>: <span class="hljs-string">"v0.0.3"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/item-3"</span> },
  ],
},
</code></pre>
<p>Now the changelog will become a dropdown menu with the respective links you pass inside.</p>
<p>Here's the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/dropdown-menu.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-add-social-icons">How to Add Social Icons</h3>
<p>Navigation menus usually have social icons that visitors can use to visit your social platforms. To add them, define a new object called <code>socialLinks</code> inside <code>themeConfig</code> and simply pass in the social icon and the link you want it to navigate to.</p>
<pre><code class="lang-js"><span class="hljs-comment">// .vitepress/config.js</span>
<span class="hljs-attr">socialLinks</span>: [
  { <span class="hljs-attr">icon</span>: <span class="hljs-string">"github"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"https://github.com/Evavic44/adocs"</span> },
  { <span class="hljs-attr">icon</span>: <span class="hljs-string">"twitter"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"https://twitter.com/victorekea"</span> },
  { <span class="hljs-attr">icon</span>: <span class="hljs-string">"discord"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"..."</span> },
]
</code></pre>
<p>By default, only 8 icons (Discord, Facebook, GitHub, Instagram, LinkedIn, Slack, Twitter, and YouTube) are provided. If you want to add a custom icon, use the SVG property to define an svg image. You can get free icons from <a target="_blank" href="https://icones.js.org/">icones.js.org</a>.</p>
<p>For example, here's a snippet of the <code>apple</code> icon. </p>
<pre><code class="lang-js">{
  <span class="hljs-attr">icon</span>: {
    <span class="hljs-attr">svg</span>: <span class="hljs-string">'&lt;svg role="img" width="26.01" height="32" viewBox="0 0 256 315"&gt;&lt;path d="M213.803 167.03c.442 47.58 41.74 63.413 42.197 63.615c-.35 1.116-6.599 22.563-21.757 44.716c-13.104 19.153-26.705 38.235-48.13 38.63c-21.05.388-27.82-12.483-51.888-12.483c-24.061 0-31.582 12.088-51.51 12.871c-20.68.783-36.428-20.71-49.64-39.793c-27-39.033-47.633-110.3-19.928-158.406c13.763-23.89 38.36-39.017 65.056-39.405c20.307-.387 39.475 13.662 51.889 13.662c12.406 0 35.699-16.895 60.186-14.414c10.25.427 39.026 4.14 57.503 31.186c-1.49.923-34.335 20.044-33.978 59.822M174.24 50.199c10.98-13.29 18.369-31.79 16.353-50.199c-15.826.636-34.962 10.546-46.314 23.828c-10.173 11.763-19.082 30.589-16.678 48.633c17.64 1.365 35.66-8.964 46.64-22.262"/&gt;&lt;/svg&gt;'</span>,
    },
  <span class="hljs-attr">link</span>: <span class="hljs-string">"https://www.apple.com/"</span>,
},
</code></pre>
<p>For custom SVG icons, make sure you add the <code>role="img"</code> property to the <code>svg</code> tag, as this allows the string convert it properly.</p>
<p>Here's the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/social-icons.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-add-a-sidebar">How to Add a Sidebar</h3>
<p>VitePress also comes with built-in components like sidebar menus. To add a sidebar, create an object called <code>sidebar</code> and inside it, add nested objects that take in three values: the nested title, collapsible functionality (default is set to true), and the nested links.</p>
<pre><code class="lang-js"><span class="hljs-comment">// .vitepress/config.js</span>
<span class="hljs-attr">sidebar</span>: [
    {
      <span class="hljs-attr">text</span>: <span class="hljs-string">"Section A"</span>,
      <span class="hljs-attr">collapsible</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">items</span>: [
        { <span class="hljs-attr">text</span>: <span class="hljs-string">"Introduction"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/introduction"</span> },
        { <span class="hljs-attr">text</span>: <span class="hljs-string">"Getting Started"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/getting-started"</span> },
      ],
    },
    {
      <span class="hljs-attr">text</span>: <span class="hljs-string">"Section B"</span>,
      <span class="hljs-attr">collapsible</span>: <span class="hljs-literal">false</span>,
      <span class="hljs-attr">items</span>: [
        { <span class="hljs-attr">text</span>: <span class="hljs-string">"Introduction"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/introduction"</span> },
        { <span class="hljs-attr">text</span>: <span class="hljs-string">"Getting Started"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/getting-started"</span> },
      ],
    },
    {
      <span class="hljs-attr">text</span>: <span class="hljs-string">"Section C"</span>,
      <span class="hljs-attr">collapsible</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">items</span>: [
        { <span class="hljs-attr">text</span>: <span class="hljs-string">"Introduction"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/introduction"</span> },
        { <span class="hljs-attr">text</span>: <span class="hljs-string">"Getting Started"</span>, <span class="hljs-attr">link</span>: <span class="hljs-string">"/getting-started"</span> },
      ],
    },
  ],
</code></pre>
<p>By adding <code>collapsible: "true"</code> to the sidebar object, it shows a toggle button to hide/show each section. You can create as many sections as you want.</p>
<p>Here's the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/sidebar-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You can see section B is not collapsible, and we have that nice next page button on the bottom of the page.</p>
<h3 id="heading-how-to-set-up-page-routing">How to Set Up Page Routing</h3>
<p>As explained earlier, VitePress automatically converts every <code>.md</code> file inside the root of the docs directory to static HTML that can be accessed in the address bar. For instance the <code>index.md</code> is converted to <code>index.html</code>, and <code>about.md</code>, <code>about.html</code> and so on. </p>
<p>Since you've created your nav links and pointed them to their respective URLs, you can access these pages easily by creating them.</p>
<pre><code>docs/
├── .vitepress/
│   └── config.js
├── public/
│   └── logo.svg
├── about.md
├── contact.md
├── guide.md
├── configs.md
└── get-started.md
</code></pre><p>Create these files inside your docs folder and add a simple markup inside them just to see how this works. This page is basic markdown so all your markdown syntax like links, code blocks, headings, and so on works here.</p>
<p>Just for testing purposes, copy this markdown content and paste it inside any of the <code>.md</code> files you just created:</p>
<pre><code class="lang-md"><span class="hljs-section"># About</span>

Welcome to the about page.

This markdown supports html elements like the <span class="hljs-code">`p`</span> tag coupled with inline styles

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"color: #ff7340; border: 1px solid rgba(255, 135, 23, 0.25); border-radius:5px; padding: 1rem;"</span>&gt;</span></span>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.<span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>

Even satire code snippets with syntax highlighting are also supported. 😅

<span class="hljs-code">```js
const lang = prompt("What is your favorite programming language?");

(lang === "JavaScript") | (lang === "javascript") | (lang === "js")
  ? alert("JavaScript to the world! 🚀🟡")
  : alert(`We don't permit such languages here 💩`);</span>
</code></pre>
<p>Of course, images are not left out.</p>
<p><img src="/logo.svg" alt="adocs logo" width="600" height="400" loading="lazy"></p>
<pre><code>
Here<span class="hljs-string">'s the output:

![Image](https://www.freecodecamp.org/news/content/images/2022/11/page-routing-2.gif)

Great! You'</span>ve set-up the docs, added a navigation menu <span class="hljs-keyword">with</span> a dropdown feature, added a sidebar, and customized the links to navigate to different pages. Next up, <span class="hljs-keyword">let</span><span class="hljs-string">'s work on the home page.

## How to Customize the Homepage

Just like every other component, VitePress provides us with markup for building the homepage. I'</span>ve broken it down into three parts: Hero, features, and footer section.

### The Hero Section

First, we<span class="hljs-string">'ll start with the hero section. Replace the Hello World text in the `index.md` page with the following markup:

```yml
# docs/index.md
---
layout: home

hero:
  name: Adocs
  text: Static docs template built with VitePress.
  image:
    src: /logo-big.svg
    alt: Adocs logo
  tagline: A free to use template for creating docs for your projects
  actions:
    - theme: brand
      text: Get Started
      link: /get-started
    - theme: alt
      text: View on GitHub
      link: https://github.com/evavic44/adocs-template
---</span>
</code></pre><h3 id="heading-the-features-section">The Features Section</h3>
<p>Additionally, you can add a features section after the hero section. Simply paste the code below under the hero objects:</p>
<pre><code class="lang-yml"><span class="hljs-comment"># /docs/index.md</span>
<span class="hljs-meta">---</span>
<span class="hljs-attr">link:</span> <span class="hljs-string">https://github.com/evavic44/adocs-template</span>

<span class="hljs-attr">features:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">icon:</span> <span class="hljs-string">⚡️</span>
    <span class="hljs-attr">title:</span> <span class="hljs-string">Adocs,</span> <span class="hljs-string">The</span> <span class="hljs-string">DX</span> <span class="hljs-string">that</span> <span class="hljs-string">can't</span> <span class="hljs-string">be</span> <span class="hljs-string">beat</span>
    <span class="hljs-attr">details:</span> <span class="hljs-string">Lorem</span> <span class="hljs-string">ipsum...</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">icon:</span> <span class="hljs-string">🎉</span>
    <span class="hljs-attr">title:</span> <span class="hljs-string">Power</span> <span class="hljs-string">of</span> <span class="hljs-string">Vue</span> <span class="hljs-string">meets</span> <span class="hljs-string">Markdown</span>
    <span class="hljs-attr">details:</span> <span class="hljs-string">Lorem</span> <span class="hljs-string">ipsum...</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">icon:</span> <span class="hljs-string">🔥</span>
    <span class="hljs-attr">title:</span> <span class="hljs-string">Simple</span> <span class="hljs-string">and</span> <span class="hljs-string">minimal,</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">details:</span> <span class="hljs-string">Lorem</span> <span class="hljs-string">ipsum...</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">icon:</span> <span class="hljs-string">🎀</span>
    <span class="hljs-attr">title:</span> <span class="hljs-string">Stylish</span> <span class="hljs-string">and</span> <span class="hljs-string">cool</span>
    <span class="hljs-attr">details:</span> <span class="hljs-string">Lorem</span> <span class="hljs-string">ipsum...</span>
<span class="hljs-meta">---</span>
</code></pre>
<p>Here's the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/hero-redesign.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-the-footer-section">The Footer Section</h3>
<p>You can add a footer message on the bottom of the page, but this will only show up in the home page.</p>
<p>According to the <a target="_blank" href="https://vitepress.vuejs.org/guide/theme-footer#footer"><em>VitePress</em> docs</a>:</p>
<blockquote>
<p>Note that the footer will not be displayed when the SideBar is visible.</p>
</blockquote>
<p>To add the footer component, go to the <code>config.js</code> file and paste the markup inside the <code>themeConfig</code> object:</p>
<pre><code class="lang-js"><span class="hljs-comment">// .vitepress/config.js</span>
 <span class="hljs-attr">footer</span>: {
   <span class="hljs-attr">message</span>: <span class="hljs-string">"Released under the MIT License."</span>,
   <span class="hljs-attr">copyright</span>: <span class="hljs-string">"Copyright © 2022-present Adocs"</span>,
 },
</code></pre>
<p>Here's the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/footer-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Aside from the markup, you can also customize the components using custom CSS to change things like fonts family, colors, layout, ETC.</p>
<h2 id="heading-how-to-add-custom-css">How to Add Custom CSS</h2>
<p>The default theme <code>CSS</code> is customized by overriding root level CSS variables. If you want, you can check out the <a target="_blank" href="https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css">full list of CSS variables that are customizable</a>. </p>
<p>To do get started, create a <code>.vitepress/theme</code> directory, and inside this theme folder, add an <code>index.js</code> and <code>custom.css</code> file. If you've been following along, you can use the terminal command below to do this quickly:</p>
<pre><code class="lang-bash">mkdir docs/.vitepress/theme &amp;&amp; touch docs/.vitepress/theme/index.js &amp;&amp; touch docs/.vitepress/theme/custom.css
</code></pre>
<p>If you run into any issues with the terminal command, just create the files manually and move on to the next step.</p>
<p>Here's an overview of the folder structure:</p>
<pre><code class="lang-bash">docs/
├── .vitepress/
│   ├── config.js
│   └── theme/
│       ├── index.js
│       └── custom.css
├── public/
│   └── logo.svg
├── about.md
├── contact.md
├── guide.md
├── configs.md
└── get-started.md
</code></pre>
<p>After creating these files, inside the <code>.vitepress/theme/index.js</code> file, paste the import commands:</p>
<pre><code class="lang-js"><span class="hljs-comment">// .vitepress/theme/index.js</span>
<span class="hljs-keyword">import</span> DefaultTheme <span class="hljs-keyword">from</span> <span class="hljs-string">"vitepress/theme"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./custom.css"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DefaultTheme;
</code></pre>
<h3 id="heading-color-theme">Color Theme</h3>
<p>The colors are controlled by the CSS variables. You can simply replace them with any colors you want.</p>
<p>Note that this color has a provision for both light and dark mode. So make sure you change them accordingly.</p>
<p>Here's an example of my custom colors:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* .vitepress/theme/custom.css */</span>

<span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--vp-c-brand</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">255</span>, <span class="hljs-number">115</span>, <span class="hljs-number">64</span>);
  <span class="hljs-attribute">--vp-c-brand-light</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">255</span>, <span class="hljs-number">87</span>, <span class="hljs-number">25</span>);
  <span class="hljs-attribute">--vp-c-brand-lighter</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">255</span>, <span class="hljs-number">115</span>, <span class="hljs-number">64</span>);
  <span class="hljs-attribute">--vp-c-brand-dark</span>: <span class="hljs-number">#FF622D</span>;
  <span class="hljs-attribute">--vp-c-brand-darker</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">226</span>, <span class="hljs-number">60</span>, <span class="hljs-number">0</span>);

  <span class="hljs-attribute">--vp-c-sponsor</span>: <span class="hljs-number">#fd1d7c</span>;
}
</code></pre>
<p>If you don't see the effects immediately, try stopping the server and starting it again.</p>
<p>Aside from the color themes, you can also override other things like font family, typography, layout, breakpoints, and so on.</p>
<h3 id="heading-how-to-use-custom-fonts">How to Use Custom Fonts</h3>
<p>You can import <a target="_blank" href="https://fonts.google.com/">Google fonts</a> inside the CSS file to override the default font family.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-attribute">https:</span>//fonts.googleapis.com/css?family=Space+<span class="hljs-attribute">Mono:</span>regular,italic,<span class="hljs-number">700</span>,<span class="hljs-number">700</span>italic);
<span class="hljs-keyword">@import</span> url(<span class="hljs-attribute">https:</span>//fonts.googleapis.com/css?family=Space+<span class="hljs-attribute">Grotesk:</span>regular,italic,<span class="hljs-number">700</span>,<span class="hljs-number">700</span>italic);

<span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--vp-c-brand</span>: <span class="hljs-number">#ff7340</span>;
  <span class="hljs-attribute">--vp-c-brand-light</span>: <span class="hljs-number">#ff5719</span>;
  <span class="hljs-attribute">--vp-c-brand-lighter</span>: <span class="hljs-number">#ff7340</span>;
  <span class="hljs-attribute">--vp-c-brand-lighter</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">255</span>, <span class="hljs-number">135</span>, <span class="hljs-number">23</span>, <span class="hljs-number">0.25</span>);
  <span class="hljs-attribute">--vp-c-brand-dark</span>: <span class="hljs-number">#ff622d</span>;
  <span class="hljs-attribute">--vp-c-brand-darker</span>: <span class="hljs-number">#e23c00</span>;

  <span class="hljs-attribute">--vp-c-sponsor</span>: <span class="hljs-number">#fd1d7c</span>;

  <span class="hljs-comment">/* Typography */</span>
  <span class="hljs-attribute">--vp-font-family-base</span>: <span class="hljs-string">"Space Grotesk"</span>, <span class="hljs-string">"Inter var experimental"</span>, <span class="hljs-string">"Inter var"</span>,
    -apple-system, BlinkMacSystemFont, <span class="hljs-string">"Segoe UI"</span>, Roboto, Oxygen, Ubuntu,
    Cantarell, <span class="hljs-string">"Fira Sans"</span>, <span class="hljs-string">"Droid Sans"</span>, <span class="hljs-string">"Helvetica Neue"</span>, sans-serif;

  <span class="hljs-comment">/* Code Snippet font */</span>
  <span class="hljs-attribute">--vp-font-family-mono</span>: <span class="hljs-string">"Space Mono"</span>, Menlo, Monaco, Consolas, <span class="hljs-string">"Courier New"</span>,
    monospace;
}
</code></pre>
<p>With the <code>--vp-font-family-base</code> variable you can change the main font and <code>--vp-font-family-mono</code>, the font for code snippets.</p>
<p>Here's the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/final-works.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You've successfully customized the theme and changed the font family using CSS. Though there's more you can do in regards to styling, but at this point, I hope it's clear how you can customize your docs with CSS. </p>
<p>Let's discuss hosting in the next section.</p>
<h2 id="heading-how-to-host-your-doc-site">How to Host Your Doc Site</h2>
<p>You can publish or host your docs site when you're done to different platforms like <a target="_blank" href="https://netlify.com">Netlify</a>, <a target="_blank" href="https://vercel.com">Vercel</a>, <a target="_blank" href="https://aws.com">AWS Amplify</a>, and so on.</p>
<p>First, run the build command:</p>
<pre><code class="lang-bash">npm run docs:build
</code></pre>
<p>This should create a new <code>dist</code> folder that contains all the static files of your docs. </p>
<p>In deciding on what hosting service to use, you can pick any of the options I mentioned earlier but we'll be using Vercel in this guide. Also, feel free to look at other alternatives of your choice. </p>
<p>If you don't have a Vercel account, follow this guide to <a target="_blank" href="https://vercel.com/docs/concepts/get-started/deploy">create one and configure your Git provider</a> before you move on to the next step.</p>
<p>Assuming you've successfully set-up your account and uploaded your docs site to Vercel, navigate to the <strong>project &gt;</strong> <strong>settings</strong> <strong>&gt; build and deploy settings</strong>, and paste the following commands to their respective fields:</p>
<ul>
<li>Build command: <code>npm run docs:build</code> </li>
<li>Output directory:  <code>docs/.vitepress/dist</code></li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/deploy-settings-vercel.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After editing the settings, save them and deploy your site!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you've set-up a full-fledged documentation site and customized it using CSS and VitePress built-in components. </p>
<p>Just keep in mind that this tutorial only covers a fragment of what is possible with VitePress. To learn more, check out the <a target="_blank" href="https://vitepress.vuejs.org">VitePress docs</a>.</p>
<h3 id="heading-additional-reading">Additional Reading</h3>
<p>Here are a few things not covered in this article that I think is also worth looking into:</p>
<ul>
<li><a target="_blank" href="https://vitepress.vuejs.org/guide/markdown#custom-containers">Custom Containers</a></li>
<li><a target="_blank" href="https://vitepress.vuejs.org/guide/using-vue#using-vue-in-markdown">Using Vue in markdown</a></li>
<li><a target="_blank" href="https://vitepress.vuejs.org/guide/theme-team-page">Team Section</a></li>
<li><a target="_blank" href="https://vitepress.vuejs.org/guide/theme-carbon-ads">Carbon Ads</a></li>
</ul>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><a target="_blank" href="https://adocs.vercel.app">Live Demo</a></li>
<li><a target="_blank" href="https://github.com/Evavic44/adocs">GitHub Repo</a></li>
</ul>
<p>If you are an open source fan like myself or you enjoy hearing about such cool projects, do follow me on my socials so you don't miss my next post. Cheers. 🍷</p>
<p><a target="_blank" href="https://github.com/evavic44">GitHub</a> | <a target="_blank" href="https://twitter.com/victorekea">Twitter</a> | <a target="_blank" href="https://eke.hashnode.dev">Blog</a> | <a target="_blank" href="https://victoreke.com">Portfolio</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an OTP Input in Vue 3 ]]>
                </title>
                <description>
                    <![CDATA[ By Paul Akinyemi OTP inputs are one of the most fun components you can use in your app. They make the dry process of filling in yet another form a little more engaging. In this article, you’ll learn how to build an OTP input from scratch in Vue 3. By... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-otp-input-vue-3/</link>
                <guid isPermaLink="false">66d4608db6b7f664236cbe2d</guid>
                
                    <category>
                        <![CDATA[ forms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 24 Aug 2022 15:00:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/otp-article-header.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Paul Akinyemi</p>
<p>OTP inputs are one of the most fun components you can use in your app. They make the dry process of filling in yet another form a little more engaging.</p>
<p>In this article, you’ll learn how to build an OTP input from scratch in Vue 3. By the end of the tutorial, you'll have built an OTP input that looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/finished-otp-demo.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here’s an overview of the steps the tutorial will follow:</p>
<ul>
<li>Project setup</li>
<li>Building the Basics</li>
<li>Adding functionality</li>
<li>Finishing touches</li>
<li>Conclusion</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To easily follow along with this tutorial, you should have the following:</p>
<ul>
<li>A basic understanding of Vue 3 and vanilla JavaScript</li>
<li>Node.js 16+ installed on your machine</li>
<li>A basic knowledge of CSS</li>
</ul>
<h2 id="heading-whats-an-otp-input">What's an OTP Input?</h2>
<p>In case you aren't familiar with the term, an OTP input is a form component for strings. Each character in the string is typed into a separate box, and the component switches between boxes as you type (as opposed to you needing to click into each box). </p>
<p>It's called an OTP input because they're usually used to let users type in an OTP (One Time Password) that they've received via some other channel, usually email or SMS.</p>
<h2 id="heading-project-setup">Project Setup</h2>
<p>This project won't use any external libraries, so all the setup you need is to create a Vue application with <a target="_blank" href="https://vitejs.dev/">Vite</a>.</p>
<p>Create the Vue project by running the following in a terminal window:</p>
<pre><code class="lang-sh">npm init vue@3
</code></pre>
<p>If you haven’t installed <code>create-vue</code> on your device, this command will install it. Next, it will present a series of options to you. The options let you specify the project name and select which add-ons you want to include. </p>
<p>Call the project <code>otp-input</code> and don't select any add-ons, as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/otp-input-install.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After you’ve done that, run:</p>
<pre><code class="lang-sh"><span class="hljs-built_in">cd</span> otp-input
npm install
npm run dev
</code></pre>
<p>After the dev server starts up, you should see something like this in your terminal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/otp-input-finish-setup.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Open the URL Vite gives you in your browser, and let’s get to the fun stuff.</p>
<h2 id="heading-how-to-build-the-basics">How to Build the Basics</h2>
<p>If you open the <code>otp-input</code> folder in your editor, it should have a file structure like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-121.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You’re going to adjust this setup to something more suitable. Start by opening <code>src/App.vue</code> and replacing its contents with this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">template</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">script</span> <span class="hljs-attr">setup</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>Next, select all the files inside <code>src/components</code> and delete them, and create a file inside components called <code>OTP.vue</code>. On Linux/Mac devices, you can do that by running the following in a new terminal window:</p>
<pre><code class="lang-sh">rm -rfv src/components
mkdir src/components
touch src/components/OTP.vue
</code></pre>
<p>Then, delete the <code>src/assets</code> folder, and remove the following line from <code>src/main.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">'./assets/main.css'</span>
</code></pre>
<p>Next, open <code>components/OTP.vue</code>, and put the starting template for your OTP into it:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"otpCont"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
      <span class="hljs-attr">class</span>=<span class="hljs-string">"digit-box"</span>
      <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(el, ind) in digits"</span>
      <span class="hljs-attr">:key</span>=<span class="hljs-string">"el+ind"</span>
      <span class="hljs-attr">v-model</span>=<span class="hljs-string">"digits[ind]"</span>
      <span class="hljs-attr">:autofocus</span>=<span class="hljs-string">"ind === 0"</span>
      <span class="hljs-attr">:placeholder</span>=<span class="hljs-string">"ind+1"</span>
      <span class="hljs-attr">maxlength</span>=<span class="hljs-string">"1"</span>
    &gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<p>Let’s explain this.</p>
<p>The template starts with a container div that you've attached a ref to called <code>otpCont</code>. Inside the container, you have a text input with a <code>v-for</code> on it. The <code>v-for</code> will render one input for each element of a collection we called <code>digits</code>, and attach a two-way binding with the element of <code>digits</code> that shares its index. </p>
<p>The first rendered input will have the <code>autofocus</code> attribute, the placeholder for each input is its index plus one, and each input has a maximum length of one character.</p>
<p>Next is the script for the component. Place the following code into <code>OTP.vue</code>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">setup</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">import</span> { ref, reactive } <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>;

  <span class="hljs-keyword">const</span> props = defineProps({
    <span class="hljs-attr">default</span>: <span class="hljs-built_in">String</span>,

    <span class="hljs-attr">digitCount</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Number</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>
    }
  });

  <span class="hljs-keyword">const</span> digits = reactive([])

  <span class="hljs-keyword">if</span> (props.default &amp;&amp; props.default.length === props.digitCount) {
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i =<span class="hljs-number">0</span>; i &lt; props.digitCount; i++) {
      digits[i] = props.default.charAt(i)
    }
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i =<span class="hljs-number">0</span>; i &lt; props.digitCount; i++) {
      digits[i] = <span class="hljs-literal">null</span>;
    }
  }

  <span class="hljs-keyword">const</span> otpCont = ref(<span class="hljs-literal">null</span>)

</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>After the import, this code defines two props: a required number <code>digitCount</code> that controls the number of inputs, and an optional string <code>default</code>.</p>
<p>Then, it creates the reactive <code>digits</code> array the template needs. If the <code>default</code> prop was provided and its length matches the <code>digitCount</code> prop, <code>digits</code> is initialized using the characters in <code>default</code>. If not the elements of <code>digits</code> are filled with <code>null</code>.</p>
<p>Finally, the code creates the <code>otpCont</code> reference from the template.</p>
<p>The last task for this section is to give the inputs a bit of styling. Put the following at the end of <code>OTP.vue</code>:</p>
<pre><code class="lang-html"><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-class">.digit-box</span> {
    <span class="hljs-attribute">height</span>: <span class="hljs-number">4rem</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">2rem</span>;
    <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid black;
    <span class="hljs-attribute">display</span>: inline-block;
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">5px</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
}

<span class="hljs-selector-class">.digit-box</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">outline</span>: <span class="hljs-number">3px</span> solid black;
}

</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>And that creates the basic form of your OTP.</p>
<p>Next, you’re going to edit the home page of your app to render the input. Replace the contents of  <code>src/App.vue</code> with the following:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">otp</span> 
    <span class="hljs-attr">:digit-count</span>=<span class="hljs-string">"4"</span>
  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">otp</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">script</span> <span class="hljs-attr">setup</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> otp <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/OTP.vue"</span>;
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>If you open the app in the browser, you should see the separate inputs rendered like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/otp-init-form.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-add-functionality">How to Add Functionality</h2>
<p>Right now, you don’t really have an OTP input yet. You need to manually switch focus between fields, and there’s no validation. Next, you’ll write the logic to fix that.</p>
<p>Open <code>components/OTP.vue</code>, and add a keydown event handler to the input tag:</p>
<pre><code class="lang-js"> @keydown=<span class="hljs-string">"handleKeyDown($event, ind)"</span>
</code></pre>
<p>Now, create the <code>handleKeyDown</code> function at the end of the <code>script setup</code> section like so:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleKeyDown = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event, index</span>) </span>{
    <span class="hljs-keyword">if</span> (event.key !== <span class="hljs-string">"Tab"</span> &amp;&amp; 
        event.key !== <span class="hljs-string">"ArrowRight"</span> &amp;&amp;
        event.key !== <span class="hljs-string">"ArrowLeft"</span>
    ) {
      event.preventDefault();
    }

    <span class="hljs-keyword">if</span> (event.key === <span class="hljs-string">"Backspace"</span>) {
      digits[index] = <span class="hljs-literal">null</span>;

      <span class="hljs-keyword">if</span> (index != <span class="hljs-number">0</span>) {
        (otpCont.value.children)[index<span class="hljs-number">-1</span>].focus();
      } 

      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">if</span> ((<span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">'^([0-9])$'</span>)).test(event.key)) {
      digits[index] = event.key;

      <span class="hljs-keyword">if</span> (index != props.digitCount - <span class="hljs-number">1</span>) {
        (otpCont.value.children)[index+<span class="hljs-number">1</span>].focus();
      }
    }
  }
</code></pre>
<p>Let’s break down this function. The event handler is called every time a key is pressed while one of the input fields is in focus.</p>
<p>If the pressed key isn’t tab or one of the horizontal arrow keys, the function will call <code>preventDefault()</code>, and move to the next if block.</p>
<p>If the pressed key was Backspace, the value of the <code>digit</code> array at the index of the target input will be set to null. Then if the target input wasn’t the first input, the code shifts focus to its previous sibling.</p>
<p>The last if block uses a regular expression to test if the pressed key was one of the digits 0 to 9. If it was, <code>digits</code> is updated appropriately, and focus is shifted to the next input.</p>
<p>If you open the app in your browser now, you should see that the OTP input automatically shifts focus between the boxes. Also, it only accepts numbers as input, and you can use the tab key to navigate between boxes:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/midway-otp-demo.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-add-the-finishing-touches">Add the Finishing Touches</h2>
<p>The OTP input is now mostly complete, but it feels a little plain. Let’s add a last set of features:</p>
<ul>
<li>The input should emit the OTP value once all fields are filled.</li>
<li>A small bounce animation should trigger when the user enters a value.</li>
</ul>
<p>We’ll start with the logic for emitting the OTP value. First, you'll modify <code>App.vue</code> so it can display the emitted value. Replace the contents of <code>App.vue</code> with the following:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">otp</span> 
    <span class="hljs-attr">:digit-count</span>=<span class="hljs-string">"4"</span>
    @<span class="hljs-attr">update:otp</span>=<span class="hljs-string">"otpValue = $event"</span>
  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">otp</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>The current OTP value is: {{ otpValue }} <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">script</span> <span class="hljs-attr">setup</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> otp <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/OTP.vue"</span>;
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

otpValue = ref(<span class="hljs-string">''</span>)
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Not much has changed: you just created a reactive variable called <code>otpValue</code>, told the template to render it, and added an event listener to the OTP component to update <code>otpValue</code>.</p>
<p>Next, open <code>components/OTP.vue</code> and add the following code just before the <code>handleKeyDown</code> function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> emit = defineEmits([<span class="hljs-string">'update:otp'</span>]);

<span class="hljs-keyword">const</span> isDigitsFull = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> elem <span class="hljs-keyword">of</span> digits) {
    <span class="hljs-keyword">if</span> (elem == <span class="hljs-literal">null</span> || elem == <span class="hljs-literal">undefined</span>) {
      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }
  }

  <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
</code></pre>
<p>This code defines the custom event <code>update:otp</code>, as well as a function <code>isDigitsFull</code> . <code>isDigitsFull</code> returns <code>false</code> if there’s any <code>null</code> value inside <code>digits</code> and <code>true</code> otherwise.</p>
<p>Add the following to <code>handleKeyDown</code> at the end of the last if block:</p>
<pre><code class="lang-js"><span class="hljs-keyword">if</span> (isDigitsFull()) {
  emit(<span class="hljs-string">'update:otp'</span>, digits.join(<span class="hljs-string">''</span>))
}
</code></pre>
<p>Each time a digit is pressed in an input box, this code calls the helper function <code>isDigitsFull</code> to determine if all the input boxes are filled.</p>
<p>If they are, it emits the <code>update:otp</code> event, combines the value of all input boxes to a single string, and sends it as the value of the event.</p>
<p>Your rendered page in the browser should now display the most recent (complete) OTP value:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/otp-semifinished-demo.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Finally, you’ll add animation to your OTP input. Paste the following CSS at the end of the style tag in <code>components/OTP.vue</code>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.bounce</span> {
  <span class="hljs-attribute">animation</span>: pulse .<span class="hljs-number">3s</span> ease-in-out alternate;
}

<span class="hljs-keyword">@keyframes</span> pulse {
  0% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1</span>);
  }

  100% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1.1</span>);
  }
}
</code></pre>
<p>And then add the following class binding to the input in the template:</p>
<pre><code class="lang-js">:<span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"{bounce: digits[ind] !== null}"</span>
</code></pre>
<p>And that’s the code for the animation! Here’s how it works:</p>
<ul>
<li>The bounce class for each input is tied to <code>digits[index]</code></li>
<li>If the value of <code>digits[index]</code> <em>changes</em>, the expression is evaluated again</li>
<li>If the new value isn’t null, the bounce class gets applied</li>
<li>If it’s null, the bounce class is removed</li>
<li>If the value doesn’t change, the expression isn’t re-evaluated, so the animation doesn’t trigger.</li>
</ul>
<p>Here’s the final look of your OTP:  </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/finished-otp-demo-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And you’re done!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to build an OTP input from scratch in Vue 3. You can find the source code for this component <a target="_blank" href="https://github.com/Morgenstern2573/otp-input">here</a>. I hope you enjoyed the read!</p>
<p>If you'd like to see more of my writing, you can follow me on <a target="_blank" href="https://twitter.com/apexPaul09">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What I Learned Speaking at VueConf US 2022 – Tech Conference Guide ]]>
                </title>
                <description>
                    <![CDATA[ By Austin Gil This year I had the honor of speaking at VueConf US 2022 and I thought I would share my experience.  Part of this article will cover my personal process, part will look at VueConf specifically, and the rest will be about the conference ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-i-learned-speaking-at-vueconf-us/</link>
                <guid isPermaLink="false">66d45da4787a2a3b05af4380</guid>
                
                    <category>
                        <![CDATA[ community ]]>
                    </category>
                
                    <category>
                        <![CDATA[ community building ]]>
                    </category>
                
                    <category>
                        <![CDATA[ conference ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 18 Aug 2022 19:51:22 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/Vue-Blog-Cover-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Austin Gil</p>
<p>This year I had the honor of speaking at <a target="_blank" href="https://us.vuejs.org/">VueConf US 2022</a> and I thought I would share my experience. </p>
<p>Part of this article will cover my personal process, part will look at VueConf specifically, and the rest will be about the conference at large. I hope you enjoy it.</p>
<h2 id="heading-how-to-get-into-vueconf">How to Get into VueConf</h2>
<h3 id="heading-call-for-papers">Call For Papers</h3>
<p>Let's start at the beginning, as that's a good place to start. As soon as VueConf announced the Call for Papers (CFPs), I submitted my talks. I had submitted a few, and the one they selected was called, "<a target="_blank" href="https://www.vuemastery.com/conferences/vueconf-us-2022/maintainable-and-resilient-projects-through-internal-ui-libraries/">Maintainable &amp; Resilient Projects Through Internal UI Libraries</a>".</p>
<p>I submitted other talks that I thought had a better chance, but they selected this one, which turned out really well.</p>
<p>The submission process the conference uses is a Google Form. There's nothing wrong with that, but I've noticed that some other conferences use <a target="_blank" href="https://sessionize.com/">Sessionize</a> or <a target="_blank" href="https://www.papercall.io/">PaperCall</a> which I prefer because you can have an account with your details that pre-fills the forms. With the Google Form, I had to re-type a lot of the same data each time (my life is so hard).</p>
<p>It's not a huge deal, but I mention it in case you're a conference organizer. Those dedicated platforms are pretty sweet. :)</p>
<p>After several weeks, maybe a month, I got the email that I'd been selected. Yay! That gave me plenty of time to prepare. </p>
<p>If you're thinking about speaking at a conference, here's my advice:</p>
<ul>
<li>Submit several talks. You're not limited to just one.</li>
<li>Find out who the organizers are and connect with them. They don't only pick their friends, but it doesn't hurt if they recognize you.</li>
<li>Try giving your talks ahead of time at meetups. It'll get nerves out, works out kinks, and gets you some good feedback.</li>
<li>Make your talk stand out. Probably the most important thing is that you need to take time to create a title, pitch, and description that will get the attention of the organizers AND the audience. Communicate the value succinctly.</li>
<li><strong>Do it</strong>! It's a great way to connect with people and potential future employers.</li>
</ul>
<p>Also, shout out to <a target="_blank" href="https://twitter.com/wesbos">Wes Bos</a> and <a target="_blank" href="https://twitter.com/stolinski">Scott Tolinski</a> for giving some good tips on a recent <a target="_blank" href="https://syntax.fm/show/480/10-years-of-speaking-conferences">Syntax.fm episode</a>.</p>
<p>After being selected, there was the matter of convincing my boss that our company should sponsor my trip.</p>
<h3 id="heading-how-to-convince-your-boss">How to Convince Your Boss</h3>
<p>Some conferences will actually cover flights, accommodations, and even pay speakers. I think it's far more common to cover all the expenses yourself, minus the entry. This means either paying for everything out of pocket, or having your company sponsor your trip (heck yeah!).</p>
<p>Convincing your company to send you to a conference can be tricky because it has to be worth it for them. That's not always easy to prove. If you're presenting, it's better because that could provide an opportunity to promote the company or engage with your community.</p>
<p>Of course, this is going to vary greatly based on your company, their budget, the nature of your role, your team, and your workload. </p>
<p>As a developer advocate, it's a lot more typical for me to go to conferences now, but there's a greater expectation for me to speak, run a booth, host some sort of gathering, and create content (ahem).</p>
<p>Some companies are really good about conference policies, others not so much. One cool thing VueConf does that's really cool is provide folks with a <a target="_blank" href="https://paper.dropbox.com/doc/Convince-Your-Boss-VueConfUS-2022-9T1Rjt4t2POm2O7aKpQ3U">"convince your boss" template</a> that you can copy and fill out with your own details.</p>
<p>I didn't use the template, but they do cover some things that I recommend. In particular, doing the research ahead of time for how much it's going to cost (tickets, flight, accommodation, meals, other travel, and so on) is a good idea.</p>
<p>Something else that helps is arranging to create content or a presentation that you can bring back to your organization. That can help spread your knowledge around and get more value for your employer.</p>
<h3 id="heading-how-to-write-the-dang-thing">How to Write the Dang Thing</h3>
<p>Once you know for sure that you're going, you have to also prepare your talk. If you've never written a presentation before, they're a <strong>LOT</strong> of work.</p>
<p>I don't even want to tell you how much time went into this presentation in case my boss reads this post (only kind of joking). That's another unspoken cost of sending someone.</p>
<p>You have to come up with a main concept, write an outline, write the script, find funny GIFs, come up with a new but more relevant title and hope no one notices, start wondering why they even picked you because it's not that good of subject after all, consider calling out sick, <strong>IMPOSTER SYNDROME</strong>, decide you don't care what people think and do it anyway because even if you fail you can always be a goat farmer, practice the talk, realize it's way too long, cut out half of the work you've already done, practice again, halve it again...and this all has to happen the night before your talk because you procrastinated. </p>
<p>And even if you don't you'll still be fiddling with your slides up until 5 minutes before you have to give your talk.</p>
<p>It's exhausting (but worth it).</p>
<h3 id="heading-how-to-write-a-conference-talk">How to Write a Conference Talk</h3>
<p>If your curious about my process for writing a talk, I've been working on it for a while now, and have come up with this little system:</p>
<ol>
<li>Start the content as a blog post.</li>
<li>Create a high level outline.</li>
<li>Shift concepts around into an order that works.</li>
<li>Fill in the gaps for a rough draft.</li>
<li>Copy the content into a markdown file.</li>
<li>Use <a target="_blank" href="https://sli.dev/">Slidev</a> (awesome project by <a target="_blank" href="https://twitter.com/antfu7">Anthony Fu</a>).</li>
<li>Come up with a story arch to make the content a little more interesting.</li>
<li>Fill in text.</li>
<li>Fill in helper graphics (code, charts, img, gifs)</li>
<li>Create speaker notes.</li>
<li>Practice reading through.</li>
<li>Practice reading through with timer.</li>
<li>Practice speaking through.</li>
<li>Practice speaking through with timer (camera optional).</li>
<li>Practice speaking it to <a target="_blank" href="https://www.instagram.com/nuggetthemighty/">Nugget</a>.</li>
</ol>
<p>I like this approach because in the end, I have a nice presentation as well as a rough draft for a blog post I can continue with later on. And Slidev is great because I can keep one main theme and reuse it for most of my presentations.</p>
<h2 id="heading-what-vueconf-is-like">What VueConf is Like</h2>
<h3 id="heading-the-check-in-process">The Check-in Process</h3>
<p>I arrived on the first day to help <a target="_blank" href="https://twitter.com/_jessicasachs">Jessica Sachs</a> give her workshop, "Stress-free Testing for Vue 3" (she's great and you should take her workshop some time). </p>
<p>The check in process was smooth, and one unique thing they had was a nice color-coded sticker system to communicate peoples preferred greeting: wave, hand-shake/fist-bump, hug. So you could stick it to your name tag to let other folks know your preference.</p>
<p>There wasn't much discussion around COVID protocols, but it's worth mentioning in case any of you are concerned about it. There was around 10 of us wearing masks, which I think goes for most events. It's mostly up to individuals, so if you're still uncomfortable in large groups, it's probably good to stick to the virtual events. I did hear of someone testing positive.</p>
<h3 id="heading-the-people-of-vueconf">The People of VueConf</h3>
<p>Ok, on to some more fun stuff – the people. This is one of my favorite parts of events, you get to meet so many great folks. And Vue folks are among the best!</p>
<p>I was happy to see greater diversity among the attendees than in the past. Like most tech events, it was still mostly men from the same few majority groups, but the gap didn't feel as stark as past events.</p>
<p>It felt like a larger distribution of people across the different race, gender, age, and experience spectrums. It was also represented in the speakers. It's working, people – more colors for our kick-ass rainbow!</p>
<h3 id="heading-how-to-meet-people-at-a-conference">How to meet people at a conference:</h3>
<ul>
<li>Don't hang out with the same people. It's easy to fall into chatting with the same people you know, but it's fun to meet new people and you never know what you'll learn.</li>
<li>People want to meet you. Some people have a harder time initiating a conversation, but are still eager to participate. Keep an eye out for folks and invite them in.</li>
<li>Follow the Pac-Man rule. If you find yourself in a circle of people chatting, always leave a gap for someone to step into. So your circle should look more like a Pac-Man.</li>
<li>Unless you need to recharge, during meals, sit at tables with people you don't know and strike up a conversation. It's great to see the variety of folks around you.</li>
</ul>
<h3 id="heading-vendors-at-conferences">Vendors at Conferences</h3>
<p>I don't spend a lot of time at the vendor booths, but they are super important for supporting events, and it's a good place to see who's taking care of your community. For that reason, I always like to swing by and talk to each vendor at least a little bit.</p>
<p>One thing I would really love to see from vendors is less wasteful swag. There's always so much stuff they give away for free that I'm sure just ends up in waste bins.</p>
<p>Some swag is super effective and a great way to get a brand name out there, but less garbage would also be awesome :)</p>
<h2 id="heading-vueconf-content">VueConf Content</h2>
<p>I thought the talks were well-selected, but they definitely leaned very heavily towards testing. I didn't mind that because each testing talk brought it's own perspective, and it's an important subject.</p>
<p>Not every talk was specific to Vue, which I always appreciate. It's cool to see a broad range of talks, both in the topics represented and in their target experience level. There was also a good range of talks from broad concepts to very specific, personal experiences.</p>
<p>This year I got to experience a workshop as well (as an assistant). I really liked the experience because workshops give you much more time on a single topic to really dive deep and get your hands dirty. And there's way more opportunity for one-on-one time between attendees and instructors.</p>
<p><strong>HOT TIP</strong>: if you know someone putting on a workshop, ask them if they need any help. It got me into a workshop for free, got my friend some extra help, and it got the attendees more individual attention. Triple-win!</p>
<p>VueConf follows a single-track system which means every single talk happens in order, in the same room. This is different than other conferences that do the multi-track approach where there are multiple tracks running simultaneously, with a more dedicated focus.</p>
<p>They each have their pros and cons:</p>
<ul>
<li>Single-track: You know where to go for each talk. You never have to choose between two talks. There's plenty of opportunity to follow the "hallway track" and just chat with folks. You inherently get a little bit of everything.</li>
<li>Multi-track: There's usually way more content to choose from. There's more content for each specific topic. It's less likely to have time slots with nothing that interests you.</li>
</ul>
<p>I don't know if I have a preference, but it's something I thought about.</p>
<p>As mentioned above, one of the presentations was done by yours truly. It was a lot of fun. And despite the overwhelming feeling of impostor syndrome, I felt like I did pretty well. </p>
<p>There were a few points that I could have improved upon or just missed, but I don't think it showed on stage. Some folks even told me it was their favorite talk.</p>
<p>That was really nice...( ˘ ³˘)♥︎♥︎♥(°◡°♡)</p>
<p>It's published on <a target="_blank" href="https://www.vuemastery.com/conferences/vueconf-us-2022/maintainable-and-resilient-projects-through-internal-ui-libraries/">Vue Mastery</a> now. You can find it here: <a target="_blank" href="https://www.vuemastery.com/conferences/vueconf-us-2022/maintainable-and-resilient-projects-through-internal-ui-libraries/">https://www.vuemastery.com/conferences/vueconf-us-2022/maintainable-and-resilient-projects-through-internal-ui-libraries/</a></p>
<p>Would love to hear what you think.</p>
<p>One last little tip/trick I might start doing is to ask organizers if I can give my talk on the first day. I'd rather get it out of the way so I can actually sleep at night and really enjoy the rest of the conference.</p>
<h2 id="heading-in-person-conference-extracurriculars">In-Person Conference Extracurriculars</h2>
<p>In case you've never been to an in-person conference, you should know that post-conference events (parties) are going on probably every night. And it's great! Most of the time it's around grabbing drinks at a bar, but some conferences focus more on networking events.</p>
<p>At VueConf this year, I went to a few events.</p>
<ul>
<li>The first night, after the workshops, there wasn't much because it was technically still before the conference. It was a great chance to catch up with <a target="_blank" href="https://twitter.com/elevatebart">Bart Ledoux</a>.</li>
<li>The second night there was no <strong>official</strong> event because the organizers were hosting the speaker dinner. This consisted of drinks at the hotel pool beforehand, some swimming, and then walking over to a Thai restaurant with amazing Massaman curry. I also got <a target="_blank" href="https://twitter.com/hootlex">Alex Kyriakidis</a> his first Thai tea.</li>
<li>The last night of the conference was spent once again at the hotel pool for swim and drinks, then there was a hosted happy hour with some food and drinks. After everything, we found a karaoke bar for some songs and drinks (there was some drama finding a place, but in true VueConf fashion, we found it).</li>
</ul>
<p>In case it wasn't obvious, a lot of the external events revolve around drinks and/or bars. Which is fine for me because I don't mind a few drinks and can keep myself under control. However, I wish there were more events that focused less around alcohol. It would be more inclusive for folks that prefer not to drink.</p>
<p>Anyway, regardless of the venue/activity, I think it's worth going to as many extra events as you can. They're usually a lot of fun, and are a great way to connect with folks, both professionally and to make new friends. There's so much value there.</p>
<p>Two tips, though:</p>
<ol>
<li>Don't forget to bring your badge to after parties (learned that one the hard way).</li>
<li>Try not to get trashed. Some folks did, and it's a bad look for you and possibly your employer (learned that the easy way).</li>
</ol>
<h2 id="heading-in-closing">In Closing</h2>
<p>Conferences are great, and VueConf was no exception. If you haven't been to a conference, you should go. If you've been to a conference, you should go again. I find they are a good way to recharge my battery.</p>
<p>From this lineup, my favorite talk was probably "<a target="_blank" href="https://www.vuemastery.com/conferences/vueconf-us-2022/how-we-migrated-our-huge-app-to-vue3">How we migrated our HUGE app to Vue 3</a>" by <a target="_blank" href="https://twitter.com/_snoozbuster">Alex Van Liew</a>. It was very informative from hands-on experience, but it also wasn't so subjective that it wasn't useful. Alex did a great job putting it together and delivering it (and I think he said it was his first talk ever).</p>
<p>One last minute tip for the whole event. Be active on Twitter before, during, and after. Put the conference name in your Twitter name. Use whatever hashtag is associated. It makes it way easier to find other folks. </p>
<p>And if you're not already on Twitter, you should get on it because everyone uses Twitter (right <a target="_blank" href="https://twitter.com/Frankyfraank">Adam</a>?).</p>
<p>Thank you so much for reading. If you liked this article, please <a target="_blank" href="https://twitter.com/share?via=heyAustinGil">share it</a>. It's one of the best ways to support me. You can also <a target="_blank" href="https://austingil.com/newsletter/">sign up for my newsletter</a> or <a target="_blank" href="https://twitter.com/heyAustinGil">follow me on Twitter</a> if you want to know when new articles are published.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Podcast Player with Transcriptions using Vue and Supabase ]]>
                </title>
                <description>
                    <![CDATA[ In this post we will walk through setting up a Podcast Player app using Supabase and Vue 3, including getting transcriptions for the podcasts.  This is a continuation of my previous post on setting up Authentication using Supabase. If you aren't fami... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-podcast-player-with-transcriptions-using-vue-supabase/</link>
                <guid isPermaLink="false">66bb92ddd2bda3e4315491ed</guid>
                
                    <category>
                        <![CDATA[ audio ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ supabase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Brian Barrow ]]>
                </dc:creator>
                <pubDate>Mon, 28 Feb 2022 23:05:43 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/02/Build-Podcast-Player-app-w-transcriptions-using-Vue-Supabase@2x.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this post we will walk through setting up a Podcast Player app using Supabase and Vue 3, including getting transcriptions for the podcasts. </p>
<p>This is a continuation of my previous post on <a target="_blank" href="https://www.freecodecamp.org/news/add-supabase-authentication-to-vue/">setting up Authentication using Supabase</a>. If you aren't familiar with getting Supabase set up in your project, I highly recommend going through that post. </p>
<h2 id="heading-the-starting-code-repo">The Starting Code Repo</h2>
<p>Here is the repo from my previous post that will get you to where this post will be starting. You'll just need to set up Supabase and add your credentials/API key to a <code>.env.local</code> file to get up and running. This repo also has styling applied to it that was not included in the previous post.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/briancbarrow/vue-supabase-auth">https://github.com/briancbarrow/vue-supabase-auth</a></div>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>You should be familiar with JavaScript, have had some experience with Vue 3, and you should have Node.js and NPM installed on your machine. </p>
<p>If you've gone through the previous post about Supabase Authentication or this other post on <a target="_blank" href="https://developers.deepgram.com/blog/2021/11/getting-started-with-supabase/">Getting Started with Supabase</a> you'll be good to go.</p>
<p>You will also need a <a target="_blank" href="https://console.deepgram.com/signup">free API key from Deepgram</a> for when we get to the transcription section. </p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Once you have downloaded the <a target="_blank" href="https://github.com/briancbarrow/vue-supabase-auth">repo from above</a> run <code>npm install</code> to get the packages installed for the project. </p>
<p>Add your <code>VITE_SUPABASE_URL</code> and <code>VITE_SUPABASE_ANON_KEY</code> environment variables from your the dashboard of your own Supabase project.</p>
<p>Run <code>npm run dev</code> to get the local dev server started.</p>
<p>Sign in to the app using either the Sign In form or the Magic Link form. Once you get signed in, you should see the HelloWorld component/page with a sign out button at the top. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screen-Shot-2022-02-18-at-2.20.26-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Hello World component</em></p>
<h2 id="heading-how-to-fetch-a-podcast-rss-feed">How to Fetch a Podcast RSS Feed</h2>
<p>The first thing we need to do is add functionality to get a podcast feed into our app. Create a new component in the components folder called <code>PodcastFeed.vue</code>. </p>
<p>Most podcasts have a public RSS feed that we can use to get the information we need with a simple fetch request. </p>
<p>Inside the of the <code>PodcastFeed.vue</code> component create the following form that takes in a RSS feed URL, and hooks up to a button that triggers the fetch request.</p>
<p>Note: I've tried to add comments in the code to help you understand what each part is doing.</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"podcast-input-feed"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Podcast RSS Feed URL<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- binding the url input field to the 'url' data property --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"url"</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"url"</span>
        <span class="hljs-attr">v-model</span>=<span class="hljs-string">"url"</span>
        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"https://rss.your-org.org/feed/"</span>
        <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"rss-url"</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- hooking the button click to the 'getRssFeed' method --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"getRssFeed()"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Get Feed<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">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../supabase"</span>;
<span class="hljs-keyword">import</span> { store } <span class="hljs-keyword">from</span> <span class="hljs-string">"../store"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  setup() {
    <span class="hljs-comment">// I am initializing the url to a url I know works, so that I don't need to keep inputing a url as I'm developing.</span>
    <span class="hljs-comment">// feel free to change this to a url of your own choosing</span>
    <span class="hljs-keyword">const</span> url = ref(<span class="hljs-string">"https://anchor.fm/s/3e9db190/podcast/rss"</span>);
    <span class="hljs-comment">// initializing the podcast state to an empty object</span>
    <span class="hljs-keyword">const</span> podcast = ref({});

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getRssFeed</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> feedUrl = url.value;
      <span class="hljs-keyword">return</span> (
        fetch(feedUrl)
          <span class="hljs-comment">// this returns a promise so we need to convert it to a string</span>
          .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.text())
          <span class="hljs-comment">// this next line is to parse the xml response</span>
          .then(<span class="hljs-function">(<span class="hljs-params">str</span>) =&gt;</span>
            <span class="hljs-keyword">new</span> <span class="hljs-built_in">window</span>.DOMParser().parseFromString(str, <span class="hljs-string">"text/xml"</span>)
          )
          <span class="hljs-comment">// parsing the data from the xml response and setting it into the podcast state</span>
          .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Data: "</span>, data);
            podcast.value.image_url = data
              .querySelector(<span class="hljs-string">"image"</span>)
              .querySelector(<span class="hljs-string">"url"</span>).innerHTML;
            podcast.value.title = data.querySelector(<span class="hljs-string">"title"</span>).textContent;
            podcast.value.description =
              data.querySelector(<span class="hljs-string">"description"</span>).textContent;
            podcast.value.rss_url = feedUrl;
          })
          .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"ERROR: "</span>, err);
          })
      );
    }
    <span class="hljs-keyword">return</span> {
      url,
      podcast,
      store,

      getRssFeed,
    };
  },
};
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre>
<p>With that set up, replace the HelloWorld component in the <code>App.vue</code> file with this new <code>PodcastFeed.vue</code> component:</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"store.state.user"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"signout-button"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"signOut"</span>&gt;</span>Sign Out<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  &lt;!-- Check <span class="hljs-keyword">if</span> user is available <span class="hljs-keyword">in</span> the store, <span class="hljs-keyword">if</span> not show auth compoenent --&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Auth</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!store.state.user"</span> /&gt;</span></span>
  &lt;!-- If user is available, show the app --&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">PodcastFeed</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">import</span> Auth <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Auth.vue"</span>;
<span class="hljs-keyword">import</span> PodcastFeed <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/PodcastFeed.vue"</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> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"./supabase"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: {
    PodcastFeed,
    Auth,
  },
  setup() {
    <span class="hljs-comment">// we initially verify if a user is logged in with Supabase</span>
    store.state.user = supabase.auth.user();
    <span class="hljs-comment">// we then set up a listener to update the store when the user changes either by logging in or out</span>
    supabase.auth.onAuthStateChange(<span class="hljs-function">(<span class="hljs-params">event, session</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (event == <span class="hljs-string">"SIGNED_OUT"</span>) {
        store.state.user = <span class="hljs-literal">null</span>;
      } <span class="hljs-keyword">else</span> {
        store.state.user = session.user;
      }
    });

    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">signOut</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase.auth.signOut();
    }

    <span class="hljs-keyword">return</span> {
      store,

      signOut,
    };
  },
};
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>So now the app should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screen-Shot-2022-02-18-at-2.38.40-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>App after adding PodcastFeed.vue</em></p>
<p>When you click the button, the data that comes back from the fetch request will show up in the console. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/xml-data-from-rss.png" alt="Image" width="600" height="400" loading="lazy">
<em>Parsed XML Data</em></p>
<p>In the <code>getRssFeed</code> method we parse that data and then take the information we need and add it to the <code>podcast</code> state data. We need to display that data so that the user can know the request was successful. We also want to add better error messaging in case the request fails. </p>
<p>Create a new component called <code>PodcastInfo.vue</code> and add the following code:</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"podcast-info"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"image-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"podcast.image_url"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"podcast-text"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title-desc"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title"</span>&gt;</span>
          {{ podcast.title }}
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"desc"</span>&gt;</span>
          {{ podcast.description }}
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</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">import</span> { store } <span class="hljs-keyword">from</span> <span class="hljs-string">"../store"</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../supabase"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">props</span>: {
    <span class="hljs-attr">podcast</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Object</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
  },
  <span class="hljs-attr">computed</span>: {},
  <span class="hljs-attr">methods</span>: {},
  setup() {},
};
</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>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"info-error"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>There was an error with your request<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Check your RSS feed URL and try again.<span class="hljs-tag">&lt;/<span class="hljs-name">p</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><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre>
<p>Then update the  <code>PodcastFeed.vue</code> to the following in order to bring in the component:</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"podcast-input-feed"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Podcast RSS Feed URL<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
      <span class="hljs-comment">&lt;!-- binding the url input field to the 'url' data property --&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"url"</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"url"</span>
        <span class="hljs-attr">v-model</span>=<span class="hljs-string">"url"</span>
        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"https://rss.your-org.org/feed/"</span>
        <span class="hljs-attr">aria-describedby</span>=<span class="hljs-string">"rss-url"</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- hooking the button click to the 'getRssFeed' method --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"getRssFeed()"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Get Feed<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Adding in these two new components --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">podcast-info</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"podcast.title &amp;&amp; !requestError"</span> <span class="hljs-attr">:podcast</span>=<span class="hljs-string">"podcast"</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">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../supabase"</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> PodcastInfo <span class="hljs-keyword">from</span> <span class="hljs-string">"./PodcastInfo.vue"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: {
    PodcastInfo,
  },

  setup() {
    <span class="hljs-comment">// I am initializing the url to a url I know works, so that I don't need to keep inputing a url as I'm developing.</span>
    <span class="hljs-comment">// feel free to change this to a url of your own choosing</span>
    <span class="hljs-keyword">const</span> url = ref(<span class="hljs-string">"https://anchor.fm/s/3e9db190/podcast/rss"</span>);
    <span class="hljs-comment">// initializing the podcast state to an empty object</span>
    <span class="hljs-keyword">const</span> podcast = ref({});
    <span class="hljs-keyword">const</span> requestError = ref(<span class="hljs-literal">false</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getRssFeed</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> feedUrl = url.value;
      <span class="hljs-keyword">return</span> (
        fetch(feedUrl)
          <span class="hljs-comment">// this returns a promise so we need to convert it to a string</span>
          .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.text())
          <span class="hljs-comment">// this next line is to parse the xml response</span>
          .then(<span class="hljs-function">(<span class="hljs-params">str</span>) =&gt;</span>
            <span class="hljs-keyword">new</span> <span class="hljs-built_in">window</span>.DOMParser().parseFromString(str, <span class="hljs-string">"text/xml"</span>)
          )
          <span class="hljs-comment">// parsing the data from the xml response and setting it into the podcast state</span>
          .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Data: "</span>, data);
            podcast.value.image_url = data
              .querySelector(<span class="hljs-string">"image"</span>)
              .querySelector(<span class="hljs-string">"url"</span>).innerHTML;
            podcast.value.title = data.querySelector(<span class="hljs-string">"title"</span>).textContent;
            podcast.value.description =
              data.querySelector(<span class="hljs-string">"description"</span>).textContent;
            podcast.value.rss_url = feedUrl;
          })
          .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            requestError.value = <span class="hljs-literal">true</span>;
          })
      );
    }
    <span class="hljs-keyword">return</span> {
      url,
      podcast,
      store,
      requestError,

      getRssFeed,
    };
  },
};
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre>
<p>Now when you click the "Get Feed" button, you should see the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screen-Shot-2022-02-18-at-3.05.15-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now that we can get the info displayed, we can wire up the app to save the info to Supabase. </p>
<h2 id="heading-how-to-add-a-table-to-the-supabase-db">How to Add a Table to the Supabase DB</h2>
<p>The first thing we need to do is add a table to our Supabase DB. In the Dashboard for your project on Supabase, select the Table Editor and click the <code>New table</code> button. I name the new table <code>podcasts</code>. Enable the Row Level Security (this makes our DB more secure) and add the following columns:</p>
<ul>
<li>id (this column should be filled in for you when you create a new table)</li>
<li>created_at</li>
<li>name</li>
<li>image_url</li>
<li>description</li>
<li>rss_url</li>
<li>user_id (for this one, we want to link it via foreign key to our users table created by the Auth service. Click the chain-link icon to get that set up and link it to the <code>users</code> table on the <code>id</code> column.)</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screen-Shot-2022-01-19-at-9.08.50-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>podcasts table setup</em></p>
<p>Because we enabled the Row Level Security, the table won't let anything get inserted until we update the policies for it. </p>
<p>Under the Authentication tab there is a section called 'Policies'. There you should see the <code>podcasts</code> table and a button to create a new policy. When you click on it, it will give you the option to create a policy from a template. Choose the template called 'Enable insert access for authenticated users only'. Now, only users that are authenticated have access to insert anything into the table. </p>
<p>When Supabase runs the <code>insert</code> command, it will automatically run a <code>select</code> command and return the newly inserted row. Because of this, we also have to add a policy to the table allowing the user <code>SELECT</code> access. </p>
<p>Create a new policy with the name <code>Enable select based on userid</code> and then in the <code>USING expression</code> section put <code>(uid() = user_id)</code>. That will prevent users from reading other users' information, while still giving them access to their own podcasts in the table.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/select-user-policy.png" alt="Image" width="600" height="400" loading="lazy">
<em>Select based on userid policy</em></p>
<h2 id="heading-how-to-link-up-the-ui-to-the-db-so-the-user-can-save-podcasts">How to Link Up the UI to the DB So the User Can Save Podcasts</h2>
<p>To add a podcast to our DB, we will first add a button to the <code>PodcastInfo</code> component. Add this code to the bottom of the <code>&lt;div class="podcast-info"&gt;</code>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"addPodcast"</span>&gt;</span>Add to My Podcasts<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>Now add a method called <code>addPodcast</code> to the setup function of the component like this. Don't forget to add the <code>props</code> to the argument of the setup function.</p>
<pre><code class="lang-js">setup(props) {
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addPodcast</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-comment">// Setting up the podcast object to send to supabase</span>
      <span class="hljs-keyword">const</span> podcast = {
        <span class="hljs-attr">name</span>: props.podcast.title,
        <span class="hljs-attr">image_url</span>: props.podcast.image_url,
        <span class="hljs-attr">description</span>: props.podcast.description,
        <span class="hljs-attr">rss_url</span>: props.podcast.rss_url,
        <span class="hljs-attr">user_id</span>: store.state.user.id,
      };
      <span class="hljs-comment">// calling supabase method to insert into the db</span>
      supabase
        .from(<span class="hljs-string">"podcasts"</span>)
        .insert(podcast)
        .then(<span class="hljs-function">(<span class="hljs-params">{ body }</span>) =&gt;</span> {
          store.addPodcastToStore(body[<span class="hljs-number">0</span>]);
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
          <span class="hljs-built_in">console</span>.log(err);
        });
    }

    <span class="hljs-keyword">return</span> {
      addPodcast,
    };
  },
</code></pre>
<p>You can see in the <code>.then</code> statement we call a method from the global store. Update the <code>store.js</code> file to the following:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { reactive } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> store = {
  <span class="hljs-attr">state</span>: reactive({
    <span class="hljs-attr">user</span>: {},
    <span class="hljs-comment">// adding podcasts array to global store</span>
    <span class="hljs-attr">podcasts</span>: [],
  }),

  <span class="hljs-comment">// adding addPodcastToStore method to store object</span>
  addPodcastToStore(podcast) {
    <span class="hljs-built_in">this</span>.state.podcasts.push(podcast);
  },
};
</code></pre>
<p>Now when we click the "Add To My Podcasts" button, the app makes a call to Supabase and then takes the result of that call and adds it to the podcasts array in the global store. (If you are getting a 403 error, make sure you set up the policies correctly. Maybe try restarting the dev server too.)</p>
<p>If a podcast is already in a user's list of podcasts, we don't want to let them click the add button again. To prevent this we need to first call Supabase to get all of the user's podcasts, and then check if the podcast they are looking at is in that list.</p>
<p>This method will not be specific to any one component so we want to create it inside of the global store. That way, any component has access to it. Add this method to the <code>store.js</code> file underneath the <code>addPodcastToStore</code> method:</p>
<pre><code class="lang-js">getPodcastsFromDB() {
    supabase
        .from(<span class="hljs-string">"podcasts"</span>)
        .select(<span class="hljs-string">"*"</span>)
        .then(<span class="hljs-function">(<span class="hljs-params">{ body }</span>) =&gt;</span> {
            <span class="hljs-built_in">this</span>.state.podcasts = body;
        });
},
</code></pre>
<p>Then we want to update the method to be called whenever a user signs in. Inside of <code>App.vue</code> change the <code>onAuthStateChange</code> handler to this:</p>
<pre><code class="lang-js">supabase.auth.onAuthStateChange(<span class="hljs-function">(<span class="hljs-params">event, session</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (event == <span class="hljs-string">"SIGNED_OUT"</span>) {
        store.state.user = <span class="hljs-literal">null</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// make call to supabase to get Podcasts for the user</span>
        store.getPodcastsFromDB();
        store.state.user = session.user;
    }
});
</code></pre>
<p>Now update the <code>PodcastInfo.vue</code> file to this in order to display to the user if a podcast is already in their library.</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"podcast-info"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"image-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"podcast.image_url"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"podcast-text"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title-desc"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title"</span>&gt;</span>
          {{ podcast.title }}
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"desc"</span>&gt;</span>
          {{ podcast.description }}
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Add check in markup to remove the button if the podcast already exists in the user's list --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"isInUserPodcasts"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"in-podcasts"</span>&gt;</span>In Your Podcasts<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">v-else</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"addPodcast"</span>&gt;</span>Add to My Podcasts<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-comment">// importing computed</span>
<span class="hljs-keyword">import</span> { ref, computed } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</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> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../supabase"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">props</span>: {
    <span class="hljs-attr">podcast</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Object</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
  },
  setup(props) {
    <span class="hljs-comment">// add computed property checking if podcast is in user's podcasts</span>
    <span class="hljs-keyword">const</span> isInUserPodcasts = computed(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">return</span> store.state.podcasts.some(
        <span class="hljs-function">(<span class="hljs-params">podcast</span>) =&gt;</span> podcast.rss_url === props.podcast.rss_url
      );
    });

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addPodcast</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-comment">// check if podcast is already in user's podcasts</span>
      <span class="hljs-keyword">if</span> (isInUserPodcasts.value) {
        alert(<span class="hljs-string">"You already have this podcast in your list!"</span>);
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">const</span> podcast = {
          <span class="hljs-attr">name</span>: props.podcast.title,
          <span class="hljs-attr">image_url</span>: props.podcast.image_url,
          <span class="hljs-attr">description</span>: props.podcast.description,
          <span class="hljs-attr">rss_url</span>: props.podcast.rss_url,
          <span class="hljs-attr">user_id</span>: store.state.user.id,
        };
        supabase
          .from(<span class="hljs-string">"podcasts"</span>)
          .insert(podcast)
          .then(<span class="hljs-function">(<span class="hljs-params">{ body }</span>) =&gt;</span> {
            store.addPodcastToStore(body[<span class="hljs-number">0</span>]);
          })
          .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(err);
          });
      }
    }

    <span class="hljs-keyword">return</span> {
      <span class="hljs-comment">// exposing the isInUserPodcasts computed property</span>
      isInUserPodcasts,
      addPodcast,
    };
  },
};
</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>Next, we want to display a list of podcasts that the user has added to their library. We have the list in the global store, so we just need to loop through them to display the needed info. </p>
<p>Add the following to the bottom of the <code>PodcastFeed.vue</code> template:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Loop through podcasts and display them --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"feeds"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Your Podcast Feeds<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"pod in store.state.podcasts"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"pod.id"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">:href</span>=<span class="hljs-string">"`/podcast/${pod.id}`"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"pod.image_url"</span> <span class="hljs-attr">:alt</span>=<span class="hljs-string">"`logo for ${pod.name}`"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>{{ pod.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h2 id="heading-how-to-set-up-the-other-pages-for-our-podcast-app">How to Set Up the Other Pages for Our Podcast App</h2>
<p>Now that we have the list of podcasts being displayed in the app, we need a way to navigate to an individual podcast. We have the markup set to link to a path like <code>/podcast/{podcast_id}</code>. Now we need to update our app to handle routes like this. </p>
<p>First, install vue-router using <code>npm i vue-router</code>.</p>
<p>Then create a file called <code>router.js</code> with the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Import Vue Router</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> VueRouter <span class="hljs-keyword">from</span> <span class="hljs-string">"vue-router"</span>;

<span class="hljs-comment">// Import the components that will show on the different routes</span>
<span class="hljs-keyword">import</span> PodcastFeed <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/PodcastFeed.vue"</span>;
<span class="hljs-keyword">import</span> PodcastDetail <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/PodcastDetail.vue"</span>;

<span class="hljs-comment">// Set up the routes</span>
<span class="hljs-keyword">const</span> routes = [
  { <span class="hljs-attr">path</span>: <span class="hljs-string">"/"</span>, <span class="hljs-attr">component</span>: PodcastFeed },
  { <span class="hljs-attr">path</span>: <span class="hljs-string">"/podcast/:id"</span>, <span class="hljs-attr">component</span>: PodcastDetail },
];

<span class="hljs-comment">// Initialize the router</span>
<span class="hljs-keyword">const</span> router = VueRouter.createRouter({
  <span class="hljs-attr">history</span>: VueRouter.createWebHistory(),
  routes,
});

<span class="hljs-comment">// Export the router</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> router;
</code></pre>
<p>Update <code>main.js</code> to use the router in the Vue app:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { createApp } <span class="hljs-keyword">from</span> <span class="hljs-string">"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> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App.vue"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;

<span class="hljs-keyword">const</span> app = createApp(App);
app.use(router);
app.mount(<span class="hljs-string">"#app"</span>);
</code></pre>
<p>Update <code>App.vue</code> to show the <code>router-view</code> component provided by Vue Router:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"store.state.user"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"signout-button"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"signOut"</span>&gt;</span>Sign Out<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- Check if user is available in the store, if not show auth compoenent --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">Auth</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!store.state.user"</span> /&gt;</span>
  <span class="hljs-comment">&lt;!-- If user is available, show the app --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"app"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">router-view</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">router-view</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<p>Now create a <code>PodcastDetail.vue</code> file that will display the episode info for the podcast:</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span></span>
  &lt;!-- Basic layout <span class="hljs-keyword">for</span> showing podcast info --&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"podcast-detail"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"podcast.image_url"</span> <span class="hljs-attr">:alt</span>=<span class="hljs-string">"podcast.name"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>{{ podcast.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{ podcast.description }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Episodes<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Looping through each episode of a podcast and displaying episode info --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
        <span class="hljs-attr">v-for</span>=<span class="hljs-string">"episode in episodes"</span>
        <span class="hljs-attr">:key</span>=<span class="hljs-string">"episode.guid || episode.link"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"info"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{{ episode.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">audio</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span> <span class="hljs-attr">controls</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"episode.url"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"audio/mpeg"</span> /&gt;</span>
            Display
          <span class="hljs-tag">&lt;/<span class="hljs-name">audio</span>&gt;</span>          
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>        
      <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</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-comment">// Importing necessary methods</span>
<span class="hljs-keyword">import</span> { ref, onMounted } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;
<span class="hljs-keyword">import</span> { useRoute } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue-router"</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../supabase"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  setup() {
    <span class="hljs-keyword">const</span> route = useRoute();
    <span class="hljs-keyword">const</span> podcast = ref({});
    <span class="hljs-keyword">const</span> episodes = ref([]);

    <span class="hljs-comment">// Getting podcast info from the database</span>
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPodcastData</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> {
        <span class="hljs-attr">data</span>: [podcastinfo],
      } = <span class="hljs-keyword">await</span> supabase.from(<span class="hljs-string">"podcasts"</span>).select().eq(<span class="hljs-string">"id"</span>, route.params.id);
      podcast.value = podcastinfo;

      <span class="hljs-comment">// Making call to episode url to get episode info</span>
      getEpisodes(podcastinfo.rss_url);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getEpisodes</span>(<span class="hljs-params">url</span>) </span>{
      fetch(url)
        .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.text())
        .then(<span class="hljs-function">(<span class="hljs-params">str</span>) =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">window</span>.DOMParser().parseFromString(str, <span class="hljs-string">"text/xml"</span>))
        .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
          <span class="hljs-comment">// Finding all the "item" tags in the xml response which will contain the episode info</span>
          <span class="hljs-keyword">const</span> items = data.querySelectorAll(<span class="hljs-string">"item"</span>);
          <span class="hljs-comment">// Looping through each item and getting the episode info and pushing it to the 'episodes' array</span>
          items.forEach(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
            <span class="hljs-keyword">let</span> url;

            <span class="hljs-comment">// Not every podcast episode is going to have the `enclosure` tag, so we need to check if it exists</span>
            <span class="hljs-keyword">try</span> {
              url = item.querySelector(<span class="hljs-string">"enclosure"</span>).getAttribute(<span class="hljs-string">"url"</span>);
            } <span class="hljs-keyword">catch</span> (e) {
              <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"error"</span>, e);
              url = item.querySelector(<span class="hljs-string">"link"</span>).innerHTML;
            }

            episodes.value.push({
              <span class="hljs-comment">// this `title` and the `guid` properties looks a little different because the title contains CDATA tags which need to be grabbed with the 'childNodes' property</span>
              <span class="hljs-attr">title</span>: item.querySelector(<span class="hljs-string">"title"</span>).childNodes[<span class="hljs-number">0</span>].textContent,
              <span class="hljs-attr">link</span>: url,
              <span class="hljs-attr">url</span>: url,
              <span class="hljs-attr">description</span>: item.querySelector(<span class="hljs-string">"description"</span>).innerHTML,
              <span class="hljs-attr">pubDate</span>: item.querySelector(<span class="hljs-string">"pubDate"</span>).innerHTML,
              <span class="hljs-attr">guid</span>: item.querySelector(<span class="hljs-string">"guid"</span>).childNodes[<span class="hljs-number">0</span>].textContent,
            });
          });
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
          alert(<span class="hljs-string">"Couldn't get episodes"</span>, err);
        });
    }

    onMounted(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// Getting podcast info from the database once the component is mounted</span>
      getPodcastData();
    });

    <span class="hljs-keyword">return</span> {
      podcast,
      episodes,
    };
  },
};
</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>With those changes, we can now see the individual episodes of the podcast and can play them using the <code>&lt;audio&gt;</code> html tag. </p>
<h2 id="heading-how-to-get-the-transcriptions-of-the-podcasts">How to Get the Transcriptions of the Podcasts</h2>
<p>The last step is to get transcriptions for the podcasts, and then save them to our database.</p>
<p>If you haven't yet, you'll need to get a <a target="_blank" href="https://console.deepgram.com/signup">free API key from Deepgram</a> in order to process the audio and get the transcriptions. </p>
<p>Once you get the API key, add it to your <code>.env.local</code> file as <code>VITE_DEEPGRAM_KEY</code>. Make sure you restart your dev server here, otherwise you'll probably get a 403 Forbidden error when we finally call the API.</p>
<p>Then add this code to a deepgram.js file in the <code>src</code> folder.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> deepgramKey = <span class="hljs-keyword">import</span>.meta.env.VITE_DEEPGRAM_KEY;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deepgram</span>(<span class="hljs-params">url</span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
    <span class="hljs-string">"https://api.deepgram.com/v1/listen?punctuate=true&amp;diarize=true&amp;utterances=true"</span>,
    {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`Token <span class="hljs-subst">${deepgramKey}</span>`</span>,
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        <span class="hljs-attr">url</span>: url,
      }),
    }
  );
  <span class="hljs-keyword">const</span> json = <span class="hljs-keyword">await</span> response.json();
  <span class="hljs-keyword">return</span> json.results;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> deepgram;
</code></pre>
<p>This gives us a utility function we can import into our app in other files to call the Deepgram API in order to get the transcriptions. We added the punctuate, diarize, and utterances to the URL as parameters to get a cleaner transcription that is easier to read. </p>
<p>Now that we have that, we need to add some functionality to the <code>PodcastDetail.vue</code> file. I'll walk through the changes and then later will put up the final code for the file.</p>
<p>First we need to have some state to keep track of the transcriptions we get, and also to have some loading state once we click a button to get a transcription. So we'll add these two lines to our setup function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> transcriptions = ref({});
<span class="hljs-keyword">const</span> episodeTranscriptionLoading = ref([]);
</code></pre>
<p>Don't forget to add them to the return object of the <code>setup</code> function.</p>
<p>Then add this function to make the request to Deepgram, and then add the transcription to the local <code>transcriptions</code> object.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Function to get a transcription from Deepgram, passing in the episode url</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTranscription</span>(<span class="hljs-params">episode</span>) </span>{
    <span class="hljs-comment">// setting the loading state to true for the episode</span>
    episodeTranscriptionLoading.value.push(episode.guid);
    <span class="hljs-keyword">const</span> transcription = <span class="hljs-keyword">await</span> deepgram(episode.url);
    <span class="hljs-comment">// setting a unique id for the episode transcription</span>
    transcriptions.value[<span class="hljs-string">`<span class="hljs-subst">${podcast.value.id}</span>---<span class="hljs-subst">${episode.guid}</span>`</span>] =
        transcription;
    <span class="hljs-comment">// removing the loading state for the episode</span>
    episodeTranscriptionLoading.value.splice(
        episodeTranscriptionLoading.value.indexOf(episode.guid),
        <span class="hljs-number">1</span>
    );
}
</code></pre>
<p>Make sure you import the deepgram function from <code>deepgram.js</code> at the top of the script tag.</p>
<p>Then update the template to this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- Basic layout for showing podcast info --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"podcast-detail"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"podcast.image_url"</span> <span class="hljs-attr">:alt</span>=<span class="hljs-string">"podcast.name"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>{{ podcast.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{ podcast.description }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Episodes<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Looping through each episode of a podcast and displaying episode info --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
        <span class="hljs-attr">v-for</span>=<span class="hljs-string">"episode in episodes"</span>
        <span class="hljs-attr">:key</span>=<span class="hljs-string">"episode.guid || episode.link"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"info"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{{ episode.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">audio</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span> <span class="hljs-attr">controls</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"episode.url"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"audio/mpeg"</span> /&gt;</span>
            Display
          <span class="hljs-tag">&lt;/<span class="hljs-name">audio</span>&gt;</span>
            <span class="hljs-comment">&lt;!-- button to get transcriptions --&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!transcriptions[`${podcast.id}---${episode.guid}`]"</span>
            @<span class="hljs-attr">click.prevent</span>=<span class="hljs-string">"getTranscription(episode)"</span>
            <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>
          &gt;</span>
            {{
              episodeTranscriptionLoading.includes(episode.guid)
                ? "Loading..."
                : "Get Transcription"
            }}
          <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 class="hljs-comment">&lt;!-- box to display the transcription --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">v-if</span>=<span class="hljs-string">"transcriptions[`${podcast.id}---${episode.guid}`]"</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"transcription"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
            {{
              transcriptions[`${podcast.id}---${episode.guid}`].channels[0]
                .alternatives[0].transcript
            }}
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> 
      <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
</code></pre>
<h2 id="heading-how-to-save-the-transcriptions">How to Save the Transcriptions</h2>
<p>Now that we can get the transcriptions, we need to add the functionality to save them to Supabase. </p>
<p>First, go create a table in Supabase like we did above, but this time name the table <code>transcriptions</code>. You'll want the following as the columns:</p>
<ul>
<li><strong>id</strong> – varchar (primary) Also remove the "Is Identity" check mark in the settings for this column</li>
<li><strong>podcast_id</strong> – int8</li>
<li><strong>episode_guid</strong> – varchar</li>
<li><strong>transcript</strong> – text</li>
<li><strong>user_id</strong> – uuid (You'll need to link this to the user table by clicking on the link icon)</li>
<li><strong>created_at</strong> – timestamptz</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screen-Shot-2022-02-22-at-4.40.52-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>columns for transcriptions table</em></p>
<p>Once that table is set up, we can add a reactive property called <code>savedTranscriptions</code> to the component and then add the following code to save the transcriptions to Supabase. Then we'll store them in the object <code>savedTranscriptions</code>.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">saveTranscription</span>(<span class="hljs-params">podcastId, episodeGuid</span>) </span>{
    supabase
        .from(<span class="hljs-string">"transcriptions"</span>)
        .insert({
        <span class="hljs-attr">id</span>: <span class="hljs-string">`<span class="hljs-subst">${podcastId}</span>---<span class="hljs-subst">${episodeGuid}</span>`</span>,
        <span class="hljs-attr">podcast_id</span>: podcastId,
        <span class="hljs-attr">episode_guid</span>: episodeGuid,
        <span class="hljs-attr">transcript</span>:
        transcriptions.value[<span class="hljs-string">`<span class="hljs-subst">${podcastId}</span>---<span class="hljs-subst">${episodeGuid}</span>`</span>].channels[<span class="hljs-number">0</span>]
        .alternatives[<span class="hljs-number">0</span>].transcript,
        <span class="hljs-attr">user_id</span>: store.state.user.id,
    })
        .then(<span class="hljs-function">(<span class="hljs-params">{ data: [transcriptObject] }</span>) =&gt;</span> {
        savedTranscriptions.value[transcriptObject.id] =
            transcriptObject.transcript;
    });
}
</code></pre>
<p>Once a user has a transcription saved, we need to display it whenever they re-visit a page. Add this function to get that data from Supabase:</p>
<pre><code class="lang-js"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTranscriptions</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: transcriptions } = <span class="hljs-keyword">await</span> supabase
    .from(<span class="hljs-string">"transcriptions"</span>)
    .select()
    .eq(<span class="hljs-string">"podcast_id"</span>, podcast.value.id);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Transcriptions"</span>, transcriptions);
    transcriptions.forEach(<span class="hljs-function">(<span class="hljs-params">transcript</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"id"</span>, transcript.id);
        savedTranscriptions.value[transcript.id] = transcript.transcript;
    });
}
</code></pre>
<p>We will want this called whenever a user hits this page, but not until we get the podcast information. Add a call to <code>getTranscriptions</code> to the bottom of the <code>getPodcastData</code> function to do that.</p>
<p>The last thing to do is to update the template to include the save buttons and to display transcriptions if they are in the saved objects. The final code for the <code>PodcastDetail.vue</code> should then look like this:</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span></span>
  &lt;!-- Basic layout <span class="hljs-keyword">for</span> showing podcast info --&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"podcast-detail"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"podcast.image_url"</span> <span class="hljs-attr">:alt</span>=<span class="hljs-string">"podcast.name"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>{{ podcast.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{ podcast.description }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>Episodes<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Looping through each episode of a podcast and displaying episode info --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
        <span class="hljs-attr">v-for</span>=<span class="hljs-string">"episode in episodes"</span>
        <span class="hljs-attr">:key</span>=<span class="hljs-string">"episode.guid || episode.link"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"info"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{{ episode.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">audio</span> <span class="hljs-attr">class</span>=<span class="hljs-string">""</span> <span class="hljs-attr">controls</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">:src</span>=<span class="hljs-string">"episode.url"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"audio/mpeg"</span> /&gt;</span>
            Display
          <span class="hljs-tag">&lt;/<span class="hljs-name">audio</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">v-if</span>=<span class="hljs-string">"savedTranscriptions[`${podcast.id}---${episode.guid}`]"</span>
            <span class="hljs-attr">disabled</span>
          &gt;</span>
            Transcription Saved
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"
              !transcriptions[`${podcast.id}---${episode.guid}`] &amp;&amp;
              !savedTranscriptions[`${podcast.id}---${episode.guid}`]
            "</span>
            @<span class="hljs-attr">click.prevent</span>=<span class="hljs-string">"getTranscription(episode)"</span>
            <span class="hljs-attr">class</span>=<span class="hljs-string">""</span>
          &gt;</span>
            {{
              episodeTranscriptionLoading.includes(episode.guid)
                ? "Loading..."
                : "Get Transcription"
            }}
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">v-if</span>=<span class="hljs-string">"
              transcriptions[`${podcast.id}---${episode.guid}`] &amp;&amp;
              !savedTranscriptions[`${podcast.id}---${episode.guid}`]
            "</span>
            <span class="hljs-attr">class</span>=<span class="hljs-string">"save"</span>
            @<span class="hljs-attr">click.prevent</span>=<span class="hljs-string">"saveTranscription(podcast.id, episode.guid)"</span>
          &gt;</span>
            Save Transcription
          <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 class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">v-if</span>=<span class="hljs-string">"savedTranscriptions[`${podcast.id}---${episode.guid}`]"</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"transcription"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
            {{ savedTranscriptions[`${podcast.id}---${episode.guid}`] }}
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"transcriptions[`${podcast.id}---${episode.guid}`]"</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"transcription"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
            {{
              transcriptions[`${podcast.id}---${episode.guid}`].channels[0]
                .alternatives[0].transcript
            }}
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</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-comment">// Importing necessary methods</span>
<span class="hljs-keyword">import</span> { ref, onMounted } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;
<span class="hljs-keyword">import</span> { useRoute } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue-router"</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../supabase"</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> deepgram <span class="hljs-keyword">from</span> <span class="hljs-string">"../deepgram"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  setup() {
    <span class="hljs-keyword">const</span> route = useRoute();
    <span class="hljs-keyword">const</span> podcast = ref({});
    <span class="hljs-keyword">const</span> episodes = ref([]);
    <span class="hljs-keyword">let</span> transcriptions = ref({});
    <span class="hljs-keyword">let</span> savedTranscriptions = ref({});
    <span class="hljs-keyword">const</span> episodeTranscriptionLoading = ref([]);

    <span class="hljs-comment">// Getting podcast info from the database</span>
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPodcastData</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> {
        <span class="hljs-attr">data</span>: [podcastinfo],
      } = <span class="hljs-keyword">await</span> supabase.from(<span class="hljs-string">"podcasts"</span>).select().eq(<span class="hljs-string">"id"</span>, route.params.id);
      podcast.value = podcastinfo;

      <span class="hljs-comment">// Making call to episode url to get episode info</span>
      getEpisodes(podcastinfo.rss_url);
      <span class="hljs-keyword">await</span> getTranscriptions();
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getEpisodes</span>(<span class="hljs-params">url</span>) </span>{
      fetch(url)
        .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.text())
        .then(<span class="hljs-function">(<span class="hljs-params">str</span>) =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">window</span>.DOMParser().parseFromString(str, <span class="hljs-string">"text/xml"</span>))
        .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
          <span class="hljs-comment">// Finding all the "item" tags in the xml response which will contain the episode info</span>
          <span class="hljs-keyword">const</span> items = data.querySelectorAll(<span class="hljs-string">"item"</span>);
          <span class="hljs-comment">// Looping through each item and getting the episode info and pushing it to the 'episodes' array</span>
          items.forEach(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
            <span class="hljs-keyword">let</span> url;

            <span class="hljs-comment">// Not every podcast episode is going to have the `enclosure` tag, so we need to check if it exists</span>
            <span class="hljs-keyword">try</span> {
              url = item.querySelector(<span class="hljs-string">"enclosure"</span>).getAttribute(<span class="hljs-string">"url"</span>);
            } <span class="hljs-keyword">catch</span> (e) {
              <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"error"</span>, e);
              url = item.querySelector(<span class="hljs-string">"link"</span>).innerHTML;
            }

            episodes.value.push({
              <span class="hljs-comment">// this `title` and the `guid` properties looks a little different because the title contains CDATA tags which need to be grabbed with the 'childNodes' property</span>
              <span class="hljs-attr">title</span>: item.querySelector(<span class="hljs-string">"title"</span>).childNodes[<span class="hljs-number">0</span>].textContent,
              <span class="hljs-attr">link</span>: url,
              <span class="hljs-attr">url</span>: url,
              <span class="hljs-attr">description</span>: item.querySelector(<span class="hljs-string">"description"</span>).innerHTML,
              <span class="hljs-attr">pubDate</span>: item.querySelector(<span class="hljs-string">"pubDate"</span>).innerHTML,
              <span class="hljs-attr">guid</span>: item.querySelector(<span class="hljs-string">"guid"</span>).childNodes[<span class="hljs-number">0</span>].textContent,
            });
          });
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
          alert(<span class="hljs-string">"Couldn't get episodes"</span>, err);
        });
    }

    <span class="hljs-comment">// Function to get a transcription from Deepgram, passing in the episode url</span>
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTranscription</span>(<span class="hljs-params">episode</span>) </span>{
      <span class="hljs-comment">// setting the loading state to true for the episode</span>
      episodeTranscriptionLoading.value.push(episode.guid);
      <span class="hljs-keyword">const</span> transcription = <span class="hljs-keyword">await</span> deepgram(episode.url);
      <span class="hljs-comment">// setting a unique id for the episode transcription</span>
      transcriptions.value[<span class="hljs-string">`<span class="hljs-subst">${podcast.value.id}</span>---<span class="hljs-subst">${episode.guid}</span>`</span>] =
        transcription;
      <span class="hljs-comment">// removing the loading state for the episode</span>
      episodeTranscriptionLoading.value.splice(
        episodeTranscriptionLoading.value.indexOf(episode.guid),
        <span class="hljs-number">1</span>
      );
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">saveTranscription</span>(<span class="hljs-params">podcastId, episodeGuid</span>) </span>{
      <span class="hljs-built_in">console</span>.log(
        <span class="hljs-string">"saving transcription"</span>,
        transcriptions.value[<span class="hljs-string">`<span class="hljs-subst">${podcastId}</span>---<span class="hljs-subst">${episodeGuid}</span>`</span>]
      );
      supabase
        .from(<span class="hljs-string">"transcriptions"</span>)
        .insert({
          <span class="hljs-attr">id</span>: <span class="hljs-string">`<span class="hljs-subst">${podcastId}</span>---<span class="hljs-subst">${episodeGuid}</span>`</span>,
          <span class="hljs-attr">podcast_id</span>: podcastId,
          <span class="hljs-attr">episode_guid</span>: episodeGuid,
          <span class="hljs-attr">transcript</span>:
            transcriptions.value[<span class="hljs-string">`<span class="hljs-subst">${podcastId}</span>---<span class="hljs-subst">${episodeGuid}</span>`</span>].channels[<span class="hljs-number">0</span>]
              .alternatives[<span class="hljs-number">0</span>].transcript,
          <span class="hljs-attr">user_id</span>: store.state.user.id,
        })
        .then(<span class="hljs-function">(<span class="hljs-params">{ data: [transcriptObject] }</span>) =&gt;</span> {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"saved"</span>, transcriptObject);
          savedTranscriptions.value[transcriptObject.id] =
            transcriptObject.transcript;
        });
    }

    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTranscriptions</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: transcriptions } = <span class="hljs-keyword">await</span> supabase
        .from(<span class="hljs-string">"transcriptions"</span>)
        .select()
        .eq(<span class="hljs-string">"podcast_id"</span>, podcast.value.id);
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Transcriptions"</span>, transcriptions);
      transcriptions.forEach(<span class="hljs-function">(<span class="hljs-params">transcript</span>) =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"id"</span>, transcript.id);
        savedTranscriptions.value[transcript.id] = transcript.transcript;
      });
    }

    onMounted(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// Getting podcast info from the database once the component is mounted</span>
      getPodcastData();
    });

    <span class="hljs-keyword">return</span> {
      podcast,
      episodes,
      transcriptions,
      savedTranscriptions,
      episodeTranscriptionLoading,

      getTranscription,
      saveTranscription,
    };
  },
};
</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>
<h2 id="heading-conclusion">Conclusion</h2>
<p>If you've followed the steps above, you should have a working app. <a target="_blank" href="https://github.com/briancbarrow/vue-supabase-auth/tree/final-podcast-feed-transcriptions">Here is the final code</a> if you want to double check against what I have written.</p>
<p>I know I enjoyed making the app. Supabase makes it really easy to get a database/backend up and running. Please reach out to me on <a target="_blank" href="https://twitter.com/the_BrianB">Twitter</a> if you have any questions!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add Supabase Authentication to a Vue App ]]>
                </title>
                <description>
                    <![CDATA[ In this post we will walk through getting authentication set up using Supabase and Vue 3.  This will also work with Vue 2, but you'll need to move things around to work with the options API. I am using Vue 3 as it is now the default version.  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/add-supabase-authentication-to-vue/</link>
                <guid isPermaLink="false">66bb92dbadd24ba42732510d</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ supabase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Brian Barrow ]]>
                </dc:creator>
                <pubDate>Thu, 10 Feb 2022 16:40:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/02/Getting-Started-with-supabase-blog@2x.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this post we will walk through getting authentication set up using Supabase and Vue 3. </p>
<p>This will also work with Vue 2, but you'll need to move things around to work with the options API. I am using Vue 3 as it is <a target="_blank" href="https://blog.vuejs.org/posts/vue-3-as-the-new-default.html">now the default version</a>. </p>
<p>Just a heads up – there will not be much styling involved here so that the focus stays on Supabase authentication. </p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>You should be familiar with JavaScript and have had some experience with Vue 3. Having some experience with Supabase will help, but isn't necessary. </p>
<p>If you need a quick review of Supabase you can check out <a target="_blank" href="https://developers.deepgram.com/blog/2021/11/getting-started-with-supabase/">a previous post</a> of mine where I go over how to get started using it. </p>
<p>You will also need <a target="_blank" href="https://nodejs.org/en/">Node.js</a> and NPM installed on your machine.</p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Let's start by building some of the frontend before we start building the database using Supabase. </p>
<p>The first thing we need to do is set up our project. Inside of your terminal and inside of the folder where you want this project to live, run this command:</p>
<pre><code class="lang-bash">npm init vite@latest vue-supabase-auth --template vue
</code></pre>
<p>This will initialize a new Vite project with Vue 3 in a folder called <code>vue-supabase-auth</code>. </p>
<p>Open this up in your code editor of choice and open up the <code>App.vue</code> file inside of the <code>src</code> folder. When I initialized the project, Vite put the script tag above the template tag. My personal preference is to move the template tag to the top, but that isn't necessary.</p>
<h2 id="heading-add-authentication-to-the-app">Add Authentication to the App</h2>
<p>The next step is to add authentication to our app. Supabase gives us the ability to authenticate a user in many different ways. </p>
<p>We'll be walking through how to set up basic email/password authentication, and authentication with a "magic link". A "magic link" is just a link sent to a user's email that, when clicked, will take them to your application and log them in. </p>
<h3 id="heading-get-a-supabase-account">Get a Supabase Account</h3>
<p>If you haven't already, you'll need to sign up for an account on <a target="_blank" href="https://app.supabase.io">Supabase</a>. It asks you to sign up with GitHub, so if you don't have a GitHub account, you should also sign up for one of those.</p>
<p>Once you are signed in, you'll click the green button that says "New Project" and select the default organization that was created when you logged in. Mine was called "briancbarrow's Org." </p>
<p>This will bring up a box where you provide some info about the project. I'll name it <code>basic-auth</code>, give it a strong password, and then I'm going to select the region <code>West US (North California)</code> because that is closest to me.</p>
<p>Once the project is done setting up, go into the Authentication -&gt; Settings and disable the "Enable email confirmations." It just makes things a little smoother for this tutorial.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/disable-email-confirmations.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showing the "Enable email confirmations" setting disabled</em></p>
<h3 id="heading-set-up-supabase-in-the-vue-project">Set up Supabase in the Vue Project</h3>
<p>First, we need to run <code>npm install @supabase/supabase-js</code> to get the JavaScript package to integrate with Supabase.</p>
<p>Then we need to create a <code>supabase.js</code> file in the <code>src</code> folder of the project. That should contain the following:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/supabase-js'</span>

<span class="hljs-keyword">const</span> supabaseUrl = <span class="hljs-keyword">import</span>.meta.env.VITE_SUPABASE_URL
<span class="hljs-keyword">const</span> supabaseAnonKey = <span class="hljs-keyword">import</span>.meta.env.VITE_SUPABASE_ANON_KEY

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> supabase = createClient(supabaseUrl, supabaseAnonKey)
</code></pre>
<p>As you can see in the code above, we need to set up some environment variables that contain our Supabase keys. Create a <code>.env.local</code> file at the root of the project and add the <code>VITE_SUPABASE_URL</code> and the <code>VITE_SUPABASE_ANON_KEY</code>. You can find your url and anon_key on the dashboard of your Supabase project. </p>
<p>Your <code>.env.local</code> file will look like this:</p>
<pre><code>VITE_SUPABASE_URL=YOUR_SUPABASE_URL
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
</code></pre><p>We also want to create a central store for data that is needed throughout the app, like user info. Create a <code>store.js</code> file in the <code>src</code> folder and fill it with this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { reactive } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> store = {
  <span class="hljs-attr">state</span>: reactive({
    <span class="hljs-attr">user</span>: {},
  }),
};
</code></pre>
<h3 id="heading-create-signin-and-signup-components">Create SignIn and SignUp Components</h3>
<p>Supabase authentication separates the <code>signIn</code> and <code>signUp</code> processes, so we'll need to handle them differently. I decided to create two separate components just to make things a little clearer in my head.</p>
<p>Create a <code>SignUp.vue</code> file in the components folder and add the following code:</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">h2</span>&gt;</span>Sign up for an account<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> @<span class="hljs-attr">submit.prevent</span>=<span class="hljs-string">"handleSignup"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"password"</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</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">v-model</span>=<span class="hljs-string">"password"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Sign up<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 class="hljs-tag">&lt;/<span class="hljs-name">form</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">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../supabase"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  setup() {
    <span class="hljs-keyword">const</span> email = ref(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">const</span> password = ref(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">const</span> handleSignup = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Use the Supabase provided method to handle the signup</span>
        <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase.auth.signUp({
          <span class="hljs-attr">email</span>: email.value,
          <span class="hljs-attr">password</span>: password.value,
        });
        <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;
      } <span class="hljs-keyword">catch</span> (error) {
        alert(error.error_description || error.message);
      }
    };

    <span class="hljs-keyword">return</span> {
      email,
      password,
      handleSignup,
    };
  },
};
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre>
<p>Now create a <code>SignIn.vue</code> file and add the code below. The only differences are the method names that get called, and the text is slightly different in the markup.</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">h2</span>&gt;</span>Sign in to your account<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> @<span class="hljs-attr">submit.prevent</span>=<span class="hljs-string">"handleSignin"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"password"</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</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">v-model</span>=<span class="hljs-string">"password"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Sign in<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 class="hljs-tag">&lt;/<span class="hljs-name">form</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">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../supabase"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  setup() {
    <span class="hljs-keyword">const</span> email = ref(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">const</span> password = ref(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">const</span> handleSignin = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Use the Supabase provided method to handle the signin</span>
        <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase.auth.signIn({
          <span class="hljs-attr">email</span>: email.value,
          <span class="hljs-attr">password</span>: password.value,
        });
        <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;
      } <span class="hljs-keyword">catch</span> (error) {
        alert(error.error_description || error.message);
      }
    };

    <span class="hljs-keyword">return</span> {
      email,
      password,
      handleSignin,
    };
  },
};
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre>
<p>Now we want to create a wrapper component for these two. Create a file named <code>Auth.vue</code> with the code below:</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">sign-up</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"isSignUp"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">sign-in</span> <span class="hljs-attr">v-else</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"isSignUp = !isSignUp"</span>&gt;</span>
      {{
        isSignUp
          ? "Already have an account? Sign In"
          : "Don't have an account yet? Sign Up"
      }}
    <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">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;
<span class="hljs-keyword">import</span> SignUp <span class="hljs-keyword">from</span> <span class="hljs-string">"./SignUp.vue"</span>;
<span class="hljs-keyword">import</span> SignIn <span class="hljs-keyword">from</span> <span class="hljs-string">"./SignIn.vue"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: { SignUp, SignIn },
  setup() {
    <span class="hljs-keyword">const</span> isSignUp = ref(<span class="hljs-literal">true</span>);

    <span class="hljs-keyword">return</span> {
      isSignUp,
    };
  },
};
</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>This just allows the user to toggle between the <code>SignIn</code> and <code>SignUp</code> views. Now open up <code>App.vue</code> again and update the code to this:</p>
<pre><code class="lang-js">&lt;template&gt;
  &lt;!-- Check <span class="hljs-keyword">if</span> user is available <span class="hljs-keyword">in</span> the store, <span class="hljs-keyword">if</span> not show auth compoenent --&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Auth</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!store.state.user"</span> /&gt;</span></span>
  &lt;!-- If user is available, show the Hello World component --&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">HelloWorld</span> <span class="hljs-attr">v-else</span> <span class="hljs-attr">msg</span>=<span class="hljs-string">"Hello Vue 3 + Vite"</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">import</span> Auth <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Auth.vue"</span>;
<span class="hljs-keyword">import</span> HelloWorld <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/HelloWorld.vue"</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> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"./supabase"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: {
    HelloWorld,
    Auth,
  },
  setup() {
    <span class="hljs-comment">// we initially verify if a user is logged in with Supabase</span>
    store.state.user = supabase.auth.user();
    <span class="hljs-comment">// we then set up a listener to update the store when the user changes either by logging in or out</span>
    supabase.auth.onAuthStateChange(<span class="hljs-function">(<span class="hljs-params">event, session</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (event == <span class="hljs-string">"SIGNED_OUT"</span>) {
        store.state.user = <span class="hljs-literal">null</span>;
      } <span class="hljs-keyword">else</span> {
        store.state.user = session.user;
      }
    });

    <span class="hljs-keyword">return</span> {
      store,
    };
  },
};
</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>&gt;</span><span class="css">
<span class="hljs-selector-id">#app</span> {
  <span class="hljs-attribute">font-family</span>: Avenir, Helvetica, Arial, sans-serif;
  <span class="hljs-attribute">-webkit-font-smoothing</span>: antialiased;
  <span class="hljs-attribute">-moz-osx-font-smoothing</span>: grayscale;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#2c3e50</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">60px</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>This will show the <code>Auth</code> component if a user is not signed in, otherwise it will show the <code>HelloWorld.vue</code> as we had initially set up.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screen-Shot-2022-02-09-at-10.14.27-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sign up form</em></p>
<p>Sign up using your email and a password you create, and you should then see the HelloWorld component again.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screen-Shot-2022-02-09-at-10.18.58-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Hello World component showing after sign up</em></p>
<h3 id="heading-how-to-log-out">How to log out</h3>
<p>Logging out is relatively straightforward. Inside the HelloWorld component, add the following to the bottom of the template tag:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"signOut"</span>&gt;</span>Sign Out<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>Then update the script tag on HelloWorld to this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">setup</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../supabase"</span>;

defineProps({
  <span class="hljs-attr">msg</span>: <span class="hljs-built_in">String</span>,
});

<span class="hljs-keyword">const</span> count = ref(<span class="hljs-number">0</span>);
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">signOut</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase.auth.signOut();
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>You can see we are now importing the <code>supabase</code> file we created earlier and then creating a <code>signOut</code> method that gets called on a button click. </p>
<h3 id="heading-authenticate-using-magic-link">Authenticate using Magic Link</h3>
<p>Supabase also offers the ability to send users a magic link to their email which they click, and it takes them to the app and signs them in. The link it sends will redirect them to your site, so we need to make sure we have the correct redirect URL in our Supabase setup. </p>
<p>Navigate to the Auth -&gt; Settings page in the Supabase dashboard for your project and make sure the localhost URL is in the <code>Site URL</code> box. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screen-Shot-2022-02-09-at-10.24.13-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Make sure your site url matches where it should redirect to on login</em></p>
<h4 id="heading-create-the-magiclink-component">Create the MagicLink component</h4>
<p>Create a new file in the components folder called <code>MagicLink.vue</code> and add the following code:</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">h2</span>&gt;</span>Sign in With Magic Link<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> @<span class="hljs-attr">submit.prevent</span>=<span class="hljs-string">"handleMagicLink"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Sign in<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 class="hljs-tag">&lt;/<span class="hljs-name">form</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">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../supabase"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  setup() {
    <span class="hljs-keyword">const</span> email = ref(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">const</span> handleMagicLink = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// We call the signIn method from Supabase to send the magic link. We only pass it the email though.</span>
        <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase.auth.signIn({
          <span class="hljs-attr">email</span>: email.value,
        });
        <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;
      } <span class="hljs-keyword">catch</span> (error) {
        alert(error.error_description || error.message);
      }
    };

    <span class="hljs-keyword">return</span> {
      email,
      handleMagicLink,
    };
  },
};
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre>
<p>This component is very similar to the <code>SignIn</code> component. It uses the same method, but to get the magic link, we only pass in the email. </p>
<p>Now we need to update <code>Auth.vue</code> to also use the <code>MagicLink</code> component. Update <code>Auth.vue</code> to the following:</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-comment">&lt;!-- v-if logic to determine which auth component to show --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">sign-up</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"isSignUp &amp;&amp; !useMagicLink"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">sign-in</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"!isSignUp &amp;&amp; !useMagicLink"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">magic-link</span> <span class="hljs-attr">v-else</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">"!useMagicLink"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!useMagicLink"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"isSignUp = !isSignUp"</span>&gt;</span>
        {{
          isSignUp
            ? "Already have an account? Sign In"
            : "Don't have an account yet? Sign Up"
        }}
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Or<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"toggleMagicLink"</span>&gt;</span>
      {{
        useMagicLink
          ? "Sign in with email and password"
          : "Sign in with magic link"
      }}
    <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">import</span> { ref } <span class="hljs-keyword">from</span> <span class="hljs-string">"vue"</span>;
<span class="hljs-keyword">import</span> SignUp <span class="hljs-keyword">from</span> <span class="hljs-string">"./SignUp.vue"</span>;
<span class="hljs-keyword">import</span> SignIn <span class="hljs-keyword">from</span> <span class="hljs-string">"./SignIn.vue"</span>;
<span class="hljs-keyword">import</span> MagicLink <span class="hljs-keyword">from</span> <span class="hljs-string">"./MagicLink.vue"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: { SignUp, SignIn, MagicLink },
  setup() {
    <span class="hljs-keyword">const</span> isSignUp = ref(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> useMagicLink = ref(<span class="hljs-literal">false</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toggleMagicLink</span>(<span class="hljs-params"></span>) </span>{
      useMagicLink.value = !useMagicLink.value;
    }

    <span class="hljs-keyword">return</span> {
      isSignUp,
      useMagicLink,

      toggleMagicLink,
    };
  },
};
</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>Now the Auth page should look like this by default:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screen-Shot-2022-02-09-at-10.50.35-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Default Auth view</em></p>
<p>And it should look like this if the user clicks on the "Sign in with magic link" button:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Screen-Shot-2022-02-09-at-10.50.42-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Auth view when signing in with magic link</em></p>
<p>If you input your email and click "Sign In", you should get an email with the magic link. Click that link, and you should be redirected to the app as a logged in user, where you'll see the HelloWorld view. </p>
<h2 id="heading-summary">Summary</h2>
<p>Supabase makes setting up authentication relatively easy. They also provide authentication using several social providers like Google, Apple, Github, and many more. </p>
<p>For my basic projects, I like to keep it simple and stick with email/password login or just letting Supabase send a magic link to log them in. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Vue vs React – How to Go from One Framework to the Other ]]>
                </title>
                <description>
                    <![CDATA[ By Yiğit Kemal Erinç These days, a new trending front-end framework is released every now and then. But React and Vue.js still stand as the most popular among all the other alternatives.  And although both are performant, elegant, and arguably easy t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/vue-vs-react-comparison-of-frameworks/</link>
                <guid isPermaLink="false">66d45e4d052ad259f07e4aaf</guid>
                
                    <category>
                        <![CDATA[ framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 22 Oct 2021 21:59:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/10/pexels-ryutaro-tsukata-5472355.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yiğit Kemal Erinç</p>
<p>These days, a new trending front-end framework is released every now and then. But React and Vue.js still stand as the most popular among all the other alternatives. </p>
<p>And although both are performant, elegant, and arguably easy to learn, they have some different opinions on how certain things should be done, and different ways of achieving the same end result.</p>
<p>I believe getting comfortable and efficient with a frontend framework is mostly about learning the patterns of doing regular stuff.</p>
<p>You know, how to listen to changes of a parameter/data and perform some action on that. And how to bind an event listener or data to an action object (button, checkbox, etc) and so on. </p>
<p>While I was working on a side-project with React, I noticed that my mind was like: "Yeah, I could do it like this in Vue, I would emit an event from the child, then listen for it in the parent and update this data". And then I was Googling how to do something like that in React.</p>
<p>In this article, I am going to show you how to apply some common patterns in both React and Vue that you'll come across in your daily front-end work. Then you can use these recipes to easily transition from one framework to the other one.</p>
<p>This will be helpful whether you are an experienced Vue developer who needs to work on a React project or the other way around. I will be using modern React with hooks and the Vue Options API (Vue 2). </p>
<p>I suggest cloning the <a target="_blank" href="https://github.com/yigiterinc/VueVsReact">repository</a> that contains all the code I use in this article and rendering the respective components in each section and playing with them to really understand how they work. </p>
<p>After cloning, you need to run <strong>npm install</strong> in the React and Vue folders. Then you can start the React project with <strong>npm start</strong> and the Vue project with <strong>npm run serve</strong>.</p>
<pre><code>https:<span class="hljs-comment">//github.com/yigiterinc/VueVsReact</span>
</code></pre><h3 id="heading-table-of-contents">Table of Contents</h3>
<ul>
<li><a class="post-section-overview" href="#heading-component-structure">Component Structure in React vs Vue</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-state">How to use State in React and Vue</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-props">How to Use Props in Vue and React</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-methodsfunctions">How to Create Methods/Functions in Vue and React</a></li>
<li><a class="post-section-overview" href="#heading-styling-options">Styling Options</a></li>
<li><a class="post-section-overview" href="#heading-how-to-bind-form-input-to-data-state">How to Bind Form Input to Data (State)</a></li>
<li><a class="post-section-overview" href="#heading-handling-events-user-input">How to Handle Events (User Input)</a></li>
<li><a class="post-section-overview" href="#heading-conditional-styling">Conditional Styling</a></li>
<li><a class="post-section-overview" href="#heading-conditional-rendering">Conditional Rendering</a></li>
<li><a class="post-section-overview" href="#heading-rendering-arrays-lists">Rendering Arrays (Lists)</a></li>
<li><a class="post-section-overview" href="#heading-child-to-parent-communication">Child to Parent Communication</a></li>
<li><a class="post-section-overview" href="#heading-reacting-to-datastate-changes">Reacting to Data/State Changes</a></li>
<li><a class="post-section-overview" href="#heading-computed-properties-vs-usememo">Computed Properties vs useMemo</a></li>
<li><a class="post-section-overview" href="#heading-vue-slots-vs-render-props">Vue Slots vs Render Props</a></li>
</ul>
<h2 id="1">Component Structure</h2>

<p>Let's take a bird's eye look into some very basic components in both frameworks. We will extend this in the following sections.</p>
<p>In Vue, a Single File Component contains 3 parts: the template, script and style.</p>
<p>The template is the part that will be rendered. It contains the HTML of the component and has access to the data (and methods) in the scripts and the styles.</p>
<p>You can find everything about a component inside these sections in Vue.</p>
<pre><code class="lang-javascript">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"structure"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello from Vue<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

&lt;!-- Use preprocessors via the lang attribute! e.g. &lt;style lang=<span class="hljs-string">"scss"</span>&gt; --&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
<span class="hljs-selector-id">#structure</span> {
  <span class="hljs-attribute">font-family</span>: Avenir, Helvetica, Arial, sans-serif;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#2c3e50</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">60px</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>To get this component rendered without a router or other complicated things, you can add it to <strong>App.vue.</strong> I suggest you render every component as you follow along so you can see them in action:</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><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">structure</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">import</span> Structure <span class="hljs-keyword">from</span> <span class="hljs-string">'./Structure/Structure.vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'App'</span>,
  <span class="hljs-attr">components</span>: { Structure },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre>
<p>You will be changing the import component inside the <strong>components</strong> section and the tag name in the <strong>template</strong> section.</p>
<p>In React, a functional component is a function that returns <a target="_blank" href="https://reactjs.org/docs/introducing-jsx.html">JSX</a> (an extension of JavaScript that allows you to use HTML tags inside JS code). You can think as if it is returning HTML to simplify things. The part that will be rendered used to be written inside the <code>render()</code> function in class-based React, if you are more familiar with that. </p>
<p>As you progress in this tutorial, in each section you can put the respective components inside App.js to get them rendered like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Structure</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Render me App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Structure
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>

<span class="hljs-keyword">import</span> Structure <span class="hljs-keyword">from</span> <span class="hljs-string">'./Structure/Structure'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Structure</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>So you will change the import and the component inside the div.</p>
<h2 id="2">How to Use State</h2>

<p>In Vue, we learned that the script tag contains the data and methods related to the component. The Vue Options API has special keywords (options) such as <em>data, methods, props, computed, watch,</em> and <em>mixins</em> that we can use, as well as lifecycle methods such as <em>created</em> and <em>mounted</em>. </p>
<p>We will use the <code>data</code> option to use state in our component. The data should be defined as a function which returns an object that contains our states. </p>
<p>To access the state inside our HTML (template), we have to use double curly braces and write the name of our variable. Keep in mind that any change to data variables will result in a render if that variable is used (referenced) in the HTML.</p>
<pre><code class="lang-javascript">&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">h1</span>&gt;</span>Hello {{ currentFramework }}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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> {
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">currentFramework</span>: <span class="hljs-string">' Vue!'</span>,
      <span class="hljs-attr">alternative</span>: <span class="hljs-string">' React!'</span>,
    }
  },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

&lt;!-- Use preprocessors via the lang attribute! e.g. &lt;style lang=<span class="hljs-string">"scss"</span>&gt; --&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>In React, functional components used to be stateless. But thanks to hooks, we now have the <code>useState</code> hook to store state inside our component. To use the useState hook we have to import it, and the syntax is:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;


<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [stateName, setStateName] = useState(<span class="hljs-string">'default value'</span>); 
}
</code></pre>
<p>We define the name of the state variable and name of its setter function inside the brackets, then we pass the default value of our variable to the useState hook. </p>
<p>You can imagine the hook like this to understand the syntax better: It is like a function that creates a variable, sets its value to the passed value, then returns an array which contains the variable and its setter function. </p>
<p>Note that you should use a single pair of curly parenthesis to switch to JavaScript scope and print a variable inside your JSX, instead of double parenthesis, which was the case with Vue.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { React, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TestUseState</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [frameworkName, setFrameworkName] = useState(<span class="hljs-string">'React'</span>)

  <span class="hljs-keyword">return</span> (
    <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">h1</span>&gt;</span>useState API<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Current Framework: {frameworkName}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TestUseState
</code></pre>
<h2 id="3">How to Use Props</h2>

<p>In Vue, we define props by adding the props option inside the object we export inside the script field like we did with the data option. It is a best practice to define the props as objects so we get more control over how they are used. </p>
<p>For example, specify their types, default values, and make them required if necessary. Vue will show a warning if you use the component wrong, like calling it without passing a required prop. </p>
<p>Let's say we have an Address child component that will be called from the <code>UserInfo</code> parent component.</p>
<pre><code class="lang-javascript">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"address"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>City: {{ city }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Street: {{ street }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>House No: {{ houseNumber }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Postal Code: {{ postalCode }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</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> {
  data() {
    <span class="hljs-keyword">return</span> {}
  },
  <span class="hljs-attr">props</span>: {
    <span class="hljs-attr">city</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">default</span>: <span class="hljs-string">'Munich'</span>,
    },
    <span class="hljs-attr">street</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">houseNumber</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Number</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
    <span class="hljs-attr">postalCode</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">Number</span>,
      <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>,
    },
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>We can access our props just like our data variables – using the double parenthesis inside the template. And we can pass the props from the parent like this:</p>
<pre><code class="lang-javascript">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"address"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Name: Yigit<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Address</span>
      <span class="hljs-attr">street</span>=<span class="hljs-string">"randomStrasse"</span>
      <span class="hljs-attr">:postalCode</span>=<span class="hljs-string">"80999"</span>
      <span class="hljs-attr">:houseNumber</span>=<span class="hljs-string">"32"</span>
    &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">Address</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">import</span> Address <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/Address.vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  data() {
    <span class="hljs-keyword">return</span> {}
  },
  <span class="hljs-attr">components</span>: {
    Address,
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>Notice how we use the v-bind shorthand <code>:</code> and write <code>:postalCode</code> and <code>:houseNumber</code> to indicate that these are not strings but Number type objects. We have to use this syntax whenever we need to pass anything other than a string (array, object, number, and so on). </p>
<p>This might confuse you if you are coming from React, so you might want to read more about <a target="_blank" href="https://vuejs.org/v2/guide/class-and-style.html">v-bind</a> to get a better understanding of how it works.</p>
<p>In React, we do not need to explicitly define what props will be passed in the child component. We can either use object destructuring to assign props to variables or access them using the props object. We access our props inside JSX, just like how we access the state.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Address</span>(<span class="hljs-params">{ city, street, postalCode, houseNumber }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <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>City: {city}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Street: {street}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Postal Code: {postalCode}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>House Number: {houseNumber}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Address
</code></pre>
<p>And we can pass the props from the parent like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserInfo</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <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>Name: Yigit<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Address</span>
        <span class="hljs-attr">city</span>=<span class="hljs-string">"Istanbul"</span>
        <span class="hljs-attr">street</span>=<span class="hljs-string">"Ataturk Cad."</span>
        <span class="hljs-attr">postalCode</span>=<span class="hljs-string">"34840"</span>
        <span class="hljs-attr">houseNumber</span>=<span class="hljs-string">"92"</span>
      &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">Address</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> UserInfo
</code></pre>
<h2 id="4">How to Create Methods/Functions</h2>

<p>In Vue, we define methods similarly to data – we can just put a methods option under the data and define the method. We can call these methods from the template and methods can access/modify our data.</p>
<pre><code class="lang-javascript">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    {{ sayHello() }}
  <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> {
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">to</span>: <span class="hljs-string">'Methods'</span>,
    }
  },
  <span class="hljs-attr">methods</span>: {
    sayHello() {
      <span class="hljs-keyword">return</span> <span class="hljs-string">'Hello '</span> + <span class="hljs-built_in">this</span>.to
    },
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>Be careful when trying to access component methods or data properties from inside the exported object (code inside script tag). If you don't include the <code>this</code> keyword, Vue will show an error saying it does not know where that property/method is.</p>
<p>In React, things are a bit more simple. It is just the regular JS function definition, with ES6 syntax, if you'd like.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HelloFunctions</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> to = <span class="hljs-string">'Functions'</span>

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sayHello</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">'Hello '</span> + to
  }

  <span class="hljs-keyword">const</span> sayHelloModern = <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'Hello '</span> + to

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {sayHello()}
      <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
      {sayHelloModern()}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> HelloFunctions
</code></pre>
<h2 id="5">Styling Options</h2>

<p>Styling Vue components is really simple. We just need to write our plain old CSS classes and selectors inside the <code>style</code> tag. </p>
<p>Vue also supports scoped CSS by using the <code>scoped</code> keyword. It helps to avoid visual bugs caused by assigning the same class name inside different components. For example, you could name the main container in all your components <code>main-container</code> and only the styles in that component file would be applied to each main-container. </p>
<pre><code class="lang-javascript">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"main-container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"label"</span>&gt;</span>I am a styled label<span class="hljs-tag">&lt;/<span class="hljs-name">h3</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> {
  data() {
    <span class="hljs-keyword">return</span> {}
  },
}
</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="css">
<span class="hljs-selector-class">.main-container</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">45%</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>);
  <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-class">.label</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">300</span>;
  <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">text-transform</span>: uppercase;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>In React, though, we have more options in terms of styling and it's basically up to your personal preference since there are multiple ways to style your components. I will suggest a few good options here.</p>
<h3 id="heading-1-writing-regular-css-in-a-css-file-and-importing-it">1) Writing regular CSS in a .css file and importing it</h3>
<p>This is probably the most basic and straightforward approach for applying styles to your React components. It does not mean it is a bad approach, as it allows you to write plain old CSS. It is a good method if you are a CSS guru who is just getting started with React. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./styles.css'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Styled</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <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">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title"</span>&gt;</span>I am red<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Styled
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.title</span> {
  <span class="hljs-attribute">color</span>: red;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">30px</span>;
}
</code></pre>
<h3 id="heading-2-using-material-ui-usestylesmakestyles">2) Using Material UI (useStyles/makeStyles)</h3>
<p>Material UI is a CSS framework that has so many reusable components. It also provides a way to style your components, which uses CSS in JS and therefore has its advantages such as scoped CSS. </p>
<p>The <code>makeStyles</code> hook receives a list of classes in an object, then you can use those classes by assigning them to objects. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { makeStyles } <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/styles'</span>;
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core/Button'</span>;

<span class="hljs-keyword">const</span> useStyles = makeStyles({
  <span class="hljs-attr">root</span>: {
    <span class="hljs-attr">background</span>: <span class="hljs-string">'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)'</span>,
    <span class="hljs-attr">border</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">borderRadius</span>: <span class="hljs-number">3</span>,
    <span class="hljs-attr">boxShadow</span>: <span class="hljs-string">'0 3px 5px 2px rgba(255, 105, 135, .3)'</span>,
    <span class="hljs-attr">color</span>: <span class="hljs-string">'white'</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">48</span>,
    <span class="hljs-attr">padding</span>: <span class="hljs-string">'0 30px'</span>,
  },
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Hook</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> classes = useStyles();
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{classes.root}</span>&gt;</span>Hook<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span></span>;
}
</code></pre>
<h3 id="heading-3-using-styled-components-css-in-js">3) Using Styled Components (CSS in JS)</h3>
<p><a target="_blank" href="https://styled-components.com/">Styled components</a> are modern and easy to use and it allows you to take advantage of all the features of plain CSS as well. </p>
<p>In my opinion, it is easier to use and more powerful than MaterialUI (you can also style MaterialUI components with this, instead of using <code>makeStyles</code>). It's also better than importing a CSS file since it is scoped and styled components are reusable.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> styled, { css } <span class="hljs-keyword">from</span> <span class="hljs-string">'styled-components'</span>

<span class="hljs-comment">// Use Title and Wrapper like any other React component – except they're styled!</span>
<span class="hljs-keyword">const</span> Title = styled.h1<span class="hljs-string">`
  font-size: 2em;
  text-align: center;
  color: palevioletred;
`</span>

<span class="hljs-comment">// Create a Wrapper component that'll render a &lt;section&gt; tag with some styles</span>
<span class="hljs-keyword">const</span> Wrapper = styled.section<span class="hljs-string">`
  padding: 4em;
  background: papayawhip;
  height: 100vh;
`</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">StyledComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Wrapper</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Title</span>&gt;</span>Hello World!<span class="hljs-tag">&lt;/<span class="hljs-name">Title</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Wrapper</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> StyledComponent
</code></pre>
<h2 id="6">How to Bind Form Input to Data (State)</h2>


<p>We have learned how to have state inside our components but we also need a way to bind user inputs to that state. For example in login forms, we will probably need to store the user's username and password input in the component state. React and Vue have different ways of keeping user inputs in sync with state.</p>
<p>In Vue we have a special directive for this operation called <a target="_blank" href="https://vuejs.org/v2/guide/forms.html">v-model</a>. To use this, you need to create a state by using the <code>data</code> property as we have learned before. Then you add the v-model keyword to your input and specify which data variable is responsible for storing this input (this is applicable to form input, textarea and select elements). </p>
<p>This is a high-level and clean way to connect data, removing the need to create additional lambda functions or handlers. </p>
<pre><code class="lang-javascript">&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">input</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"inputState"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
    {{ inputState }}
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"changeInputState()"</span>&gt;</span>Click to say goodbye<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> {
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">inputState</span>: <span class="hljs-string">'Hello'</span>,
    }
  },
  <span class="hljs-attr">methods</span>: {
    <span class="hljs-attr">changeInputState</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-built_in">this</span>.inputState = <span class="hljs-string">'Goodbye'</span>
    },
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>Here is a small example: we have a text input, and we connect it to the <code>inputState</code> variable by using the v-model keyword. So whenever the user inputs text, the <code>inputState</code> variable will reflect the changes automatically. </p>
<p>However, there is one special thing that you need to know: v-model implements <strong>2-way data binding</strong> in contrast to <strong>1-way binding</strong> in React. </p>
<p>This means that, not only when you change the input does the data change, but also, if you change the data, the input value changes as well. </p>
<p>To demonstrate this, I have created a button and connected it to a method. Don't worry about the event handling yet, we will see that in next section. When the button is clicked, the value of inputState variable is changed and the input also changes when that happens. </p>
<p>I encourage you to try it yourself by running the code. Also, notice that the initial value of your input box is 'Hello' – it is not initialized to empty string or null because we set the <code>inputState</code> variable to 'Hello'.</p>
<p>Now let's see it in React:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { React, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FormInputBinding</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [userInput, setUserInput] = useState(<span class="hljs-string">'Hello'</span>)

  <span class="hljs-keyword">return</span> (
    <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">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setUserInput(e.target.value)} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setUserInput('Goodbye')}&gt;
        Click to say goodbye
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      {userInput}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> FormInputBinding
</code></pre>
<p>This topic overlaps with handling user events so if you do not understand something, wait until you complete the next section. Here, we handle the <code>onChange</code> event manually and call the <code>setUserInput</code> function to set the state to the event's value. </p>
<p>As we mentioned earlier, React uses a <strong>1-way binding</strong> model. This means that changing the userInput state will not affect the value we see inside the text input – we won't see Hello inside the input box initially. Also when we click the button, it will update the state but the input inside the box will maintain its value.</p>
<h2 id="7">Handling Events (User Input)</h2>

<p>Let's see another form that is closer to real-life cases in Vue and React:</p>
<pre><code class="lang-javascript">&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">input</span>
      <span class="hljs-attr">v-model</span>=<span class="hljs-string">"username"</span>
      <span class="hljs-attr">id</span>=<span class="hljs-string">"outlined-basic"</span>
      <span class="hljs-attr">label</span>=<span class="hljs-string">"Username"</span>
      <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
      <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span>
      <span class="hljs-attr">id</span>=<span class="hljs-string">"outlined-basic"</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
      <span class="hljs-attr">label</span>=<span class="hljs-string">"Password"</span>
      <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
    /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
      <span class="hljs-attr">v-model</span>=<span class="hljs-string">"termsAccepted"</span>
      <span class="hljs-attr">id</span>=<span class="hljs-string">"outlined-basic"</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
      <span class="hljs-attr">label</span>=<span class="hljs-string">"Password"</span>
      <span class="hljs-attr">variant</span>=<span class="hljs-string">"outlined"</span>
    /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"contained"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"submitForm"</span>&gt;</span>
      Submit
    <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> {
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">username</span>: <span class="hljs-string">''</span>,
      <span class="hljs-attr">password</span>: <span class="hljs-string">''</span>,
      <span class="hljs-attr">termsAccepted</span>: <span class="hljs-literal">false</span>,
    }
  },
  <span class="hljs-attr">methods</span>: {
    <span class="hljs-attr">submitForm</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.username, <span class="hljs-built_in">this</span>.password, <span class="hljs-built_in">this</span>.termsAccepted)
    },
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>As you can see, we are using the v-model property that we just learned about to connect all our inputs to data properties (state). So, whenever the inputs change, Vue automatically updates the corresponding variable. </p>
<p>To see how we handle a click event on button, check the submit Button. We use the <a target="_blank" href="https://vuejs.org/v2/guide/events.html">v-on</a> keyword to handle click event. <code>@click</code> is just a shorthand for <code>v-on:click</code>.</p>
<p>Whenever a click event happens it simply calls the <code>submitForm</code> method. You can familiarize yourself with the list of possible events by going through the linked docs.</p>
<p>In React, we can have a form like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { React, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">import</span> {
  TextField,
  Checkbox,
  FormControlLabel,
  Button,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@material-ui/core'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">EventHandling</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> [username, setUsername] = useState(<span class="hljs-string">''</span>)
  <span class="hljs-keyword">let</span> [password, setPassword] = useState(<span class="hljs-string">''</span>)
  <span class="hljs-keyword">let</span> [termsAccepted, setTermsAccepted] = useState(<span class="hljs-literal">false</span>)

  <span class="hljs-keyword">const</span> submitForm = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(username, password, termsAccepted)
  }

  <span class="hljs-keyword">const</span> formContainer = {
    <span class="hljs-attr">display</span>: <span class="hljs-string">'flex'</span>,
    <span class="hljs-attr">flexDirection</span>: <span class="hljs-string">'column'</span>,
    <span class="hljs-attr">alignItems</span>: <span class="hljs-string">'center'</span>,
    <span class="hljs-attr">gap</span>: <span class="hljs-string">'20px'</span>,
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{formContainer}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
        <span class="hljs-attr">onInput</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setUsername(e.target.value)}
        id="outlined-basic"
        label="Username"
        variant="outlined"
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">TextField</span>
        <span class="hljs-attr">onInput</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPassword(e.target.value)}
        id="outlined-basic"
        type="password"
        label="Password"
        variant="outlined"
      /&gt;

      <span class="hljs-tag">&lt;<span class="hljs-name">FormControlLabel</span>
        <span class="hljs-attr">control</span>=<span class="hljs-string">{</span>
          &lt;<span class="hljs-attr">Checkbox</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
            <span class="hljs-attr">checked</span>=<span class="hljs-string">{termsAccepted}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTermsAccepted(e.target.checked)}
          /&gt;
        }
        label="Accept terms and conditions"
      /&gt;

      <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"contained"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> submitForm()}&gt;
        Submit
      <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>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> EventHandling
</code></pre>
<p>We create our state variables for each input. We can then listen to events on inputs and the event will be accessible inside the handler function. We call the state setters to update our state as a response to these events. </p>
<h2 id="8">Conditional Styling</h2>

<p>Conditional Styling means binding a class or style to an element if a condition is true. </p>
<p>In Vue it can be achieved like this:</p>
<pre><code class="lang-javascript">&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">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"toggleApplyStyles"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">:class</span>=<span class="hljs-string">"{ textStyle: stylesApplied }"</span>&gt;</span>
      Click the button to {{ stylesApplied ? 'unstyle' : 'style' }} me
    <span class="hljs-tag">&lt;/<span class="hljs-name">p</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> {
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">stylesApplied</span>: <span class="hljs-literal">false</span>,
    }
  },
  <span class="hljs-attr">methods</span>: {
    <span class="hljs-attr">toggleApplyStyles</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-built_in">this</span>.stylesApplied = !<span class="hljs-built_in">this</span>.stylesApplied
    },
  },
}
</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>&gt;</span><span class="css">
<span class="hljs-selector-class">.textStyle</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">25px</span>;
  <span class="hljs-attribute">color</span>: red;
  <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">120%</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>We create a paragraph and want to apply the <code>textStyle</code> class only when the <code>stylesApplied</code> data property's value is true. We can use v-bind to achieve this. The colon is the shorthand for v-bind so <code>:class</code> is same as <code>v-bind:class</code>. </p>
<p>We use v-bind object syntax to bind classes. We pass an object to the class property: {textStyle: stylesApplied}, which means apply the <code>textStyle</code> class if <code>stylesApplied</code> is true. </p>
<p>It is a bit complicated at the start but it helps us avoid multiple chained if statements to determine which class will be applied and handles style bindings in a clean way: class names on the left (object keys), conditions on the right (object values).</p>
<p>In React we have to do things more primitively.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { React, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./styles.css'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ConditionalStyling</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> [stylesApplied, setStylesApplied] = useState(<span class="hljs-literal">false</span>)

  <span class="hljs-keyword">return</span> (
    <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">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setStylesApplied(!stylesApplied)}&gt;Click me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">stylesApplied</span> ? '<span class="hljs-attr">red</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">green</span>' }}&gt;</span>Red or Green<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{stylesApplied</span> ? '<span class="hljs-attr">styleClass</span>' <span class="hljs-attr">:</span> ''}&gt;</span>Red with class<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ConditionalStyling
</code></pre>
<p>Here we use plain JavaScript to bind either a styles object or a class name to the element. I think this complicates the code a bit, and I'm not a huge fan of this syntax.</p>
<h2 id="9">Conditional Rendering</h2>

<p>Sometimes, we want to render a component after some operation – such as fetching data from an API – is completed. Or maybe we want to display an error message if there is an error or success message if not. </p>
<p>For such situations, we use conditional rendering to change the HTML to be rendered programmatically. </p>
<p>In Vue, there are <a target="_blank" href="https://vuejs.org/v2/guide/conditional.html">special directives</a> for that as well. We can use the <code>v-if</code> and <code>v-else</code> or even <code>v-else-if</code> for rendering templates based on conditions.</p>
<pre><code class="lang-javascript">&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">h2</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"condition1"</span>&gt;</span>condition1 is true<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">v-else-if</span>=<span class="hljs-string">"condition2"</span>&gt;</span>condition2 is true<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">v-else</span>&gt;</span>all conditions are false<span class="hljs-tag">&lt;/<span class="hljs-name">h2</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> {
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">condition1</span>: <span class="hljs-literal">false</span>,
      <span class="hljs-attr">condition2</span>: <span class="hljs-literal">false</span>,
    }
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>This syntax allows us to create complex chains of conditional rendering without complicating our template code with if else statements.</p>
<p>Here is one of the ways to accomplish the same output with React:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ConditionalRendering</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> condition1 = <span class="hljs-literal">false</span>
  <span class="hljs-keyword">const</span> condition2 = <span class="hljs-literal">false</span>

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getMessage</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> message = <span class="hljs-string">''</span>

    <span class="hljs-keyword">if</span> (condition1) {
      message = <span class="hljs-string">'condition1 is true'</span>
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (condition2) {
      message = <span class="hljs-string">'condition2 is true'</span>
    } <span class="hljs-keyword">else</span> {
      message = <span class="hljs-string">'all conditions are false'</span>
    }

    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{message}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
  }

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;&gt;</span>{getMessage()}<span class="hljs-tag">&lt;/&gt;</span></span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ConditionalRendering
</code></pre>
<p>This is just plain JS and JSX, no magic here.</p>
<h2 id="10">Rendering Arrays (Lists)</h2>

<p>Now let's see how we can render list data. In Vue, there is <code>v-for</code> keyword for doing this. The syntax <strong>name in names</strong> means the name variable will always hold the current name. As the index changes, if index is 0, it is <code>names[0]</code> and so on. We can also access the index as specifying it inside the parentheses. The <strong>v-for</strong> directive also requires a key.</p>
<pre><code class="lang-javascript">&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">h1</span>&gt;</span>Names<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(person, index) in people"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span>&gt;</span>{{ person.name }}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</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> {
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">people</span>: [
        {
          <span class="hljs-attr">id</span>: <span class="hljs-number">0</span>,
          <span class="hljs-attr">name</span>: <span class="hljs-string">'Yigit'</span>,
        },
        {
          <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
          <span class="hljs-attr">name</span>: <span class="hljs-string">'Gulbike'</span>,
        },
        {
          <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>,
          <span class="hljs-attr">name</span>: <span class="hljs-string">'Mete'</span>,
        },
        {
          <span class="hljs-attr">id</span>: <span class="hljs-number">3</span>,
          <span class="hljs-attr">name</span>: <span class="hljs-string">'Jason'</span>,
        },
        {
          <span class="hljs-attr">id</span>: <span class="hljs-number">4</span>,
          <span class="hljs-attr">name</span>: <span class="hljs-string">'Matt'</span>,
        },
        {
          <span class="hljs-attr">id</span>: <span class="hljs-number">5</span>,
          <span class="hljs-attr">name</span>: <span class="hljs-string">'Corey'</span>,
        },
      ],
    }
  },
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre>
<p>Note that we can also use the <strong>v-for</strong> directive for iterating over properties of an object. Remember that, in JS, arrays are just a special subset of objects with number keys. </p>
<p>In React, we will use the <code>Arrays.map</code> function to iterate over the array and return a JSX tag for each element.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RenderingLists</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> cities = [
    <span class="hljs-string">'Istanbul'</span>,
    <span class="hljs-string">'München'</span>,
    <span class="hljs-string">'Los Angeles'</span>,
    <span class="hljs-string">'London'</span>,
    <span class="hljs-string">'San Francisco'</span>,
  ]

  <span class="hljs-keyword">return</span> (
    <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">h1</span>&gt;</span>Cities<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {cities.map((city, index) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">h4</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>{city}<span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> RenderingLists
</code></pre>
<h2 id="11">Child to Parent Communication</h2>

<p>Imagine you have a form component and a button sub-component inside it. And you want to perform some action when that button is clicked, like calling an API to submit data – but you do not have access to the form data in the button component since it is stored in the parent. What do you do?</p>
<p>Well, if you are in Vue, you want to emit a custom event from the child and act on that in the parent. In React, you would create the function that will be executed (when button is clicked) in the parent, where the function has access to form data and pass it to the button component so that it can call the parent's function. </p>
<p>Let's see an example in Vue:</p>
<pre><code class="lang-javascript">&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">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"buttonClicked"</span>&gt;</span>Submit<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">methods</span>: {
    <span class="hljs-attr">buttonClicked</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-built_in">this</span>.$emit(<span class="hljs-string">'buttonClicked'</span>) <span class="hljs-comment">// Emits a buttonClicked event to parent</span>
    },
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>In our child component, we have the button and on click we emit a <code>buttonClicked</code> event. We could also send data in this call. For example if this was a text input box instead of a button and had its own data, we could send that data to the parent with emit. </p>
<p>In the parent component, we need to listen for the custom <code>buttonClicked</code> event that we just created.</p>
<pre><code class="lang-javascript">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"#"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">child</span> @<span class="hljs-attr">buttonClicked</span>=<span class="hljs-string">"handleButtonClicked"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">form</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">import</span> Child <span class="hljs-keyword">from</span> <span class="hljs-string">'./Child.vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: { Child },
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">username</span>: <span class="hljs-string">''</span>,
    }
  },
  <span class="hljs-attr">methods</span>: {
    <span class="hljs-attr">handleButtonClicked</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.username)
    },
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>We just added a <code>@buttonClicked</code> event to our child component call to handle this custom event. </p>
<p>In React, we could achieve the same results by passing a handler function to the child component. The concept was a bit complicated to me first but the syntax is easier than the Vue example and there is no magic.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Child</span>(<span class="hljs-params">{ handleButtonClicked }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <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">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleButtonClicked()}&gt;Submit<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>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Child
</code></pre>
<p>We access the <code>handleButtonClicked</code> prop and call it when the button is clicked.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { React, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">import</span> Child <span class="hljs-keyword">from</span> <span class="hljs-string">'./Child.js'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Parent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">''</span>)

  <span class="hljs-keyword">const</span> submitForm = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(username)
    <span class="hljs-comment">// Post form data to api...</span>
  }

  <span class="hljs-keyword">return</span> (
    <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">input</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setUsername(e.target.value)} type="text" /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Child</span> <span class="hljs-attr">handleButtonClicked</span>=<span class="hljs-string">{submitForm}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Parent
</code></pre>
<p>In the parent, we pass the <code>submitForm</code> function as the <code>handleButtonClicked</code> prop which will do the job.</p>
<h2 id="12">Reacting to Data/State Changes</h2>

<p>In some cases, we need to react to data changes. For example, when you want to perform asynchronous or expensive operations in response to a change in data.</p>
<p> In Vue, we have <code>watch</code> properties or watchers for that. If you are familiar with <code>useEffect</code> in React, this is closest thing you can find in Vue and their use cases are more or less the same.</p>
<p>Let's see an example:</p>
<pre><code class="lang-javascript">&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">input</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"number1"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"number 1"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"number2"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"number 2"</span> /&gt;</span>
    {{ sum }}
  <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> {
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">number1</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">number2</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">sum</span>: <span class="hljs-number">0</span>,
    }
  },
  <span class="hljs-attr">watch</span>: {
    <span class="hljs-attr">number1</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">val</span>) </span>{
      <span class="hljs-built_in">this</span>.sum = <span class="hljs-built_in">parseInt</span>(val) + <span class="hljs-built_in">parseInt</span>(<span class="hljs-built_in">this</span>.number2)
    },
    <span class="hljs-attr">number2</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">val</span>) </span>{
      <span class="hljs-built_in">this</span>.sum = <span class="hljs-built_in">parseInt</span>(<span class="hljs-built_in">this</span>.number1) + <span class="hljs-built_in">parseInt</span>(val)
    },
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>Here, we have <code>number1</code> and <code>number2</code> defined in our data properties. We have 2 respective inputs and we are printing the sum of those numbers and we want sum to update when any of the inputs change. </p>
<p>Inside the <code>watch</code> property, we write the name of the variable we want to <strong>watch</strong>. In this case, we want to watch both number1 and number2. If the user enters an input, <code>v-model</code> will change the corresponding data variable and when that happens, the <strong>watch</strong> function for that variable will be triggered and the value of sum will be recalculated.</p>
<p>Note that, in a real application, you wouldn't need to use watch for this simple thing and you would just put sum inside <code>computed</code> instead. This is a made-up example to demonstrate how <code>watch</code> works. </p>
<p>Before using <code>watch</code> with more complicated things like objects, arrays, and nested structures, I suggest reading <a target="_blank" href="https://michaelnthiessen.com/how-to-watch-nested-data-vue/">this article</a> because you will probably need to learn some <code>watch</code> options like <code>deep</code> and <code>immediate</code>.</p>
<p>In React, we use the built-in <code>useEffect</code> hook to watch for changes.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { React, useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ReactToDataChanges</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [number1, setNumber1] = useState(<span class="hljs-number">0</span>)
  <span class="hljs-keyword">const</span> [number2, setNumber2] = useState(<span class="hljs-number">0</span>)
  <span class="hljs-keyword">const</span> [sum, setSum] = useState(<span class="hljs-number">0</span>)

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'I am here!'</span>)
    setSum(<span class="hljs-built_in">parseInt</span>(number1) + <span class="hljs-built_in">parseInt</span>(number2))
  }, [number1, number2])

  <span class="hljs-keyword">return</span> (
    <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">input</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setNumber1(e.target.value)}
        type="number"
        name="number 1"
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setNumber2(e.target.value)}
        type="number"
        name="number 2"
      /&gt;
      {sum}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ReactToDataChanges
</code></pre>
<p><code>useEffect</code> expects a function to run when a dependency changes as the first argument and a list of dependencies as the second argument. </p>
<p>Keep in mind that this is also a made-up example to demonstrate <code>useEffect</code> (we could achieve the same without <code>useEffect</code> by taking the sum variable out of state).</p>
<p>I want to show a very common use case for this hook: fetching data from an API after the component loads:</p>
<pre><code class="lang-javascript">useEffect(<span class="hljs-function">() =&gt;</span> {
    fetchUserData()
}, [])

<span class="hljs-keyword">const</span> fetchUserData = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> url = <span class="hljs-string">''</span>;
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(url);
    <span class="hljs-keyword">const</span> user = response.data;
    setUser(user);
}
</code></pre>
<p>We can specify empty array to run the <code>useEffect</code> once when the component renders. In Vue, we would do the same operation inside a lifecycle hook, such as <code>created</code> or <code>mounted</code>.</p>
<h2 id="13">Computed Properties vs useMemo</h2>

<p>Vue has a concept called computed properties, which serve the purpose of caching rather complex computations and re-evaluating their values whenever one of the dependencies change (similar to <code>watch</code>). </p>
<p>It is also useful in keeping our templates clean and concise by moving the logic to <strong>JavaScript</strong>. In this case, they act like regular variables which we don't want to be a state.</p>
<pre><code class="lang-javascript">&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">h3</span>&gt;</span>Yigit's Favorite Cities are:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"city in favCities"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"city"</span>&gt;</span>{{ city }}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Yigit's Favorite Cities in US are:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"town in favCitiesInUS"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"town"</span>&gt;</span>{{ town }}<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">click</span>=<span class="hljs-string">"addBostonToFavCities"</span>&gt;</span>
      Why is Boston not in there? Click to add
    <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">computed</span>: {
    <span class="hljs-attr">favCitiesInUS</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.favCities.filter(<span class="hljs-function">(<span class="hljs-params">city</span>) =&gt;</span> <span class="hljs-built_in">this</span>.usCities.includes(city))
    },
  },
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">favCities</span>: [
        <span class="hljs-string">'Istanbul'</span>,
        <span class="hljs-string">'München'</span>,
        <span class="hljs-string">'Los Angeles'</span>,
        <span class="hljs-string">'Rome'</span>,
        <span class="hljs-string">'Florence'</span>,
        <span class="hljs-string">'London'</span>,
        <span class="hljs-string">'San Francisco'</span>,
      ],
      <span class="hljs-attr">usCities</span>: [
        <span class="hljs-string">'New York'</span>,
        <span class="hljs-string">'Los Angeles'</span>,
        <span class="hljs-string">'Chicago'</span>,
        <span class="hljs-string">'Houston'</span>,
        <span class="hljs-string">'Phoenix'</span>,
        <span class="hljs-string">'Arizona'</span>,
        <span class="hljs-string">'San Francisco'</span>,
        <span class="hljs-string">'Boston'</span>,
      ],
    }
  },
  <span class="hljs-attr">methods</span>: {
    addBostonToFavCities() {
      <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.favCities.includes(<span class="hljs-string">'Boston'</span>)) <span class="hljs-keyword">return</span>

      <span class="hljs-built_in">this</span>.favCities.push(<span class="hljs-string">'Boston'</span>)
    },
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>Here, we do not want to put the <code>favCitiesInUS</code> function inside our template because it is too much logic. </p>
<p>Think of it like a function where the output will be cached. The function will be re-evaluated only if <code>favCities</code> or <code>usCities</code> (its dependencies) changes. To try that, you can click the button and see how the template changes. Keep in mind that computed functions do not receive any arguments.</p>
<p>We can use the <code>useMemo</code> hook to achieve the same result in React. We wrap the function in the useMemo hook and provide the list of dependencies in the second argument. Whenever one of those dependencies changes, React will run the function again.</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> { React, useMemo, useState } from <span class="hljs-string">'react'</span>

<span class="hljs-function">function <span class="hljs-title">UseMemoTest</span><span class="hljs-params">()</span> </span>{
  <span class="hljs-keyword">const</span> [favCities, setFavCities] = useState([
      <span class="hljs-string">'Istanbul'</span>,
      <span class="hljs-string">'München'</span>,
      <span class="hljs-string">'Los Angeles'</span>,
      <span class="hljs-string">'Rome'</span>,
      <span class="hljs-string">'Florence'</span>,
      <span class="hljs-string">'London'</span>,
      <span class="hljs-string">'San Francisco'</span>,
    ]),
    [usCities, setUsCities] = useState([
      <span class="hljs-string">'New York'</span>,
      <span class="hljs-string">'Los Angeles'</span>,
      <span class="hljs-string">'Chicago'</span>,
      <span class="hljs-string">'Houston'</span>,
      <span class="hljs-string">'Phoenix'</span>,
      <span class="hljs-string">'Arizona'</span>,
      <span class="hljs-string">'San Francisco'</span>,
      <span class="hljs-string">'Boston'</span>,
    ])

  <span class="hljs-keyword">const</span> favCitiesInUs = useMemo(() =&gt; {
    <span class="hljs-keyword">return</span> favCities.filter((city) =&gt; usCities.includes(city))
  }, [favCities, usCities])

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h3&gt;Yigit<span class="hljs-string">'s Favorite Cities are:&lt;/h3&gt;
      {favCities.map((city) =&gt; (
        &lt;p key={city}&gt;{city}&lt;/p&gt;
      ))}
      &lt;h3&gt;Yigit'</span>s Favorite Cities in US are:&lt;/h3&gt;
      {favCitiesInUs.map((town) =&gt; (
        &lt;p key={town}&gt;{town}&lt;/p&gt;
      ))}
      &lt;button onClick={() =&gt; setFavCities([...favCities, <span class="hljs-string">'Boston'</span>])}&gt;
        Click me to add
      &lt;/button&gt;
    &lt;/div&gt;
  )
}

export <span class="hljs-keyword">default</span> UseMemoTest
</code></pre>
<h2 id="14">Vue Slots vs Render Props</h2>

<p>We sometimes want to create generic components that can display other components inside of them, such as a grid component that displays any type of item inside it.</p>
<p>For that purpose, Vue has a mechanism called <a target="_blank" href="https://twitter.com/caglarcilara/status/1448905192045531143?s=20">slots</a>. The logic behind slots is really simple: you open a slot in the component which should receive another component to render (let's call it consumer, because it consumes the elements that are provided). </p>
<p>In the producer, you pass the components that consumer should render inside its tags – you can think of them as filling the slots you opened in the consumer. The first element will be rendered in the first slot, the second in the second slot, and so on. </p>
<p>If there is more than one slot, you have to set the names as well. Let's see an example:</p>
<pre><code class="lang-javascript">&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">h3</span>&gt;</span>Component in slot 1:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">slot</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"slot1"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">slot</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Hello slot1<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">slot</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"slot2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">slot</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Component in slot 3:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">slot</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"slot3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">slot</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><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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>Here is our consumer component. It may be creating a layout or some composition from multiple components. We create the slots and give them distinct names.</p>
<pre><code class="lang-javascript">&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">consumer</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">custom-button</span>
        <span class="hljs-attr">text</span>=<span class="hljs-string">"I am a button in slot 1"</span>
        <span class="hljs-attr">slot</span>=<span class="hljs-string">"slot1"</span>
      &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">custom-button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">"slot2"</span>&gt;</span>I am in slot 2, yayyy<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">custom-button</span> <span class="hljs-attr">text</span>=<span class="hljs-string">"I am in slot 3"</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">"slot3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">custom-button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">consumer</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">import</span> CustomButton <span class="hljs-keyword">from</span> <span class="hljs-string">'./CustomButton.vue'</span>
<span class="hljs-keyword">import</span> Consumer <span class="hljs-keyword">from</span> <span class="hljs-string">'./Consumer.vue'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">components</span>: {
    CustomButton,
    Consumer,
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>And here is the producer passing the components to the slots of consumer by specifying their slot name as an attribute.</p>
<p>And here is the simple <code>CustomButton</code> component if you are interested in that:</p>
<pre><code class="lang-javascript">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>{{ text }}<span class="hljs-tag">&lt;/<span class="hljs-name">button</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-attr">text</span>: {
      <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
      <span class="hljs-attr">default</span>: <span class="hljs-string">'I am a button component'</span>,
    },
  },
}
</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>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>Can you guess the output without running the code? That might be a good exercise to make sure you understand slots.</p>
<p>In React, it is much simpler. I think the slots overcomplicate things a lot. As React uses JSX, we can just get away with passing the component to be rendered as a prop.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> Child <span class="hljs-keyword">from</span> <span class="hljs-string">'./Child'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Parent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> compToBeRendered = (
    <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">h1</span>&gt;</span>Hello<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Im button<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>
  )

  <span class="hljs-keyword">return</span> (
    <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">Child</span> <span class="hljs-attr">compToBeRendered</span>=<span class="hljs-string">{compToBeRendered}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">Child</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Parent
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Child</span>(<span class="hljs-params">{ compToBeRendered }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <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">h1</span>&gt;</span>In child:<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {compToBeRendered}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Child
</code></pre>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>In this last section of the article, I would like to share my two cents on these frameworks. </p>
<p>As we have seen through the article, Vue usually has its own way of doing things and has different constructs for most things. Sometimes this makes it a bit harder to get started with in my opinion. </p>
<p>On the other hand, React is like pure JS, blended with JSX: not much magic and not many special keywords to learn. </p>
<p>Although it may be not be the most beginner-friendly framework, I believe that the abstractions/keywords Vue provides (such as v-for, v-if and the Options API) allow you to write code at a higher level of abstraction (think of adding a simple statement to iterate over components versus a low level, multi-line map function).</p>
<p>These features also make your Vue code more structured and clean because the framework is opinionated. So it has its own ways of doing things, and if you do things that way, you will end up with code that is easy to read and understand.</p>
<p>React, on the other hand, is not very opinionated about things and provides developers with a lot of freedom to decide the structure of their project themselves.</p>
<p>But this freedom comes with a cost: if you are a beginner who is not aware of best practices, it is easy to end up with messy code and a poorly structured project. </p>
<p>Another important difference in my opinion is this: if you are going to build a non-fundamental project with React, you will need to use a lot of external libraries to develop at a normal speed, which means you will need to learn how those things work as well.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Thank you for reading and I hope this comparison was useful. If you would like to connect, ask questions, or discuss further, feel free to send me a message on <a target="_blank" href="https://www.linkedin.com/in/yigit-erinc/">LinkedIn</a>. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Vue 3, a Front-End JavaScript Framework ]]>
                </title>
                <description>
                    <![CDATA[ Vue is one of the more popular front-end JavaScript frameworks. It makes it simpler to create powerful websites. We just released a Vue course on the freeCodeCamp.org YouTube channel that will teach you the latest version of this progressive JavaScri... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/vue-3-full-course/</link>
                <guid isPermaLink="false">66b206fba8b92c93292364ca</guid>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 07 Sep 2021 15:37:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/09/vue.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Vue is one of the more popular front-end JavaScript frameworks. It makes it simpler to create powerful websites.</p>
<p>We just released a Vue course on the freeCodeCamp.org YouTube channel that will teach you the latest version of this progressive JavaScript framework.</p>
<p>Gwendolyn Faraday developed this course. She previously created one of the most popular Vue courses on the entire internet and now she's back with this updated course.</p>
<p>In the course, you will learn the fundamentals of VUE and apply what you learn to build an e-commerce website.</p>
<p>Here are the sections in this course:</p>
<ul>
<li>What is Vue.js?</li>
<li>Vue 3 Setup</li>
<li>Vue JS Directives</li>
<li>Events and Methods</li>
<li>Components</li>
<li>Component Props</li>
<li>Lifecycle Hooks</li>
<li>App Demo</li>
<li>Adding Items to Cart</li>
<li>Reuseable Components </li>
<li>Vue CLI</li>
<li>Vue Folder Structure</li>
<li>Top Nav</li>
<li>Styling with SASS</li>
<li>Sidebar</li>
<li>Adding Items to Cart</li>
</ul>
<p>Watch the full course below or on the freeCodeCamp.org YouTube channel (4-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/FXpIoQ_rT_c" 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>
<h2 id="heading-transcript">Transcript</h2>
<p>(autogenerated)</p>
<p>Gwendolyn Farraday previously created one of the most popular Vue courses on the internet.</p>
<p>Now she's back with an all new full Vue course to teach the latest version to absolute beginners.</p>
<p>Hi, everyone.</p>
<p>My name is Gwendolyn Faraday and I will be your instructor for this course.</p>
<p>I have been a professional software developer for over five years now.</p>
<p>And I've had the opportunity to work in several different languages and frameworks over the years, including Angular react, and Vue js.</p>
<p>I currently work as a software consultant in various technologies, and use Vue js as my preferred front end framework for any type of web or mobile application.</p>
<p>If you would like to reach out to me, you can find me anywhere online at Faraday Academy.</p>
<p>If you have any specific feedback for this course, please email me at gwenf@protonmail.com.</p>
<p>I hope you enjoy this course.</p>
<p>Vue js is a JavaScript framework for building applications and websites.</p>
<p>How does it help you? It provides tools out of the box to help you make your websites and apps faster and more dynamic.</p>
<p>And it also gives you a set of standards for code organization and expectations for individuals and teams that work in the same code base.</p>
<p>If you have heard of the virtual Dom before, Vue js is a virtual Dom framework.</p>
<p>If you don't know what that is, it's okay.</p>
<p>It's not important for understanding this course.</p>
<p>The virtual Dom basically makes JavaScript web applications a little bit faster and more efficient Vue by itself is extremely lightweight, you can get it down to about eight or 10 kilobytes g zipped.</p>
<p>Although in a practical sense, your Vue and bundled JavaScript will probably never be that small in an application anyway.</p>
<p>Although it is good to know that Vue doesn't have a lot of extra code taking up more space in your application.</p>
<p>Why does Vue JS call itself a progressive framework, they use the term progressive to mean that you can use it anywhere from small features on websites where you want to add some interactivity and using it as kind of a drop in replacement for jQuery and legacy applications.</p>
<p>All the way up to using it as a more full featured batteries included framework for large scale applications like Gmail or Twitter or something like that.</p>
<p>You get to decide what features you want to add in from the Vue ecosystem beyond the core library, and it's extremely flexible to allow you to choose the tools and other libraries you want on your own.</p>
<p>Or you can use the ones that Vue provides in its ecosystem by default, many people and companies are using it for its incrementally adoptable nature.</p>
<p>That means that if they have a legacy application, it's quite simple to update their application page by page to turn it into a Vue application into a more modern application, instead of having to rewrite the whole app at once.</p>
<p>That is one very convenient thing about Vue j s.</p>
<p>Let's look at a really quick overVue of the history of Vue.</p>
<p>The Vue project was started in 2013 by its founder, Evan you.</p>
<p>In 2014.</p>
<p>version one launched and started to become popular in China where revenue is from a few years later, Vue two was launched with many new updates and improvements over Vue version one.</p>
<p>And with the release of version two is really where we start to see the massive growth of Vue j s and popularity in the rest of the world.</p>
<p>So many developers had not heard of uJs before 2017.</p>
<p>But from 2017, and especially in 2018 and 2019 Vue really solidified itself as one of the top three JavaScript frameworks.</p>
<p>Many Vue conferences started popping up lots of content creation around the Vue ecosystem started to take place.</p>
<p>And many companies started to use Vue for their applications as well.</p>
<p>In fact, many companies that do you recognize, which are household names in the West, use Vue, j s now.</p>
<p>And now we can see that Vue version three has been released in fall of 2020.</p>
<p>And along the way, over these last six years, we see many different libraries that are also created and maintained by Ave and the core team of Vue.</p>
<p>Like the vcli Vue router in Vue x, also being regularly updated to match with the current version of Vue.</p>
<p>Even now, with Vue three just released, we see that a new version of Vue, router and VX have also been released to be compatible with Vue version three.</p>
<p>In this course, we will be using the Vue j s core library as well as the vcli.</p>
<p>For more information on Vue, x Vue router, Vue test utils and some of the other tools in the Vue ecosystem that I don't cover in depth in this course, I will be making future courses about those on my Faraday Academy YouTube channel.</p>
<p>So let's get started with learning v j, s.</p>
<p>And keep in mind, I'm using v3 here.</p>
<p>So make sure you are at the correct website, which is v3 dot Vue, J s.org.</p>
<p>And then click on getting started here.</p>
<p>This will take you to the documentation.</p>
<p>And by default, the introduction to Vue j s, I'm going to go straight to the installation link on the sidebar here.</p>
<p>And if I scroll down, I can see the place where it says CDN.</p>
<p>And you'll notice here it says Vue add next make sure you are importing the right library from the right URL here at next is necessary, because Vue three is not in the main Vue j s repository yet it's in this other repository that you can reference with that next, which points to Vue three, until the whole ecosystem and everything finishes getting updated.</p>
<p>There is going to be a difference between importing Vue to an importing Vue at next, which points to Vue version three.</p>
<p>And I'm going to go ahead and grab this script tag here.</p>
<p>So I'm in VS code, and I just have a basic HTML file.</p>
<p>And I'll be adding Vue j s into this application to demonstrate the basics of Vue syntax before I get into building a larger application with the Vue COI.</p>
<p>So first of all, I'm going to be using VS code plug in called live server.</p>
<p>And you can see at the bottom here it says go live.</p>
<p>So if you go to plugins, which is this four box icon on the side, you can type in live server and click on this plug in.</p>
<p>And you can install it if you do not already have it installed.</p>
<p>But I already have it installed and enabled.</p>
<p>So I'm going to go back to my code over here.</p>
<p>And at the bottom, I'll just click go live.</p>
<p>And you can see it shows my HTML page, I'll just zoom in a little bit here with the static content.</p>
<p>Now if you don't want to use live server, you can just come here and right click and click on copy path.</p>
<p>And then you can go to your browser and paste that absolute path to the project or to your index dot HTML file.</p>
<p>And it will display the same way in the browser.</p>
<p>live server just makes things a bit easier because it will automatically refresh when you make code changes.</p>
<p>And it also opens up the browser page for you.</p>
<p>But it's up to you if you want to use it or not.</p>
<p>So now I want to add Vue to this application.</p>
<p>So I'm going to go inside of the body tag and just below this div, just paste in the script tag that I just copied.</p>
<p>So now this is all that I have to do to import Vue and start using it in my application.</p>
<p>I don't actually need Babel or anything else to get started.</p>
<p>So to write my own custom code, I'm going to add my own script tag right below that.</p>
<p>So there's basically two things that I need to do here.</p>
<p>And the first is to use this Vue variable that I have access to from importing Vue.</p>
<p>And that script tag and Vue gives me this method called create app.</p>
<p>And that basically creates my Vue application.</p>
<p>And I can pass it an options object, which I'll get to in a second.</p>
<p>Now I need to somehow connect this JavaScript for my Vue application with the HTML that I'm going to be displaying in the browser.</p>
<p>And that is through another method that I can actually chain on to this Vue instance I'm creating.</p>
<p>So I'm actually going to save this as a variable.</p>
<p>I'm going to say let app equals Vue create app.</p>
<p>And then I'm going to use this other method called Mount because I want to tell it to mount my Vue application somewhere in my HTML here.</p>
<p>So I'll do ID equals, I'll just call it app.</p>
<p>And I'm actually going to tell it to mount to my Vue j s application inside of that div.</p>
<p>And that means that the Vue j s instance that I'm creating here will be able to connect and display data and interact with any kind of DOM element inside of this div here.</p>
<p>So that will be more clear in a second.</p>
<p>So now let me change this, let me create a variable on my Vue instance.</p>
<p>And to do this, I need to create a function called data here.</p>
<p>Now this whole object here is called the options object.</p>
<p>So any variables or functions that I'm going to use in my application will live on this object here.</p>
<p>So specifically with data that is a function, and it needs to return an object.</p>
<p>And on this object that is returned by the data function, I can put whatever variables I want.</p>
<p>So I'm going to create a greeting variable.</p>
<p>And I'm basically going to say hello, v3, then exclamation point.</p>
<p>And now I can actually go into my div here, delete that static code there.</p>
<p>And I'm going to use my variable now.</p>
<p>So to use a variable in Vue, you use this double curly brace syntax, it's called double mustache syntax, which is kind of hard to pronounce.</p>
<p>So you can just call it double curly braces.</p>
<p>It's a common syntax in templating languages.</p>
<p>And it basically means that anything found in between these sets of double curly braces will be parsed as JavaScript by Vue.</p>
<p>So Vue is first going to look inside of this data object that we're returning, and see if there is a variable named greeting, and then it is going to display that variable or the value of that variable inside of these curly braces.</p>
<p>And you can see that now it displays the greeting variable from our Vue instance.</p>
<p>Let's talk about Vue j.</p>
<p>s directives.</p>
<p>They are basically a way to connect elements in our HTML or template here with the Vue j.</p>
<p>s JavaScript.</p>
<p>And let's see what that looks like through an example.</p>
<p>I'm going to create an input here.</p>
<p>In the browser, it looks like this.</p>
<p>Now, what if I want to get the value out of this input Vue has a built in way to do that through a directive called v model.</p>
<p>Now, these directives in Vue are used just like an HTML attribute, but they are prepended with v dash to differentiate them from regular HTML attributes.</p>
<p>And Vue when it is parsing this Vue application will see this keyword v model, and will bind it to whatever variable we pass in as an argument to the model here.</p>
<p>So here inside quotes, I need to put a variable name.</p>
<p>And I'm actually going to put the variable greeting here.</p>
<p>And let's see what that does.</p>
<p>So you can see now in my input, it actually starts off with the text Hello Vue.</p>
<p>And as I change it, it also changes the greeting variable that is displayed on the page.</p>
<p>This is called two way data binding and is handled in Vue with that V model directive.</p>
<p>Let's look at another directive.</p>
<p>I'm going to create an HR here.</p>
<p>And I'll make a div with a class of box.</p>
<p>And I'm going to use another directive here called v if, which also takes an argument, which will be another variable.</p>
<p>So I'm going to set an is visible variable which I have to create.</p>
<p>So let me do is visible and set this to true to start, I am going to paste in some styling that I made.</p>
<p>This is just to style the box so you can see it on the page.</p>
<p>Awful that you can see that I do see that box, because this V if directive is basically just like an if statement in JavaScript.</p>
<p>So if this value is truthy, then this element will be displayed on the page.</p>
<p>But if it's false, this div will not be rendered to the DOM at all.</p>
<p>So let me change this variable to false.</p>
<p>And you can see the box disappears.</p>
<p>And if I check, I can inspect element.</p>
<p>And there is no div found in the DOM.</p>
<p>Now v If is very similar to V show, which is another vj s directive, it takes the same kind of argument a Boolean expression.</p>
<p>And let me set this to true again, you can see if it's true, it shows on the page, just like v if.</p>
<p>However, when it's false, you can see there's still a div, render to the DOM.</p>
<p>The only difference is the style is set to display none.</p>
<p>So you won't actually see it, but it is there in the DOM.</p>
<p>So when would you use v show? Well, in most cases, you would just use v if, because you either want something to render or not.</p>
<p>Like if you have a loading spinner, you would use V, if it's loading show the spinner.</p>
<p>And then when the page or whatever has loaded, you would set the variable to false and then v if would remove it from the DOM.</p>
<p>Now v show is useful for specific cases, when you might need to toggle something more frequently.</p>
<p>And it would be more performant than adding and removing it to the DOM constantly.</p>
<p>So it's already there, all you're doing is changing the CSS.</p>
<p>So you're changing it from display none to display block.</p>
<p>So changing this back to Vf.</p>
<p>There are other directives that you can chain on to Vf.</p>
<p>There's v, elsif, and V else.</p>
<p>And you can already guess what these do.</p>
<p>So I'm just going to show you the syntax here.</p>
<p>So v else if and V else is the one that doesn't take any argument.</p>
<p>And I'm just going to demonstrate these really quickly.</p>
<p>I'll add another variable here.</p>
<p>So it's visible is visible to.</p>
<p>So I've added a little bit more CSS here to differentiate between the three boxes that I've created here.</p>
<p>And this works as a regular if else statement.</p>
<p>So if is visible is true, this div will be rendered.</p>
<p>If it's not true, it's going to keep going down the chain.</p>
<p>So it will look at any v else ifs you have here, you can have as many as you want.</p>
<p>So then it will look at is visible to to see if that is true.</p>
<p>If that's not true, then it will automatically display this third box.</p>
<p>Now the third box is blue, the second box is red, and the first box is purple.</p>
<p>So you can see the blue box displayed because the other two values were false.</p>
<p>Likewise, I could change one of these variables to true.</p>
<p>And then that box would be rendered in the DOM here.</p>
<p>Now I want to point something out here, if I refresh the page, you can see for a split second, you actually saw all of the boxes render, as well as the curly braces show up on the screen here before it was parsed as a Vue variable.</p>
<p>I'm going to refresh the page again and slow it down a little bit, just in case you couldn't see that.</p>
<p>So how do I prevent that from happening? Vue has something called v cloak, which is a convenient utility that will hide anything from rendering until the whole Vue application is ready.</p>
<p>So I'm going to add a V cloak here.</p>
<p>And then I basically need to add a style for it.</p>
<p>So you can see, I'm setting v cloak or this V cloak attribute to display none.</p>
<p>This is the recommended pattern in Vue js.</p>
<p>And then I just add a V cloak to my div with my app in it.</p>
<p>Now if I go back here and refresh, you no longer see the curly braces or the other boxes render.</p>
<p>How does that happen? I'm going to go to inspect element.</p>
<p>And you can see on the div with ID app here, there is no v cloak attribute.</p>
<p>But if I refresh the page, you can't really see it because it's too fast.</p>
<p>But basically, that V cloak attribute remains on this div until the app is loaded, and then it's removed.</p>
<p>Once everything is rendered to the DOM.</p>
<p>I don't often run into cases where I have to manually use this, but it is a nice feature to know about if you run into that issue.</p>
<p>These were just a few basic directives.</p>
<p>We will definitely be covering more directives as we go along in this course.</p>
<p>In the next video, we will go over events and methods in Vue js.</p>
<p>Now that you've seen how to use variables and directives in Vue, j s, let's make this code a little bit more interactive with a So you probably already know that there are many events that can be captured in the browser and used in our applications.</p>
<p>For example, when the user clicks on an element on the screen, like a button, or if the user presses a certain key on the keyboard, like Enter to submit a form, let's try out both of these cases in our little mini application here.</p>
<p>First, going to get rid of the two extra boxes.</p>
<p>And I'm going to add a button here.</p>
<p>Which for right now, I will label as showbox.</p>
<p>So right now, this V if is set to false or the variable is visible set to false.</p>
<p>So this div will never be rendered on page unless we somehow update that variable.</p>
<p>Before we were hard coding the variable value here as true or false.</p>
<p>But we can actually use this button to change the variable value as well.</p>
<p>And this is done with another directive called v dash on.</p>
<p>Now, the v dash on directive is specific for events.</p>
<p>You can use it for custom events that you create yourself.</p>
<p>Or you can use it for any of the standard browser events, like, as I mentioned before, when a user clicks or presses a key on their keyboard.</p>
<p>So here's specifically, I'm going to do v on colon, and then the type of event which will be a click event.</p>
<p>So I'm listening for a click event on this button right now.</p>
<p>But now when someone clicks on the button, I have to tell you what to do with that click event.</p>
<p>So I need to pass in an argument of whatever JavaScript I want to run when this button is clicked.</p>
<p>And for right now, I will keep it simple.</p>
<p>And I'm going to set the is visible variable to true when that button is clicked.</p>
<p>Now you can see I have this button show box.</p>
<p>When it's clicked, the box shows what if I want to hide the box.</p>
<p>Right now, this only shows the box.</p>
<p>And the only way to get rid of it is by refreshing.</p>
<p>I can set up a toggle for the box, by simply saying is visible equals the opposite of whatever it currently is.</p>
<p>So is visible equals not as visible.</p>
<p>So if it's true, it will be set to false.</p>
<p>If it's false, it will be set to true.</p>
<p>And this should toggle our box, we label this to toggle box.</p>
<p>And now, if I keep clicking toggles on and off, that is basically how events work.</p>
<p>There's also a shorthand for creating events.</p>
<p>So you don't have to type out the dash on colon, you can just type the app symbol, and then the event name.</p>
<p>And this is exactly the same thing as it was when I typed v dash on colon.</p>
<p>the at symbol just replaces all of that.</p>
<p>So what if you wanted to do something more complex in here not just setting a variable to True or false? Well, you can actually use this to pass in any kind of method on your VJs object.</p>
<p>So I'm going to get rid of is visible here.</p>
<p>And I'm going to create a method called toggle box.</p>
<p>And now I have to create this toggle box method.</p>
<p>You can see I already have data on my vj s object, this data function.</p>
<p>But now I need to make another key, which is called methods and methods is an object of functions.</p>
<p>I can put as many functions as I want on this methods object to be able to use these in my Vue, j s application.</p>
<p>So let me create that toggle box function.</p>
<p>I could do the same thing here as I did above, but I'm just going to use the function shorthand and I want the same logic again but inside this function, so in order to refer to this is visible variable here, I have to get it off of the this context.</p>
<p>And Vue j s handles putting all of my methods and variables on the this context so that they're available to me anywhere in my Vue application.</p>
<p>So I can do this.is visible and then set it equal to not this.is visible This is not function there.</p>
<p>And this should work the same way as it did before.</p>
<p>So I can test it out and toggle the box once again.</p>
<p>So that is the basics of how methods work.</p>
<p>And you can see because I have called my method toggle box That it is also available to me anywhere inside my Vue JS template here.</p>
<p>So let's look at one more type of event.</p>
<p>And that will be an event listening for keyboard input.</p>
<p>So here I want to listen for key presses.</p>
<p>This is also an event.</p>
<p>So I'm going to start with the Add symbol.</p>
<p>And listen for a key up event.</p>
<p>I could also use key down if I wanted to.</p>
<p>So for keyboard events, I need to add a modifier to say which keyboard input I am listening for.</p>
<p>So for input here, I want to run a function or some JavaScript, whenever I press the enter key.</p>
<p>So for enter, I actually have a shorthand because this is a common keyboard input.</p>
<p>So I can say, Listen for the key up event specifically with the enter key.</p>
<p>Or I can always use the key code associated with any key on the keyboard.</p>
<p>So for enter, that would be 13.</p>
<p>It doesn't matter which one I use, I'm just going to go ahead and use key up dot enter, because it's a bit more obvious what it is.</p>
<p>And then it's the same syntax here.</p>
<p>And I'm going to create a greet method for this key up event.</p>
<p>So let me go down to my methods, create a method called greet.</p>
<p>Use the method shorthand.</p>
<p>And I'm actually just going to console dot log, this dot greeting.</p>
<p>And let's see how that works.</p>
<p>So I can just focus this input anywhere and just hit enter, it doesn't matter what's already in the input.</p>
<p>And you can see it logs out the greeting.</p>
<p>If I change the input, it logs out whatever the greeting variable is currently set to.</p>
<p>Now what if I want to pass something into a function as I'm calling it into one of these methods, then I could do that, just by adding the parentheses to call the function.</p>
<p>So for example, greet here, I can just pass something in.</p>
<p>So just for demonstration purposes, I'm going to pass in the greeting through the template here.</p>
<p>I'm going to accept that here.</p>
<p>And I'll still call it greeting.</p>
<p>And then get rid of this because I'm no longer looking for the greeting variable.</p>
<p>On the vj s instance here, I am actually just going to be using the greeting variable that I am passing in here.</p>
<p>And just to show you that it's different, I can use the greeting variable and then pass it in with some exclamation points appended to it.</p>
<p>And now when I go here, and I click Enter again, you can see that it is the greeting variable that I passed in through the template.</p>
<p>If I erase a few characters here, hit ENTER again, you can see it's still the same variable set to the new value.</p>
<p>Those are the basics of how to use events and methods in Vue js.</p>
<p>I do want to point out here, you see this dot enter, that is an event modifier in Vue js.</p>
<p>So you're not only listening to the key up event you're listening to specifically the enter key.</p>
<p>Now there are many modifiers that you can use.</p>
<p>For example, at this click event here, for example, I get I have a modifier here that says I'm only listening for right clicks.</p>
<p>So a normal left click on a mouse will not trigger this toggle box.</p>
<p>But only if you make a right click, I can also use some handy modifiers like prevent.</p>
<p>So if I don't want a form to submit instead of using the regular event dot prevent default in my method, I can just add this modifier here dot prevent.</p>
<p>And I can do that for stop propagation as well.</p>
<p>So I could add that stop.</p>
<p>You can chain as many of these modifiers as you want in Vue j s, there are definitely a handy thing to know about when you're building Vue applications.</p>
<p>That's all for this video, we will be diving deeper into events and methods later on in this course and in future courses.</p>
<p>In the next video, we're going to talk about custom components in Vue js.</p>
<p>Let's talk about Vue components.</p>
<p>Now when we created our Vue application here, we are basically just using one standard component, you could call it just a default options object for use in our template.</p>
<p>So now we're going to work on breaking up parts of our application into separate components in order to prepare for learning how to build larger applications and work on applications with the Vue COI outside of a single HTML file.</p>
<p>Let's take a break from the code for a second and take a look At what we are going to be building with Vue components, we're going to use a simple example of a form to work on breaking up an application into separate components.</p>
<p>Now, where you see the red outline, those are each going to be a separate component.</p>
<p>So the outer red outline around the whole login form will be its own login form component.</p>
<p>And then each input with its label will be a custom input component that we are going to create and be able to reuse for as many inputs as we have.</p>
<p>So we're going to start off with this outer component, and then break out the inner components into their own components after that.</p>
<p>And then we are going to look at how you can pass data around between components in your application.</p>
<p>So what would a Vue component look like? Let's say we wanted to have a form in here.</p>
<p>And I'm gonna get rid of this greeting really quick.</p>
<p>And put a form here.</p>
<p>So I could do this directly in the HTML and create a form tag.</p>
<p>Or I can create a custom tag as a Vue component called custom form.</p>
<p>Now, this is the same syntax as if it were an HTML tag.</p>
<p>Except, of course, it is not a standard HTML tag.</p>
<p>So I have to define it as a Vue component down here.</p>
<p>And I need to define it after I define my app variable, which is my Vue instance.</p>
<p>And before I actually mount it to the DOM, so I can chain this here as app dot component.</p>
<p>This is a function and it takes two arguments here that I'm going to pass in.</p>
<p>So the first one is the name of the component that I'm going to use.</p>
<p>And that is the name that I'm going to be using in my HTML up there.</p>
<p>So I'll give it the same name custom form.</p>
<p>And the second is an options object.</p>
<p>And since this is his own self contained component, I can actually use any of the same options that I've been using here, such as data and methods, etc.</p>
<p>The only extra thing that I need right now is I have to define a template for this component.</p>
<p>And the easiest way to define a template is by using graves.</p>
<p>So I can make this multi line and pass in the HTML here.</p>
<p>So real quick, I'm going to create a div.</p>
<p>And I'm just going to put, let's say, two inputs in here for right now, but a type of email, and then an input type of password.</p>
<p>And let's call this a login form.</p>
<p>Since we're doing email and password, I'll change that up here to login form.</p>
<p>And since template is the only required option that I need to pass in on this object, it should run like it is right now.</p>
<p>So let me see if this works.</p>
<p>I'm gonna go to go live.</p>
<p>And you can see these two form inputs up at the top here, completely unstyled, just basic browser inputs.</p>
<p>So I'm going to style these inputs really quickly, so they're easier to see.</p>
<p>After all of these boxes, I'm going to add a reference to input here.</p>
<p>I'm going to say margin of 10 pixels just on all sides, and display of block so they don't go in line.</p>
<p>And now they are a bit easier to see here.</p>
<p>Alright, let me code for the styles again.</p>
<p>And now let me add a data method to this component.</p>
<p>So you can see what that looks like.</p>
<p>So after this template key I have here, I'm going to do the same thing I did above.</p>
<p>With data, I'll just use the function shorthand here, return an object.</p>
<p>And here I'm going to give it a title.</p>
<p>And the title will be login form.</p>
<p>And now I need to do something with this title.</p>
<p>So up here when I defined variables, I use them inside of my app template here.</p>
<p>But since my login form is a self contained component, any variables I define on data here, I am going to have to use them inside its own template.</p>
<p>So I'll just add another line here and give it an h1 and by the way, This doesn't have syntax highlighting, and isn't kind of a weird template form.</p>
<p>Because I'm just doing this all in one HTML file.</p>
<p>This is just a stepping stone to get to more standard ways of creating Vue components where you will have syntax highlighting, and auto completion and all of those other great features.</p>
<p>So here, I need to use that variable title.</p>
<p>So I'll use that the same way I did before by referencing it.</p>
<p>And now I should see the title on top of those two input boxes.</p>
<p>And indeed, I do here I am, zoomed in quite a bit.</p>
<p>So that is a basics of how you can create a component here, I'm going to go ahead and keep building out this form, and then also show you how to compose components now.</p>
<p>So I'm just going to change this really quickly to form.</p>
<p>And then I'm going to add some submit functionality here.</p>
<p>So I'm going to add an event for submit, submit, and then pass in an argument with the method I want to run or the function I want to run when I submit a form.</p>
<p>So I'm just going to call my function, I suppose handle Submit.</p>
<p>And then I need to make a methods object down here with that function.</p>
<p>I'll call it a handle, submit.</p>
<p>And I will just console dot log submitted.</p>
<p>So now when the form submits, it will run this function, there's a few more things that I need to do, I need to add a button here, that will actually submit the form.</p>
<p>So by default buttons are type submit, so I don't need to add that here.</p>
<p>But I am going to add some text to the button.</p>
<p>Now when the form submits it refreshes the whole page.</p>
<p>Of course, this is the default behavior in browsers.</p>
<p>So you can just automatically click and send data from the form to your back end.</p>
<p>But since we are going to be handling the form submission from our handle submit function, we don't want this default behavior with the page refresh.</p>
<p>So like we saw earlier, we have event modifiers.</p>
<p>So we can do prevent, to prevent default, this would be the same thing as passing in an event object to our handle submit function, and then doing e dot prevent default.</p>
<p>Again, this is just a shorthand.</p>
<p>So now if we look at our console, here, we see that it logs submitted when we submit the form.</p>
<p>So now, we probably want to be capturing these inputs.</p>
<p>So we can do that.</p>
<p>Again, by using the directive v model to bind to the value of the form input to a variable, we'll call this one email.</p>
<p>And we'll v model this one as password.</p>
<p>And then add these into data.</p>
<p>And now let's log those out.</p>
<p>So let's log out email.</p>
<p>And password.</p>
<p>Of course, if you remember, I have to get it off of the this context, since I'm referencing it inside of JavaScript here.</p>
<p>And now I should be able to type in something here, this has to be an email.</p>
<p>So I'll say gwen@example.com.</p>
<p>Just any password, and I'll click Login.</p>
<p>And you can see it did log out my credentials here.</p>
<p>Okay, so that's one component.</p>
<p>In the next video, let's look at how to break up this component and take out the inputs to put them in separate components, as you saw in the markups earlier in this video.</p>
<p>And we'll also look at how to pass data between components.</p>
<p>So from a parent component to a child, and then also from a child backup to the parent.</p>
<p>So what if we want to compose multiple components together? Let's demonstrate this by removing the inputs and creating a custom component just for our form inputs.</p>
<p>Let's say we want some logic just contained within a special input component.</p>
<p>So let me fold this real quick.</p>
<p>And I'm going to create another component here.</p>
<p>I'll do app dot component again.</p>
<p>And I'm going to call this custom input passing in options.</p>
<p>object.</p>
<p>Again, I need to have a template here.</p>
<p>And in this one, I'm just going to have Label Label when a display a label variable here, and then I'll have that wrap around the input.</p>
<p>And I'll use a type, just the default text for right now we'll change that in a second.</p>
<p>And that is a default input.</p>
<p>So now where am I going to use this component, so I'm actually going to replace my input fields in this component with this new one that I created.</p>
<p>So what I can do here is Call this Custom input, and custom input.</p>
<p>And I can use my components inside of this other component.</p>
<p>Now there's one more step that I have to take here.</p>
<p>And that is registering the component.</p>
<p>So I have to let my login form component know about the other custom component.</p>
<p>And I can do that here by creating components array, and then just give it the string of the component that I want to be using, which is custom input.</p>
<p>Now let's see how this works.</p>
<p>Okay, so I have these two inputs.</p>
<p>Now it is giving me this warning, that property label was accessed during render, but it's not defined on the instance.</p>
<p>This is happening, because here, I'm referencing this variable label, but it is not defined anywhere.</p>
<p>So it's giving me that warning.</p>
<p>Now I could define data function here and create the variable on this component.</p>
<p>But I want to demonstrate passing data from one component to another.</p>
<p>So instead of defining it on this component, I'm actually going to define label on the parent component and pass it to the custom input component.</p>
<p>To do that, I'm going to come here and add just a label, let me add in, we call it email label for right now.</p>
<p>And I'm going to call it email.</p>
<p>And I'll also have a password, label and call this password.</p>
<p>Now I have to get these two variables passed into these custom components here.</p>
<p>And so what I'm going to do here, I can go ahead and get rid of the V model for just a second.</p>
<p>And I'm going to add a label here that I'm going to pass in.</p>
<p>And I'm going to pass in the email label.</p>
<p>Now this looks just like an HTML attribute.</p>
<p>But I'm actually going to add a modifier on here.</p>
<p>That is a Vue directive called v bind.</p>
<p>What v bind does is basically turn this regular HTML attribute into something that can be parsed as JavaScript so that I can pass down a variable to the child component.</p>
<p>So I'm v binding this label, which is email label, which refers to this string here, which is email, this will get passed down as a property to the child component called label.</p>
<p>And now in this custom input child component, I need to receive that property to accept it here with a props object.</p>
<p>And the simplest way to write props is to make an array of strings, just like I did for custom components.</p>
<p>And these props are basically just a list of all of the names of the information that I'm passing down from the parent to this child.</p>
<p>So now, because I'm defining label in props, I will have access to use the label variable here inside my template.</p>
<p>Now if you look at the login form, you can see that the email field, it has a label here, and you can tell it to label because when I click on the word email, it focuses on the field it's related to.</p>
<p>So let me give a label the password now to I'm going to pass in password here.</p>
<p>By the way v bind, there is also a shortcut for V bind.</p>
<p>This is one of the most common directives in all Vue applications.</p>
<p>So the shortcut is instead of using v bind colon, you just use colon and then label.</p>
<p>So let me pass a label in here as well.</p>
<p>So I'll pass a label in As password label, since we're using this reusable component, the label will always display as the label that we pass in.</p>
<p>And now you can see that both form fields are properly labeled here.</p>
<p>Now I want to point one thing out really quickly.</p>
<p>And that is for email and these password labels, you could not make variables for these and just pass them in as strings here.</p>
<p>So for example, if I get rid of the bind of the colon, shortcut there, then I could just pass in, let's say, password.</p>
<p>And let me put enter email here.</p>
<p>So it's different.</p>
<p>And now I can just pass in this text as a string.</p>
<p>Because there's no more v bind here, Vue is no longer looking for a variable.</p>
<p>So now in the application, you can see that it's just passing the string down as a label to the child component and displaying that string, I'm going to do those changes.</p>
<p>When you're working in actual Vue applications, you will see that 95% of the time, you want to pass a variable in when you're passing a prop down to a child component, either a data variable or some kind of a function.</p>
<p>So you'll almost always be using this V bind syntax here.</p>
<p>Now there's one issue because in the child component, we have the input down here, we're not actually listening for changes to the text in the input, we're not v modeling that to any variable, so we don't have access to whatever is inside the input.</p>
<p>So we actually need to create a V model here in the child, I'm going to save the model.</p>
<p>And just temporarily here, I want to map this to a variable in the child.</p>
<p>And I'm going to could just call this input value.</p>
<p>And I need to create data function here, return an object with input value as an empty string.</p>
<p>So now in this case, you're already familiar with the model.</p>
<p>And you know that anytime we type a character into this input, it's going to update this variable and this variable, and the input will stay in sync.</p>
<p>But now how can I get the value of this variable up to the parent component here, because I actually want it to stay in sync with these two variables on the parent component.</p>
<p>So that way, when I submit my form, I can have access to it in this handle submit function.</p>
<p>So there are actually a couple different ways of doing this.</p>
<p>I'm going to show you the most straightforward approach for getting started with this.</p>
<p>And then in future courses, I'm going to explain a little bit more in depth about how you can use custom events and other methods of capturing the value of a variable from the child to the parent.</p>
<p>So to get started, here, I'm going to use my same input variable.</p>
<p>But I'm going to use a new object here.</p>
<p>And this object is called computed.</p>
<p>I'm going to comment out data for a second.</p>
<p>So computed is an object where you can put variable names in here as keys.</p>
<p>So for example, this input value variable that I want to create, I can put it in here as a key.</p>
<p>And whenever this value changes, I can actually get it to run getter and setter functions.</p>
<p>So I can create a getter function, and then a setter.</p>
<p>So when I get the variable value here, it will run this function.</p>
<p>And then when I go to set the variable value, it will run the set function.</p>
<p>So now what value do I want to put in my getter here, I want to get that value from the parent component.</p>
<p>So I'm actually going to use these two variables that I already have here.</p>
<p>And I'm just going to get rid of these types.</p>
<p>I'm not using them yet.</p>
<p>So get rid of those.</p>
<p>And I'm actually going to do something different.</p>
<p>I'm going to create v model directly on my custom component here.</p>
<p>And I'll show you why in a second.</p>
<p>And I want to model this to the variable that I'm going to be using.</p>
<p>So for this one, that is the password variable.</p>
<p>And for this one, that's email And these got out of order.</p>
<p>So I'll switch them around.</p>
<p>Okay, so now I'm be modeling the email and password.</p>
<p>And now I want to get these variables in my child component here.</p>
<p>Now, how do I do that.</p>
<p>So in props, I can actually accept a prop called model value.</p>
<p>And this comes from the parent.</p>
<p>Now it doesn't really look like we are passing in another Prop, because we're not v binding any variable and passing it to the child.</p>
<p>But actually, what v modeling does on a child component is actually under the hood, it's giving us another prop called model value, which is mapped to email.</p>
<p>So v model does a few steps all at once, it's kind of a shorthand here.</p>
<p>So I have access to this model value prop because I'm using the model.</p>
<p>So I can accept that prop in the child here v model.</p>
<p>And then in my getter function, I can do this dot model value.</p>
<p>And I can return that.</p>
<p>So now whenever I get the value for this input, it should be the same as the value in the parent component.</p>
<p>And I can check that by just typing in some values here.</p>
<p>And you can see that the inputs are pre populated with the value from the parent component.</p>
<p>Because I am v modeling this input to a getter function that I'm setting here and saying that the value will be this dot model value, which comes from the V model variable in the parent component, which are these variables.</p>
<p>So now, how do we handle setting the value if we type text into this input here, so we need to capture the value first and Vue passes this in via a parameter.</p>
<p>So we can give this parameter any name that we want, I'm just going to call it value.</p>
<p>And I'm just going to first log out this value.</p>
<p>And so here, I can try typing in.</p>
<p>And you can see it's logging out the value of the input from that log in the setter function.</p>
<p>But now it's not setting a variable anywhere.</p>
<p>So let me go ahead and set the variable.</p>
<p>Now to do that, I'm going to use a new method that you haven't seen yet.</p>
<p>And that is this dot dollar sign emit.</p>
<p>What emit does is allow me to emit events that other components can listen to.</p>
<p>And I can pass data around by Vue application like that.</p>
<p>I can emit events that are built in like I could emit some kind of on click event or something like that.</p>
<p>Or I can emit a custom event that I create.</p>
<p>For right now I'm going to use an event that Vue gives me and this is called an update event.</p>
<p>This syntax is actually new, slightly updated in Vue three.</p>
<p>So if you see older tutorials, and might not be using this exact same syntax, it will probably be using an input event here instead.</p>
<p>But I'm going to pass in a value here.</p>
<p>Oops, I need a comma.</p>
<p>So this first argument is the type of event that I'm emitting.</p>
<p>And the second argument is the value that I'm passing through that event, which is this value that I'm getting from the input via the set function.</p>
<p>Now, how can I listen for an event in another component? I could set this manually.</p>
<p>But like I said before, V model is a shorthand.</p>
<p>So v model is actually listening for this update event from my child.</p>
<p>And whenever this update event emits, this V model from the parent component is updating the value of the variable for us.</p>
<p>Let's test this out.</p>
<p>I'm going to start typing here, typing here.</p>
<p>And I'm going to press login.</p>
<p>And you can see that it logs out the values of the email and password.</p>
<p>So this isn't that clear.</p>
<p>So let me put a real email here, or real fake email anyway.</p>
<p>And you can see there's the email and there's a password, which are coming from this log statement in handle Submit.</p>
<p>Now, you might be wondering, why do we have to go through all that trouble to model a variable from a child to a parent.</p>
<p>And the reason why is because the props that we pass to children, they are immutable.</p>
<p>We cannot them in the child, these variables on data here can only be changed in the same component.</p>
<p>So my custom input can't change anything we pass in via props here.</p>
<p>So for example, if I tried to model this to label here, getting all of these warnings attempting to mutate prop label, props are read only.</p>
<p>So I'm gonna undo that.</p>
<p>So that's why I had to create this extra variable in the child and create a getter.</p>
<p>So I'm getting this read only model value prop from the parent.</p>
<p>And then what I'm doing to update the value of that prop is I made it emitting an event to the parent, this update model value event.</p>
<p>So the parent, because I have this V model shorthand is listening for that event.</p>
<p>And this component, this login form component is actually updating these variables itself.</p>
<p>So I'm not actually mutating props from the child.</p>
<p>Now, there are definitely other ways of handling changing props in the child component, I could listen for changes on this input.</p>
<p>And I could call a method on a methods object, which could do the same thing either amid an event, I could also pass a function from the parent to the child, and the child can call functions in the parent.</p>
<p>And then I could update variables in that way too.</p>
<p>There are also other state management solutions.</p>
<p>And we will explore all of these different options later, I just wanted to give you an initial taste of how this can be done in Vue js, and specifically in Vue version three, now that the syntax has changed a little bit.</p>
<p>So in this video, we've gone over custom components, composing components together, importing them into each other, like we are with this custom input into the login form component.</p>
<p>We also talked about using props, passing data from the parent to the child, and then being able to set data by emitting an event that the parent can listen to and passing it a value.</p>
<p>In the next video, we are going to talk about loops in Vue to simplify our syntax here with having multiple of the same component.</p>
<p>Now let's talk about loops.</p>
<p>Here, we have two of the same component, these custom input components.</p>
<p>And I would like to just be able to loop through as many of these components as I want.</p>
<p>To do this, I need to add an array and data here.</p>
<p>And this array will have all of the information for each input here, including the variable that I want to model to the label name.</p>
<p>And I'm also going to add a type.</p>
<p>So I'm going to create an array here called inputs.</p>
<p>And just to demonstrate really quickly, I'm going to add just some strings here, like email, password.</p>
<p>And let's say name.</p>
<p>So what if I wanted to display all three of these strings inside the template here, I'm going to come back to looping over the form in a second.</p>
<p>But for right now, I'm just going to create a p tag here.</p>
<p>And I want to show each one of these strings inside its own paragraph tag.</p>
<p>So I'm going to create a loop for these, I'm going to say V four equals, and then I need to pass in the array here, which is called inputs.</p>
<p>And this will loop over the inputs array.</p>
<p>Now this is a four in loop.</p>
<p>So I'm going to have to create a variable that I can use in the iterations.</p>
<p>So I'm going to say for str, short for string in inputs, and now I have access to this string variable each time through the loop.</p>
<p>And I can basically just display it in a variable now.</p>
<p>Right, so it is complaining that I made a mistake in my syntax.</p>
<p>And of course that is because I didn't put a comma after my array.</p>
<p>And now you can see that these top three here are strings that are displayed in a paragraph tag.</p>
<p>Of course, they are so big because I am zoomed in so far, but they are displaying properly.</p>
<p>And that is basically how you use a loop in Vue js.</p>
<p>I am missing a prop here that I need to add.</p>
<p>Whenever you do a loop you have to add a key prop here and this key has to be unique on E iteration of the loop.</p>
<p>Now the reasons for using this key prop are a little bit more advanced.</p>
<p>So I'm not going to go in depth on it in this video.</p>
<p>But I just want you to understand that it is good practice for you to use a key that will uniquely identify any elements that you loop through in your Vue JS templates.</p>
<p>This can help with performance and preventing bugs in your applications.</p>
<p>And when you move into programming a more structured Vue application with Vue components in their own files, you will see that your linter and code editor will pick up on it if you don't have a key value here.</p>
<p>And it will give you a warning and ask you to add one.</p>
<p>So we have to have a key to give a unique reference to each one of these paragraph tags, we're adding into the template.</p>
<p>Now what I can do since the names are unique here, each string is different.</p>
<p>So I can v bind to key, the string variable str.</p>
<p>This is a really simple Vue application.</p>
<p>So you basically don't notice a difference in the browser.</p>
<p>But you can see that there are keys attached to these elements.</p>
<p>Now, I want to point out though, that one more way that you can create this unique key every time through the loop is you can actually get an index through each iteration of the loop.</p>
<p>You can get it here and then use it as your key.</p>
<p>And if I print out I, you can see that I is the index of each iteration in the loop, put that back a string.</p>
<p>So this was just a demonstration, of course.</p>
<p>So I'm actually going to get rid of this whole p tag here.</p>
<p>And what I really want to be putting in inputs here are objects for the information that has to do with each input that I want.</p>
<p>So the first one, let me put a label here.</p>
<p>And I'm going to say the label is email, I'm going to create a value here.</p>
<p>And this was what I'm going to V model to.</p>
<p>And then I'll go ahead and add a type.</p>
<p>So let's say type is email.</p>
<p>And I'll do the same thing for password.</p>
<p>I can get rid of those now.</p>
<p>Alright, so now my application is broken, because I got rid of all the data that I had been passing into these custom inputs.</p>
<p>And actually, I'm going to get rid of one of these custom inputs, because now I'm going to be looping over just one, and it will create one for each iteration of the loop.</p>
<p>Let me clean this up a little bit.</p>
<p>But these on separate lines.</p>
<p>And so the first thing I want to do is create a V four here.</p>
<p>And this V four will look through inputs, just as I did before, I'm going to say four inputs in inputs.</p>
<p>And I'm actually going to get the index here really quick as well.</p>
<p>And then use a key of V bind the index.</p>
<p>So now I can't v model email, I need to V model based off of this input object, which is each object in this inputs array.</p>
<p>So I'm going to have to V model input dot value here to model it to the value.</p>
<p>So I'll do input that value, the label, also, I'm gonna have to do input dot label.</p>
<p>And now I do have a type.</p>
<p>So let me rebind a type as well.</p>
<p>And I'm going to do input dot type.</p>
<p>So that's one thing that I need to update in this child component.</p>
<p>Now, I'm still accepting that model value prop and the label prop.</p>
<p>But I also want to accept a type prop now.</p>
<p>And instead of doing type is text, now I have a prop from the parent based off of which component it is in the loop.</p>
<p>So now I'm going to V bind this so it can take a variable, and I'm going to say type, which will refer to whatever prop I've passed in.</p>
<p>So I'm going to come to my form here.</p>
<p>And I'm going to type in and I actually forgot to change the logging here for handle Submit.</p>
<p>So I don't want to overcomplicate things for this example.</p>
<p>So what I'm going to do is just delete this and log out this dot inputs of zero and that value and then this dot inputs, have one and then that value.</p>
<p>And this should fix my problem here.</p>
<p>Let me just type something in.</p>
<p>And it's complaining that I don't have an email address, I'm just going to type in a fake email, login.</p>
<p>And you can see that it has my correct login information.</p>
<p>So this is the basics of how to handle loops in Vue j s, is you can use V for either on regular HTML elements like an h1 or any custom components that you make as well.</p>
<p>This is very commonly done with card components.</p>
<p>If you see a website like Pinterest, how it shows all those different little boxes with pretty photos in them.</p>
<p>If that was both in Vue js, it would be doing this V for loop over all of those data objects that make up all of those Pinterest cards on your Pinterest wall.</p>
<p>The last thing we need to look at before we get into the demo application is lifecycle hooks.</p>
<p>So we will cover those in the next video.</p>
<p>Another important concept in Vue j.</p>
<p>s is lifecycle hooks, also called component lifecycle hooks.</p>
<p>So what is the hook and what are component life cycles.</p>
<p>To understand this, I made a quick demo.</p>
<p>Similar to the demo that we started off with in this course, I can click the toggle box button and a box appears.</p>
<p>Now I'm using a V if to take this box, add it you can see it was added to the DOM.</p>
<p>Now if I click again, it was completely removed from the DOM here, that whole process of coming into the DOM.</p>
<p>And then finally leaving the DOM.</p>
<p>That is the life cycle of this box component that I have.</p>
<p>Now, sometimes things might leave the DOM because you navigate to another page, or because something is coming into Vue via scrolling, or because you're hiding and showing something like this example.</p>
<p>In any case, you can use something called lifecycle hooks.</p>
<p>A hook is just a function that will be triggered to run at a specific point in the lifecycle of a component.</p>
<p>For example, it's a function that will be called right when this purple box appears on the screen, or right before it leaves the screen.</p>
<p>If you look at the Vue, j s documentation.</p>
<p>Now this is the version two documentation here, because they don't have what I'm going to show you yet in the version three docks.</p>
<p>But it is the same thing.</p>
<p>So I'm under learn guide.</p>
<p>And then if I scroll down on the sidebar, I'm at the Vue instance and creating a Vue instance.</p>
<p>And I can actually click on the lifecycle diagram here.</p>
<p>So this is a diagram like it says of the instance lifecycle of your Vue instance.</p>
<p>And like it says, You don't need to fully understand everything that goes on right now.</p>
<p>But it is a useful reference.</p>
<p>And this chart isn't just useful for your Vue instance.</p>
<p>But every single Vue component will have access to these lifecycle hooks.</p>
<p>So you can see these two up top in the red.</p>
<p>All of the boxes in the red are the lifecycle hooks, you can see before create and created, these hooks will be run right before and right after Vue.</p>
<p>js has initialized your component.</p>
<p>Now the next two before mount and mounted, the format is run right before your component is mounted to the DOM.</p>
<p>And mounted is run as soon as your component is mounted to the DOM.</p>
<p>components can also go through updates.</p>
<p>So before update and updated, like it says here, this will happen.</p>
<p>Or these updates will be triggered when data changes on your component.</p>
<p>So any of those data variables that you create, if you're incrementing a number or changing some kind of value, then updated and before update will run.</p>
<p>And then when your component is going to leave the DOM.</p>
<p>Now here it says before destroy and destroyed.</p>
<p>Now this terminology has been updated for Vue three for these two lifecycle hooks.</p>
<p>So if we go to the Vue three documentation now and we're on lifecycle hooks here.</p>
<p>I'm going to scroll down so you can see before create created before mount mounted before update and updated.</p>
<p>I'm going to skip over some of these and Now you can see it's before unmount and unmounted, which is in place of before destroy and destroyed.</p>
<p>The lifecycle hooks function exactly the same way, they've just been renamed.</p>
<p>I hope this will become a little bit more clear as we look at a demo.</p>
<p>So in the code, you can see I have the same box that we used before appear.</p>
<p>And here is the toggle box button inside of my Vue template.</p>
<p>But this time, I do have a special test box custom component that I made, which is toggled based off of a V, if so this is my main application.</p>
<p>And the options object with my is visible variable for whether or not the box is visible.</p>
<p>And then I just have a toggle box method, which I call when I click this button.</p>
<p>So again, this is pretty much the same thing that we did before.</p>
<p>Except for this new component here.</p>
<p>I put the box in its own component.</p>
<p>Now Now that we've learned about composing components, and I'm just going to add some lifecycle hooks here really quickly to illustrate when these are called on the component lifecycle.</p>
<p>So I'm just going to add a couple of them here.</p>
<p>We're gonna add created, and then mounted, and then unmounted.</p>
<p>And in each of these, I'll put a console dot log.</p>
<p>And let's see when these console dot logs print out.</p>
<p>Back in my browser, I'm going to hit toggle box here.</p>
<p>And you can see in the terminal at the bottom, created, printed and then mounted printed in the same order that we saw in the VJs documentation.</p>
<p>So this one happened before.</p>
<p>And then this one happened after it was mounted to the screen to the DOM here.</p>
<p>Now if I hit toggle box, again, we can see unmounted prints because that is run after the box leaves the DOM.</p>
<p>Now let's look at another one.</p>
<p>After methods here, I'm going to put lifecycle hook on this component, or on the main Vue instance that we have here.</p>
<p>And I'm going to try updated.</p>
<p>And I'll hit toggle box.</p>
<p>And you can see that we have created and mounted those both print from the box component itself, but from the main instance also updated prints.</p>
<p>And that is because we are updating this data variable from is visible false to is visible true.</p>
<p>And so the update function is triggered on this component because our data updated for that component.</p>
<p>And if we toggle it again, we can see updated is run again, because that variable was changed to false again.</p>
<p>So updated will run every single time the data changes.</p>
<p>Now, why might you want to use a lifecycle hook, some of the most common use cases are checking whether someone is authorized to Vue a certain page or component.</p>
<p>A lot of people use the created and mounted hooks as well to pull data into their application from a back end or from in browser storage.</p>
<p>Sometimes they are also used to initialize events.</p>
<p>And then when the component is about to unmount, you can clean up that event.</p>
<p>Or you can save some data or run some kind of check on before unmount or in the unmounted function.</p>
<p>So those are the basics of lifecycle hooks, I encourage you to test out lifecycle hooks on your different components and see what happens when you use different lifecycle hooks.</p>
<p>In a future course we can get into some more advanced examples and a few of the more advanced lifecycle hooks as well that you won't see as often.</p>
<p>So those are the basics of Vue js.</p>
<p>In the next video, we are going to build a Vue three application from scratch, starting with the Vue COI this time.</p>
<p>This is a demo of the application that we will be building.</p>
<p>It's a simple shop application with a few items.</p>
<p>Now it looks like the web page is already done.</p>
<p>But actually it's just static HTML and CSS so far.</p>
<p>As you can see, if I click the Add to Cart button, nothing happens.</p>
<p>And if I scroll up, the only things that are actually functional on this site right now are these top nav links.</p>
<p>Which are just regular browser anchor tag links to bring you to another page.</p>
<p>So this one goes to the Products page.</p>
<p>And you can see I have this cart, which is not functional.</p>
<p>So if I click the X, nothing happens, it's just fully slid out here to demo how it will look.</p>
<p>And if I click the X, nothing happens, it doesn't delete the item, I can't add items to the cart.</p>
<p>And on this page, I have a past Orders table, which is also just static content right now.</p>
<p>This project is going to be a little bit different than tutorials that you are used to, we are not going to be starting from scratch with some mock ups here.</p>
<p>Instead, we will be starting with a static application with HTML and CSS already coded, then we will figure out step by step how to add Vue JS into the application.</p>
<p>This will help to give you a deeper understanding of how Vue works and how to build real world Vue applications.</p>
<p>First, I will give you an overVue of the code base.</p>
<p>And then we're going to see how it looks in the browser.</p>
<p>And then finally, we will start with the Vue JS portion and implementing our own Vue code into each feature one at a time, the goal is to eventually reach a point where it gets to be difficult to continue to code inside of HTML.</p>
<p>And then we are going to move the project over to a Vue COI setup project where we will have Webpack and the full ecosystem of Vue j s tooling and libraries like Vue x and Vue router.</p>
<p>So let's get started looking at the code.</p>
<p>So I'm going to start here with the package dot JSON.</p>
<p>Now this is the file that's generated by NPM.</p>
<p>You should have seen one of these before if you've worked with JavaScript, and it has some metadata about our project here, and then the scripts section.</p>
<p>So you don't need to know what all of these scripts are doing.</p>
<p>This code will be available for you.</p>
<p>So if you want to dive deeper into each one of these you can.</p>
<p>But since we're focusing on Vue here, the important part is that we have this start server that compiles our styles and serves our application for us.</p>
<p>Now later on, I'll show you how to start an application with the vcli.</p>
<p>But I had to use some kind of a temporary server here in the meantime.</p>
<p>So that's what live server is doing for us, it will serve it on a port, similar to what we did with the live server plugin that we used in VS code for the last demo application.</p>
<p>So to start this application, I'm going to go up to my terminal option here.</p>
<p>And I'm going to choose new terminal.</p>
<p>And my terminal opens at the bottom here inside my current folder.</p>
<p>And I'm going to run the start command.</p>
<p>So NPM start, you can see that automatically opens the application on the correct port here.</p>
<p>And if I scroll down, I can see the same page that you already saw.</p>
<p>Now back in the code, let's look in the source directory.</p>
<p>So the source directory is where all of our JavaScript and other code is going to live.</p>
<p>And this is where we'll also be adding Vue js.</p>
<p>This is our main HTML file for the application, which is the home page.</p>
<p>And you can see the links here go to Vues pages inside of this Vues directory over here.</p>
<p>So the links will take you to the past orders page and also the Products page.</p>
<p>Now to start working with Vue j s, I'm going to start with these cards here.</p>
<p>Right now I want to be able to update and save the quantities and be able to add them to the cart.</p>
<p>So in this app dot html file, I'm going to go ahead and add my link to Vue j s, just like I had in the last demo application.</p>
<p>So I'm going to go to the bottom here and paste the script tag.</p>
<p>So I'm importing vj s.</p>
<p>And now I need to write some custom vj s code to get my application.</p>
<p>So I will create another script tag.</p>
<p>And here I'm going to do let app equal Vue dot create app up a pass it in empty object for right now.</p>
<p>And then here I'm going to do app dot mount and then mounted in the same DOM element as before with the ID of app.</p>
<p>And let me just check here.</p>
<p>Yes, the wrapper div here.</p>
<p>If I fold it, you can see all of the content is created inside of app.</p>
<p>So to get started here I definitely want to create a data method.</p>
<p>And I need to return an object.</p>
<p>And on this object, I want to track my inventory.</p>
<p>So when someone clicks the Add to Cart button, I want to increment or change the amount of inventory that I have.</p>
<p>So inventory itself will be an object.</p>
<p>And you can see the different types of produce that I have here.</p>
<p>So carrots, pineapples, and cherries.</p>
<p>And so I'm going to add these three items to my inventory, carrots, and I'm going to initialize all of these with zero.</p>
<p>That looks good.</p>
<p>Now I need to find these elements inside my application and put the variables there.</p>
<p>So if I look down at these cards, you can see here's the recommended product section.</p>
<p>So I have carrots here.</p>
<p>And I have the price here is the quantity with the input field.</p>
<p>And what I want to do here, instead of setting the value, I want to do v model.</p>
<p>And this should be inventory, dot carrots.</p>
<p>And then I'm going to copy the same thing for the other fields.</p>
<p>So come down here to pineapples, and paste this.</p>
<p>And then cherries as well.</p>
<p>Okay, now let me take a look at that.</p>
<p>And you can see it still shows zero here.</p>
<p>Just like before I can update a number, we do three carats.</p>
<p>And now the number starts at three.</p>
<p>So now we want to do something when someone clicks add to cart, if they have a certain quantity in here, we want to add it to a cart total, we change this back to zero.</p>
<p>So to do that, I need to create a method, we create my methods object, I'll create an Add To Cart method.</p>
<p>And in this method, I need to take in the number of items that someone wants to add to their cart, and also the type of item.</p>
<p>So to do this, I'm going to need another place to store what items are actually in the cart.</p>
<p>So I'm going to create a cart here.</p>
<p>And for right now, I'm just going to copy the same items over.</p>
<p>And then when I call the add to cart method, I need to pass in the type of item and quantity, then I can access my cart variables by doing this, that cart and pass in a variable that I want to access on my cart object, I need to use the square brackets, and then I can pass in type.</p>
<p>So it would be the same as this cart carrots or this card, pineapples, or whichever item we want to access.</p>
<p>And then I'm going to increment by the quantity.</p>
<p>So plus equals quantity.</p>
<p>Now I don't have to return anything from this function.</p>
<p>Because this is really the action that I want to take by calling this function is to update whatever I have in my cart right now.</p>
<p>And to show this, I'm just going to log this out in the console in the browser, so you can see it when I log out this cart.</p>
<p>And I'm gonna open my console here.</p>
<p>So for carrots, I'm going to add three, you can see nothing happened.</p>
<p>That is because I forgot to connect this method to that button.</p>
<p>So let me go up here and add that button.</p>
<p>So I'm just going to add it to carrots right now, here.</p>
<p>So when someone clicks on the Add to Cart button, I'm going to call the add to cart method.</p>
<p>Now I need to call it passing in a few arguments here.</p>
<p>So the first one is going to be the type of item that I want to add to the cart.</p>
<p>So this one will be carrots, and I also need to pass in the quantity.</p>
<p>To pass in the quantity I need to use the inventory carats variable.</p>
<p>So I can just pass that in here.</p>
<p>I could also just call it from inside of my function which is Actually what I'm going to do.</p>
<p>So let me scroll down to see my function again.</p>
<p>And instead of quantity here, instead of passing in this extra variable, I'm going to just update this to this dot, this dot inventory, and then get the type from there.</p>
<p>So let's see if this is working.</p>
<p>Let me add to cart.</p>
<p>And you can see there is definitely a problem because the input value is a string, and it's trying to add it to the numbers zero, so then it turns the expression into a string.</p>
<p>Now Vue has a very easy way of fixing this.</p>
<p>And this is through a modifier just like we learned about a little bit in the last demo that we did.</p>
<p>So let me go up here to the V model.</p>
<p>And we don't want this V model to be considered as a string, we want to go ahead and cast it as a number.</p>
<p>So Vue gives us this modifier as a shortcut.</p>
<p>So v model DOT number.</p>
<p>So now if we look in our application, may add to cart.</p>
<p>And I can see down here that my carrots have one item in it, which is a number so I can add to cart again.</p>
<p>And now it's two, and I can add multiples.</p>
<p>And now there's eight carrots in the cart.</p>
<p>Let's stop here for this video.</p>
<p>And don't forget to download the related code and try out these features for yourself.</p>
<p>In the next video, we will work on displaying the items in the cart.</p>
<p>So now we want to hook up this cart menu or cart slide out.</p>
<p>And right now it's just static content.</p>
<p>So we can only see it from the Products page.</p>
<p>And if you look at the code, we go to the products dot html, I'm going to fold this header, and also the main container, which is this main part of the page right here.</p>
<p>And now I can just see this aside, which is that cart section on the side.</p>
<p>So I basically want to get all of this HTML and make it available on my other pages like my app page, which is the homepage, so that I can use Vue j s to trigger opening or closing the menu.</p>
<p>And I also want to make these cart items dynamic.</p>
<p>So when I add more items to the cart, it can update the quantity and the price.</p>
<p>And I can also set a variable.</p>
<p>So if there are no items in the cart, this will display.</p>
<p>Now HTML itself doesn't have something like an import to import a block of HTML into another HTML file.</p>
<p>A lot of people use PHP or some other back end tool for that.</p>
<p>But we can also easily do this in JavaScript.</p>
<p>So we're going to do this in Vue, j.</p>
<p>s, actually.</p>
<p>So I'm going to remove this sidebar from the page that it is on right now.</p>
<p>And move it into our Vue application.</p>
<p>Of course, our Vue application is nested inside of the app dot html page.</p>
<p>But we can move it outside later.</p>
<p>So that this menu will be accessible on all pages in the future.</p>
<p>So I'm going to fold this Vue create app.</p>
<p>And now I will paste this HTML aside that I have.</p>
<p>Now it's giving me an error or a couple errors right now because it's inside of a script tag.</p>
<p>But I'm going to fix that.</p>
<p>So if you recall, in the earlier lessons, we defined the different components inside of our Vue application.</p>
<p>So this is a perfect use case for a component right now, because it's this reusable block of HTML or template that we want to use on multiple different pages and also interact with.</p>
<p>So I'm going to register this as a component.</p>
<p>And I'm just going to call it sidebar.</p>
<p>And now I pass in the object just as before, and on this options object, I can set the template and then use graves.</p>
<p>And now I want to grab this aside again.</p>
<p>And paste it inside of here.</p>
<p>And so now I have this whole aside all of the code inside of my template for this component.</p>
<p>And now I can add this To the page with the name sidebar.</p>
<p>So I'm going to go ahead and add it here.</p>
<p>And remember that our div wraps the whole Vue application.</p>
<p>So I can put this anywhere inside of that div with ID of app.</p>
<p>I'm going to put it here, actually between the main and the footer, I'm going to put the custom component, sidebar, and Vue will handle putting the template I have down here where this sidebar element is in the template.</p>
<p>So let me go back to the HTML here, you can see the sidebar is no longer on the Products page.</p>
<p>But if I go to the home page, now I have a sidebar here.</p>
<p>So now that the sidebar is in Vue js, I can start making it interactive.</p>
<p>And the first thing I want to do is be able to hide and show the sidebar.</p>
<p>So basically, when this is clicked, I want to hide it.</p>
<p>And then when another button is clicked, I want to show it.</p>
<p>So I need to create a variable for this.</p>
<p>And let me go down to my JavaScript down here.</p>
<p>So inside of my regular create app here, in my main options object, I'm going to add an element to data here.</p>
<p>And I'm going to call it show sidebar, false.</p>
<p>And now I can come to my sidebar, and simply use a vi F, and point it to the variable show sidebar.</p>
<p>So if show sidebar is true, then my custom component will show up on the page.</p>
<p>If it's false, then I shouldn't see the sidebar at all.</p>
<p>And you can see it's false, I don't see any sidebar.</p>
<p>And when I change this to true, I see the sidebar.</p>
<p>Now I just need to add a toggle for this sidebar and change it back to false by default.</p>
<p>And now I can create a method called toggle sidebar.</p>
<p>And I'm going to say this dot show sidebar equals the opposite of whatever it is because it will toggle true or false every time this function is run.</p>
<p>So I'm going to say it equals not this dot show sidebar.</p>
<p>So if it's currently false, that means it will be set equal to true and if it's true, it will be then set equal to false.</p>
<p>Now I just have to call this method.</p>
<p>So the first place that I'm going to put it is on this button here, this cart button should open that cart sidebar.</p>
<p>I'm going to find that on the page.</p>
<p>Here is that Cart button.</p>
<p>And I'm just going to add an ad click here.</p>
<p>Add click equals toggle sidebar, I don't need to pass anything in so I can just leave it as this.</p>
<p>And Vue will automatically look through my methods and find that method.</p>
<p>So let me see if that works.</p>
<p>Go back to the page should be able to click on this now.</p>
<p>And yes, it does toggle.</p>
<p>Now the next thing I need to be able to do is close it and I need to close it using this x here.</p>
<p>So I'll have to go down to my template here.</p>
<p>And here is the button.</p>
<p>That's that x that's in the corner of the header for the sidebar.</p>
<p>So I need to add an app click on this.</p>
<p>And I'll have to do app click.</p>
<p>And now I want to use the function toggle sidebar.</p>
<p>But because this is wrapped in its own component, I actually don't have access to the toggle sidebar function from here, I actually have to pass it into this component to be able to access it.</p>
<p>And I can do that here.</p>
<p>So I'll pass it in as toggle equals toggle sidebar, I'm using my method on the vj s object called toggle sidebar passing it into the sidebar component with the name toggle.</p>
<p>So inside my component here, it's going to be called toggle.</p>
<p>So I'm going to have to accept it as a prop and as accepted as toggle.</p>
<p>And that will be my function name.</p>
<p>So now I have to rename this function and call it toggle.</p>
<p>Let me see if this works.</p>
<p>Go to cart click x and it is not working.</p>
<p>So I do have an error here maximum call stack size exceeded.</p>
<p>So let me see what I do.</p>
<p>Wrong in the code.</p>
<p>So I'm importing the prop toggle, the function should be called from here of toggle sidebar that is pointing to toggle sidebar here.</p>
<p>And, oh, I forgot to make this point to a Vue variable.</p>
<p>Instead, it was just trying to use it as a string before which was causing an error.</p>
<p>So now it should be calling the actual toggle sidebar function.</p>
<p>And let me see that in the code.</p>
<p>Okay, it works just as intended now.</p>
<p>So now on the sidebar, I want to be displaying actually dynamic items here.</p>
<p>For right now, I only have one item hooked up carrots.</p>
<p>And so I'm only going to be working with this one item until the next video.</p>
<p>So let's hook this item up.</p>
<p>When I add items to the cart here, I should it should update in the cart over here.</p>
<p>Now to do that, I need to take this cart object and pass it in to my sidebar, so my sidebar has access to it.</p>
<p>First, let me do some cleanup here.</p>
<p>With this on multiple lines to make it a little bit cleaner.</p>
<p>And I'm going to pass in cart as just cart.</p>
<p>And now I have to receive this prop in my component here.</p>
<p>So I'm going to do it here and call it cart.</p>
<p>And now cart that I'm getting in my component is actually that cart object.</p>
<p>So since I'm only working with carrots for right now, I'm going to just assume that and only add the number here for carrots.</p>
<p>So I'll use my double mustache syntax.</p>
<p>And I have that cart variable.</p>
<p>So I'll do cart dot carrots, and that will be the number of carrots that I have.</p>
<p>So let me go back to here and automatically updated.</p>
<p>Let me add three.</p>
<p>And my cart now is quantity three.</p>
<p>So if I add, let's add five more now this quantity eight in my cart.</p>
<p>So now my cart is dynamic.</p>
<p>Of course the total should also be updated based off of the quantity should be price times quantity equals the total for that item.</p>
<p>So let me do that really quickly.</p>
<p>This is the total number.</p>
<p>So I'm just going to have to do this.</p>
<p>And let's say cart dot carats times the price which it says it's $1.</p>
<p>But here it says 482.</p>
<p>So I'm going to use this price because $1 isn't that interesting.</p>
<p>So I'll do times 482.</p>
<p>And then before that, I need to put in dollars.</p>
<p>And let's see if that works.</p>
<p>To add to cart.</p>
<p>Now there is an error, let's see what the error is unexpected token with a dot.</p>
<p>The reason why it's complaining is because $1 sign followed by curly braces.</p>
<p>in JavaScript, whenever you put that syntax inside of the backticks that we have around this template here.</p>
<p>It's called a template string.</p>
<p>And it will parse whatever is inside those outer curly braces as JavaScript.</p>
<p>So thinks we're trying to pass in a JavaScript object.</p>
<p>And it's complaining because cart carrots is not a valid key.</p>
<p>So the only thing we have to do here is actually escape the dollar sign.</p>
<p>So JavaScript doesn't think where you're trying to use a template string and pass in a variable.</p>
<p>And then Vue can just parse the double curly brace syntax on its own.</p>
<p>This should work.</p>
<p>So let me go to cart now my cart opens as normal.</p>
<p>You can see there's zero carrots.</p>
<p>And now if I add two carrots to the cart, and now gives me the correct total of 964.</p>
<p>Now I also want to have a total of all the items in the cart.</p>
<p>I only have one item now but I will have more items soon.</p>
<p>So I'm going to go ahead and add a function for that.</p>
<p>And then we will hook up the rest of the items in the next video.</p>
<p>So back in the code here, this is the total that I want to update.</p>
<p>So I'm going to add this and escape that dollar sign that comes with For the double curly braces, now I could create a formula just in line here and say carrot cart carrots, times the carrot price, plus the second item times that price, and so on and so on.</p>
<p>But that's not going to make a lot of sense.</p>
<p>And that doesn't scale for multiple items.</p>
<p>So what I'm going to do here is actually add a computed object.</p>
<p>And if you remember computed watches the changes in variables, and we'll update the result.</p>
<p>So I'll call this computed function cart total.</p>
<p>And on my cart appear.</p>
<p>Right now I have just the number of each item.</p>
<p>So for right now, I'm just going to hard code the price down here.</p>
<p>So I'm going to return cart dot carats times the price, which is 482.</p>
<p>And now I can take this computed variable that I created, and put it in here.</p>
<p>And now the cart total, that amount should be updated every single time.</p>
<p>Let's see if this works.</p>
<p>Add to cart, open my cart.</p>
<p>And there is a bug because it's not opening and stepping through trying to figure out why the cart total isn't working.</p>
<p>And it is because I have accessed it incorrectly.</p>
<p>So cart dot carrots has to be accessed This is inside of JavaScript, so I need to access it on the this context in my component.</p>
<p>So I have to access it on this card carrots, and that should come up with my number times that number.</p>
<p>So let me go back to my page.</p>
<p>And now it opens.</p>
<p>And if I add items, I can see it's $24.10.</p>
<p>Of course this isn't that pretty.</p>
<p>Sometimes it rounds it to one, or sometimes there's only one decimal, and sometimes there's like 10 here.</p>
<p>So let's just run this really quick using something built in in JavaScript.</p>
<p>So we just get two decimals.</p>
<p>I'm going to wrap this here, that two fixed.</p>
<p>And then the number two.</p>
<p>And let's go back to the browser, I'm going to open up the cart, add a few items.</p>
<p>And now it's at two decimals Exactly.</p>
<p>Always two.</p>
<p>Okay, I'm going to leave it there in this video.</p>
<p>Again, please try out implementing these features on your own from the example code, you should be able to check out the starter branch called homepage, one from the repository and start exactly where I did at the beginning of this video.</p>
<p>In the next video, we will cover adding all of the rest of the items to the cart by importing them into our JavaScript.</p>
<p>So we can use loops to make our code more efficient and not have to hard code everything.</p>
<p>In this video, we are going to pull in dynamic content to populate our page.</p>
<p>And that will be from this food dot JSON file.</p>
<p>So this actually has a list of objects of all different kinds of groceries that we are going to display in our app.</p>
<p>It has some information, like the names as well as the price.</p>
<p>And then even if we want to add a filter to sort by the type.</p>
<p>So how can we pull this into our application.</p>
<p>Actually, we are going to use lifecycle hooks in Vue j s for this.</p>
<p>If we come to our main Vue application here, below methods, I am going to add mounted hook just like we had before.</p>
<p>And inside of here, I am going to fetch this JSON data.</p>
<p>And that's going to be an asynchronous call.</p>
<p>So I first need to fetch this from the file name, which is food dot JSON.</p>
<p>And I'm going to call this the response.</p>
<p>And then I need to call the JSON method on that response.</p>
<p>Which I put on this line, and that will be data.</p>
<p>And actually I need to add a weight to these calls.</p>
<p>So res dot JSON, I can call that method.</p>
<p>I'm going to await this as well.</p>
<p>And then because I'm using a weight, I need to add async To this mounted method.</p>
<p>So now I've created the mounted lifecycle hook, I get my data, which is the array of all of the food objects.</p>
<p>And now that I have my data, I am going to set it on state here.</p>
<p>So instead of inventory here, I'm going to replace inventory, just get rid of all this dummy data that I have right now.</p>
<p>Set it as an empty array.</p>
<p>This will definitely break my application right now.</p>
<p>But it's okay because it's a step toward fixing it.</p>
<p>So now I'm going to set this stat inventory equal to data.</p>
<p>Let's see if that even works.</p>
<p>And I'm going to come to my Vue here, I can see my root.</p>
<p>And I can see that the inventory in my root element here that I have all 15 items.</p>
<p>Good.</p>
<p>So I know my data is working.</p>
<p>Now, the next two things I need to do are display that data on this page here.</p>
<p>And so these are just three recommended items, actually, all of the products will display on this page.</p>
<p>So for the homepage, I'm just going to display the first three and slice that list as I loop over it.</p>
<p>So now that I have inventory, I'm actually going to come up here to my main container.</p>
<p>And I'm going to come to the recommended section and fold all of these cards and get rid of the last two, because I'm only going to need one for my loop.</p>
<p>And now with this initial card, I'm going to turn it into a V for loop and loop over each item in that inventory array.</p>
<p>So equals product in inventory.</p>
<p>Let me just see what this looks like really quick.</p>
<p>And yes, it tries to loop through every single item in the whole inventory.</p>
<p>So I'm going to slice it at three items now.</p>
<p>And I can do this because inside of my Vue directive, I can put valid JavaScript.</p>
<p>So we're going to do dot slice from 023.</p>
<p>And now we'll go back to my page.</p>
<p>And you can see I only have three items.</p>
<p>Now, of course, it is only displaying carrot, because that's all still hard coded.</p>
<p>So let me put some dynamic content in here.</p>
<p>And first with the name, I'm going to put product dot name.</p>
<p>And then I believe it's product dot type.</p>
<p>Yes.</p>
<p>So here, I'll put product dot type.</p>
<p>And for the price, now I do have prices in two different currencies, I'm just going to use US dollars for right now.</p>
<p>So I need to access price dot USD.</p>
<p>And so here, I'm going to go ahead and escape this.</p>
<p>And then do product dot price, dot u, s, d.</p>
<p>And actually, this is just an HTML template.</p>
<p>This isn't inside of a JavaScript template string, so I don't need to escape that at all.</p>
<p>And that should be all of the dynamic content that we need for right now.</p>
<p>Let's actually go ahead and update the icon as well.</p>
<p>So that would be product dot icon.</p>
<p>Make sure that's the right.</p>
<p>One.</p>
<p>Yes, that icon.</p>
<p>Okay, so let me go to the page.</p>
<p>Okay, so the icons not working, but all the other data is displaying quite nicely.</p>
<p>So now we want to add functionality so that the quantity properly updates and we can add it to the cart.</p>
<p>Of course right now, all of these elements have the same v model.</p>
<p>So that's why they are marrying each other.</p>
<p>So let's change that.</p>
<p>Now I'm going to go to the V model here which is inventory carrots, but I need the inventory of the correct item instead of just hard coding carrots here.</p>
<p>So because these numbers are In order or because this is an ordered list, I'm going to come to my loop and get the index.</p>
<p>Of course, I could use the ID as well.</p>
<p>But I'll just use the index in the loop here.</p>
<p>And actually, I almost forgot, I also need to add a key here since I am looping.</p>
<p>So let me add that key.</p>
<p>And I'm going to come down here, and inventory, I'm going to pass in that index.</p>
<p>And then I'm going to add a new attribute called quantity.</p>
<p>And so this should model to an attribute called quantity, which is not currently on the objects, but that's okay, I'll just leave it off.</p>
<p>And this should just add the quantity key to the object as needed.</p>
<p>So let's see if this works.</p>
<p>Let me go back over here.</p>
<p>I'm going to add one here, you can see they're not all mirrored for each other anymore, I'm going to add it to cart.</p>
<p>And let me see how this represents in my Vue data here, I can come to inventory.</p>
<p>And I can see quantity of one.</p>
<p>Whatever number I've put this number mirrors it.</p>
<p>But now I need a way to add this to the cart.</p>
<p>So let me set up the cart then.</p>
<p>And here at this add to cart function, I do need to change it because I need to pass in instead of a string, the dynamic name of the item.</p>
<p>So I can do product dot name.</p>
<p>And actually here, I didn't think of this, but instead of inventory and getting the inventory at index, I, I already really have that in this loop.</p>
<p>That's what the product variable is.</p>
<p>So I'm just going to replace that.</p>
<p>And that should work just fine.</p>
<p>Now, of course, I don't really need this index anymore, because for the key, I can use the ID of the product.</p>
<p>So let me just use that product ID and that should work okay.</p>
<p>And then this should also mirror object to let me see if that does.</p>
<p>Yes, and the quantity is married.</p>
<p>Okay, now for the cart, passing in the product name as Add To Cart.</p>
<p>Let's take a look at the add to cart function.</p>
<p>We are passing in the type here.</p>
<p>And then saying this duck card duck type.</p>
<p>So it will be like this cart dot radishes plus equals whatever the amount is that this that inventory.</p>
<p>So we do need to do one more thing here, we could either search and find the item by name in the inventory, or the easier thing to do would be to pass in the index of that item.</p>
<p>So that's what we're going to do.</p>
<p>And while I'm changing this, instead of type now, I think it makes more sense to call it name because it is the name of the item.</p>
<p>And we're using type for the type of item like vegetable or fruit not the name anymore.</p>
<p>So now to access it in inventory, I want to do index and then dot quantity.</p>
<p>And that should work.</p>
<p>But we have to actually passing the index here.</p>
<p>And up here, we're actually going to be passing in the index actually.</p>
<p>So we're going to take the index here.</p>
<p>And now add to cart.</p>
<p>Okay, so we are getting not a number for these values.</p>
<p>So I actually want to see what we are passing in or what gets passed in to the function.</p>
<p>And so to debug the function quickly, I'm just going to console dot log and name and index.</p>
<p>Now back in the code.</p>
<p>So the arguments are getting passed into the function just fine.</p>
<p>So stepping back through this, I can see that my problem here is that I am doing a plus equals on cart or this cart name when there is no value for that name in the cart yet.</p>
<p>And by the way, I'm going to go ahead and get rid of my dummy data.</p>
<p>In the cart, and here, I'm just going to put a simple check.</p>
<p>So if not this dot cart name, then I'm going to set this cart name and equal to zero.</p>
<p>And now this statement should work.</p>
<p>Okay, let me try again.</p>
<p>So here, I'm going to do two.</p>
<p>And this should update.</p>
<p>Let's see.</p>
<p>Okay, yes.</p>
<p>So it's taking a minute, for some reason, buy, it shows the correct number of each in the cart, no more, not a number.</p>
<p>Now that shows it on the cart over here, I want to show it in the sidebar.</p>
<p>Right now in the sidebar is hooked up to only look for carrots.</p>
<p>So let's make the sidebar dynamic now.</p>
<p>So if you remember, the sidebar here is in this template.</p>
<p>So it's part of the custom sidebar component that we made.</p>
<p>And we are already passing the cart in here.</p>
<p>Now we actually need more information because the cart is only showing us the number of items in the cart.</p>
<p>But we also want more information from those items, such as the price.</p>
<p>So I'm going to come up here to my sidebar, and after cart, I'm going to be passing in the inventory as well as inventory.</p>
<p>And now I can receive that as a prop in my component.</p>
<p>So basically, we have to loop through all of the items in the cart and display their information now.</p>
<p>And we have a table here.</p>
<p>So we have all of the headers for the table.</p>
<p>And then we can loop through these rows and basically make as many rows as we want.</p>
<p>So I'm going to go ahead and add a v4 here to loop through each item in the cart.</p>
<p>And here, I do need to use the index, I will be using that as a key here.</p>
<p>Okay, and now these are being looped through in sidebar.</p>
<p>So if I come to the sidebar, I should see no items right now, of course the totally needs to be fixed.</p>
<p>And now I can see I have this item.</p>
<p>And now I have another item.</p>
<p>So now I need to get rid of these hard coded names.</p>
<p>Now to do that, I'm going to go ahead and grab the key for these items in the cart.</p>
<p>And actually, because cart is an object, this index is actually going to be a key.</p>
<p>And then the third one is index, or just I.</p>
<p>So now I have access to the item name, which is the key, the item quantity, which will change this to the name, quantity.</p>
<p>And here, I can change this to that key and we should see the names of all of the items in our cart.</p>
<p>Let's test this out.</p>
<p>Let me add different items to the cart, should see radishes and artichokes.</p>
<p>And in the cart, we do indeed see radishes and artichokes.</p>
<p>Now let's display the quantity.</p>
<p>So here, we can get rid of this and say just quantity, which we're pulling off of the object in the cart.</p>
<p>Of course, we already know that should work when we add an item here.</p>
<p>And quantity works.</p>
<p>Now price is a little bit trickier.</p>
<p>Because we don't have the price stored on the cart, we actually have to search through inventory for the price.</p>
<p>So we're going to make a helper method for that.</p>
<p>First, let me escape this.</p>
<p>And then we're going to call get price Asin the name of the item which is the key and we will find the price and return it based off of the name.</p>
<p>So after computed here, I'm going to add methods for this regular methods object and add that get price.</p>
<p>And basically we can access this dot inventory and to do a dot find.</p>
<p>So we want to find one of the inventory items.</p>
<p>So I'll call each item product in the function that I pass in, and find will loop through all products in the inventory and try to find whatever item I want.</p>
<p>So I want the item where the product name is equal to the name that I'm passing into the function.</p>
<p>And when I find that product, I'm going to set it equal to a variable here.</p>
<p>kind of confusing, if I call it product again, so maybe I'll just call this one p instead.</p>
<p>There we go.</p>
<p>And now for the return function, now that I have the product saved in this variable, I can do product.</p>
<p>And it should be dot price dot USD again.</p>
<p>So dot price that USD.</p>
<p>And that should return the price of the item.</p>
<p>And let's see if that works.</p>
<p>So let me get one here and Vue the cart.</p>
<p>And I can indeed see the price.</p>
<p>Let me try that for artichokes too.</p>
<p>And I can see the price and quantities of the item correctly.</p>
<p>Now, let me update the function for total.</p>
<p>And so total here needs to be dynamic, based off of the whole cart really.</p>
<p>So to do this, I'm actually going to use a helper method.</p>
<p>So what I'm going to do is take this out of computed, and instead use it as a method.</p>
<p>So since it's not computed as a method, I'm going to call it a verb.</p>
<p>So calculate total.</p>
<p>And I'm going to go ahead and rename the method call down here, of course, I'll actually be calling that as a function now.</p>
<p>And I won't be needing this line of code anymore.</p>
<p>So now we basically need to calculate the total based off of the quantity in the cart.</p>
<p>And then we have to look up the price in the inventory.</p>
<p>Fortunately, we already have a method to be able to look up the price.</p>
<p>So we're going to just use that.</p>
<p>And the easiest way to do this is actually to do object dot values.</p>
<p>And so object dot values can give me an easy array of values out of an object.</p>
<p>And because cart is an object, I'm not going to loop through it directly, I'm just going to grab all of the values out.</p>
<p>So I will pass in cart.</p>
<p>And now I have an array of all of the values here, which are the quantities that I want.</p>
<p>So out of that array, I'm going to reduce it.</p>
<p>Now the reduced function is just a built in JavaScript function, where I save an accumulator.</p>
<p>Some people like to call it a Some call it an accumulator, because that's what it uses on MDN.</p>
<p>And basically, I'm calculating a sum on each iteration through the loop.</p>
<p>I also have my current item that's being looped through.</p>
<p>And then I can also get the index of that item in the function.</p>
<p>And basically, what I want to do is return the accumulator, sum total, whatever you want to call it, plus the current item or the current value, because I'm looping through all of the values on the cart here.</p>
<p>And I need the value times the price.</p>
<p>So I'm going to have to call this dot get price.</p>
<p>And then I need to pass in the name of the item that I want to get the price for.</p>
<p>So the easiest way to do that is to also make an array of names.</p>
<p>So I'm going to do that by using this time object keys.</p>
<p>And I will do this cart, get all of the keys this time off of cart.</p>
<p>And actually, I forgot to put this here.</p>
<p>And so I will do the current value times this dot get price.</p>
<p>And now that I have the names here, I'm just going to look up by the index.</p>
<p>So I can pass a names index to that this dot get price function, and that should work.</p>
<p>For the function.</p>
<p>I forgot to put an arrow here.</p>
<p>And now for the total variable.</p>
<p>I just stored it in a variable to explicitly name it.</p>
<p>All I need to do now is return the total now, this time function works, there might be a more optimized way to do this.</p>
<p>This is just to demonstrate how to calculate a total using a VJs method for this application.</p>
<p>And it's basically just using regular JavaScript.</p>
<p>So let me add items to the cart here.</p>
<p>And of course, of course, this total, we haven't done yet.</p>
<p>But we do have two radishes, and the total says $2.</p>
<p>So let's add some artichokes.</p>
<p>And now we have a total of $30.32.</p>
<p>As you can see, those are the correct values, what I believe is happening is because objects are unordered, and arrays are ordered, that the names and the object values, they aren't being listed in the array in the same order.</p>
<p>So I'm going to have to instead of making two separate arrays here, I'm going to get rid of this one.</p>
<p>And here, I will just have to change this to entries.</p>
<p>And now my current value here will basically be in array, that will be the key and the value, each time looping through this larger array.</p>
<p>So for the value, now, I will have to access it at the first index.</p>
<p>And instead of names here, I can access the name at the current item at the zeroeth index, that all looks good.</p>
<p>The last thing I'm going to do is add an initial value here.</p>
<p>And this means that the accumulator will start at zero.</p>
<p>And also, if there are no items in this array, which there aren't any to start, that means the number will just be zero total.</p>
<p>And for here for the total, actually, I'm going to use that method again, that we use before, which was too fixed.</p>
<p>So I could do it to two decimals, which is what I want in my cart.</p>
<p>Let me see if this works.</p>
<p>And this is exactly what I want here.</p>
<p>So let me add items.</p>
<p>Yes.</p>
<p>And the price is exactly right.</p>
<p>One artichoke, and the price still works there.</p>
<p>Now what about the total here, that should be easy enough to do with our get price method.</p>
<p>So let's go down to the total.</p>
<p>Right now it's hard coded as carrots, which doesn't exist.</p>
<p>So now I can do just the quantity, which is the quantity of the item in the cart.</p>
<p>And then I'll call the get price method.</p>
<p>And I'm going to pass in the key, which is the name of the item.</p>
<p>And so that should multiply by the total.</p>
<p>Let's see if that works.</p>
<p>add an item and check out the cart.</p>
<p>And we do indeed see the total here.</p>
<p>Now it still says no items in cart, let's go ahead and fix that.</p>
<p>So this should only show if in fact, there are no items.</p>
<p>And so I'm going to add a V if here.</p>
<p>And just to speed this up, we're going to do object that keys and then check the cart object.</p>
<p>So if there are no keys on the cart object that will be zero, which is a falsie value.</p>
<p>And let's see if that works.</p>
<p>Let's go down here to radishes, add one in the cart, we are still seeing this no items in cart.</p>
<p>So I believe I have to do length here.</p>
<p>Let's see if that works.</p>
<p>Okay, that does work, but I have it backwards.</p>
<p>So I basically need to do if not, because if the length is zero, I want to show this.</p>
<p>And if it's not zero, then I don't want to show this no items in cart because there will be items in the cart.</p>
<p>So let's see if that works.</p>
<p>Let's first go here, it does show no items in cart.</p>
<p>And now let me go here.</p>
<p>And now it changes to the item in the cart.</p>
<p>And all of the totals are shown correctly and the quantities updated and all of that stuff.</p>
<p>The only other thing I want to do is provide full CRUD operations, and this delete does not work.</p>
<p>So I'm going to hook up the Delete now.</p>
<p>So you can see the Delete is here on this button for remove.</p>
<p>And so I'm going to add a function here and actually this function will have to be not inside of this component.</p>
<p>But inside of the parent component, which is my main Vue application in this case, so I'm going to do a click.</p>
<p>So when this button is clicked, I'm going to say remove item to remove the item from the cart, and then I need to pass in the name of the item, which is the key.</p>
<p>Now this remove item is going to have to be a function passed in as a prop here.</p>
<p>Because I can't mutate props, I couldn't change the inventory, or the cart actually directly from this component, I have to change it from the parent component where it originates.</p>
<p>So I'll take a remove item function, let me go ahead and pass that in.</p>
<p>Remove item equals remove item.</p>
<p>And now I have to create that function here as one of these methods.</p>
<p>So let me add that remove item, this will take in the item name.</p>
<p>And I am going to remove it from the cart basically.</p>
<p>So I can just remove JavaScript, delete this cart name.</p>
<p>Let's see if that works.</p>
<p>Let me add some vegetables to my cart.</p>
<p>And now I will remove them.</p>
<p>And it does not remove let's see if I'm getting an error.</p>
<p>Remove item is not a function.</p>
<p>So let's see why it's not considered a function.</p>
<p>I do have it in methods here, remove item.</p>
<p>Let's go here.</p>
<p>This is remove item that I'm passing into my sidebar.</p>
<p>I'm also accepting it as a prop in the sidebar here.</p>
<p>Let me get rid of computed.</p>
<p>So it's not recognizing this as a function.</p>
<p>So what I'm going to do is rename it in the child component.</p>
<p>Now, this is a workaround only for the CDN, you won't have this problem if you were using Vue JS from NPM.</p>
<p>But I'm just renaming the function in app component here.</p>
<p>There we go.</p>
<p>And of course, I need to pass it in as the name remove.</p>
<p>So I basically gave it a different name for the child component and for the parent component.</p>
<p>And let's see if it recognizes this as a function.</p>
<p>Now, I will come here.</p>
<p>And I can remove it from the cart.</p>
<p>Awesome.</p>
<p>Of course, when I add things to the cart, I do want the number to clear here.</p>
<p>So let me take care of that really quickly.</p>
<p>In Add To Cart here, just really quickly, I'm going to set this to zero.</p>
<p>Let's see if that works.</p>
<p>And back to zero, and it is in the cart now.</p>
<p>Awesome.</p>
<p>The only other thing is that the cart does show zero items, even when there are items in it.</p>
<p>That's because the number is not dynamic.</p>
<p>So let me change that really quickly.</p>
<p>Here, inside of the parentheses, I'm going to change this to be dynamic.</p>
<p>And I'm just going to call the variable total quantity.</p>
<p>Okay, and now I need to make this variable.</p>
<p>So what I'm going to do is create a computed object here.</p>
<p>And I'm going to say total quantity is basically the sum of all of the quantities in the cart.</p>
<p>And to do this, I'm going to use another reduce method, I'm going to say object, that values pass in this cart.</p>
<p>And then I will reduce those to sum up all of the numbers.</p>
<p>So I have my accumulator and my current value.</p>
<p>And then all I need to do is add the accumulator and current value together.</p>
<p>Of course, I'll set a default of zero here as a starting point or initial value.</p>
<p>And I'm just going to return this directly this time.</p>
<p>Let me see if that worked.</p>
<p>Right now it says zero, but let me add items Notes three, let me add one more.</p>
<p>And now it's four.</p>
<p>So the quantity is working.</p>
<p>If I remove one, now it's just one.</p>
<p>So that is a dynamic value now.</p>
<p>And that is basically it for the homepage here.</p>
<p>In the next video, we are going to move the Vue JS code outside of the app dot html file.</p>
<p>So we can see how it can work in multiple different pages.</p>
<p>And also some of the struggles that we might run into trying to build a multi page site via the Vue CDN and trying to do things like share data across pages and stuff like that.</p>
<p>If you want to see the starter code for this video, make sure you check out the branch and the repo called homepage, number two, or homepage, two.</p>
<p>Hi, everyone, welcome back.</p>
<p>First, I want to reVue what we did in the last video, we connected the cart slide out draw menu on the right here and made that fully functional.</p>
<p>And then we added an actual loop, as well as functionality to be able to add items to our cart here.</p>
<p>Now this is only one page, of course.</p>
<p>So we also have the Products page here.</p>
<p>So if I go to Products page, you can see the URL changes to go to the products dot html page.</p>
<p>Now if I look at this in my code, so let me open up the source.</p>
<p>And this app dot html file.</p>
<p>Again, you can see here is the header with all of the links on it.</p>
<p>I'm going to fold that real quick.</p>
<p>And then you can see the different sections of the page, including that sidebar that slides out that we actually want on every page.</p>
<p>But now it's kind of just hard coded into this homepage.</p>
<p>I can also go to Vues here.</p>
<p>So you can see in the header actually.</p>
<p>So when I click on products, it goes to Vues slash products, that HTML.</p>
<p>So it's actually navigating me to this products dot html page.</p>
<p>And if you look at the header here, here's the whole page, including a completely separate div with ID of app where we would have to inject our Vue JS code.</p>
<p>You can see we already did that on this page, because our Vue j s is in the script down here.</p>
<p>And we are rendering it or mounting it inside of that div.</p>
<p>But if I go to products, we have no JavaScript, no interaction, everything is hard coded.</p>
<p>We also have a duplicate header.</p>
<p>So this is exactly the same thing as the header on this page is just copy pasted into the HTML on this page.</p>
<p>Of course, we don't want to do that everywhere.</p>
<p>We don't want to have a copy pasted header for all of our different pages.</p>
<p>Not only that, we would have to copy paste the whole cart sidebar as well.</p>
<p>So to make this code reusable here, we need to extract these things into other files.</p>
<p>Now, this is not easy to do for plain HTML.</p>
<p>But we can use a Vue component like we did before with the sidebar.</p>
<p>So I'm actually going to extract all of this out into a separate JavaScript file.</p>
<p>And now import this file into my HTML.</p>
<p>And you can see my page is still working.</p>
<p>My cart is still fully functional.</p>
<p>And what this allows me to do is now take this file this JavaScript file that I have separated and import it also into my products dot html file.</p>
<p>And I'm actually going to grab both of the script tags so I can also have my Vue and I'm going to put them at the bottom here, except I'm going to have to go up a directory here because my app.js file lives outside of my Vues, right? Here's products.</p>
<p>And I need to get upload folder to app.</p>
<p>So I have to do dot dot.</p>
<p>And that should reference the correct app.js file.</p>
<p>Let me see if that's working for go to products.</p>
<p>And you can see the cart page doesn't open.</p>
<p>But that's because I have not hooked up the cart button yet.</p>
<p>So I will have to copy this over from the app dot html file for right now.</p>
<p>So if I go here, I can just take the same code.</p>
<p>And now it should reference that same toggle sidebar function, and also display the total quantity correctly as well, because I am importing the same Vue j s code in the script tag here.</p>
<p>Now, you can see that the cart variable displays just fine on the Products page.</p>
<p>But if I click here, of course, the cart doesn't open.</p>
<p>Because the cart is only available on this page, I only have the sidebar component here.</p>
<p>And the sidebar component, you know is actually a custom component that we made in vj s.</p>
<p>So we can put that on any page where we import the vj s.</p>
<p>So I'm just going to put it here below this main tag.</p>
<p>And with all the same variables, there should be fine, because we're sharing the same Vue JS script.</p>
<p>Let me save that.</p>
<p>Now you can see I can toggle the cart here.</p>
<p>And all of this is pretty much the same thing that we did on the homepage, down here where we looped through the different types of foods, we would do the same thing over here on the Products page, loop through them hook up in each individual number, then hook up the Add to Cart button so that it would actually display in the cart over here.</p>
<p>Now if I add items here, may add a couple to cart can see I have three in my cart here.</p>
<p>If I go to products, you can see the page refreshed.</p>
<p>And now there are no items in my cart.</p>
<p>So though there is some functionality to this application.</p>
<p>So far, there are a few problems that we have run into with just using a CDN to import Vue j s.</p>
<p>And that is how do we share data across pages and across pager refreshes.</p>
<p>So here at the homepage, when I add something to the cart here, it leaves the car as soon as the page refreshes.</p>
<p>So as soon as I navigate to another page, it's gone.</p>
<p>Now how would I fix that problem.</p>
<p>So generally, in front end applications, we would want to do something like persist our data or save our data somewhere.</p>
<p>One easy way to do that in the browser.</p>
<p>And one very common way is to go here in application.</p>
<p>And you can see there's different types of storage.</p>
<p>This is in browser storage.</p>
<p>And local storage will persist even if the page is refreshed.</p>
<p>So we can actually save the data like our current data into local storage here.</p>
<p>And then if we refresh or anything, we will just automatically try to pull anything that's saved from local storage for the way our application is set up right now.</p>
<p>That would be every time we navigate to a new page, we would have to check local storage, see if there's anything in there and then pull it into our application.</p>
<p>It's kind of a workaround for our setup.</p>
<p>So one way to fix this would actually be to create a single page application with Vue where the front end would actually do the routing.</p>
<p>Instead of our server.</p>
<p>In this case, we're just using a live server in VS code.</p>
<p>But our servers serving at pages every time we go to a new URL here.</p>
<p>And that's why it has to refresh because it's coming from the server.</p>
<p>Whereas if we make a single page application, there will be no page refreshes, we will go seamlessly from page to page because our front end in other words, Vue j S will be routing us to different pages.</p>
<p>The second problem, as you can see is sharing code.</p>
<p>We do have some duplicate code across pages.</p>
<p>Of course, we are reusing the same sidebar template here, this sidebar template.</p>
<p>We just registered it as a Vue template, a Vue component called sidebar and we can use that on any page.</p>
<p>Now.</p>
<p>We could do the same thing with header as well.</p>
<p>And we would probably do that if we were going to build an application using the CDN.</p>
<p>We get to extract this into a template as well.</p>
<p>And then we would have to do the same thing for the past orders page.</p>
<p>Of course, none of this is dynamic or set up yet.</p>
<p>But the easiest thing to do is actually to set up our project with something called the Vue see ally.</p>
<p>As our code base grows, it will be very difficult to manage many different components, if we are managing them just importing different files into all of our different HTML files.</p>
<p>But there is a much easier way.</p>
<p>And that is with the Vue COI This is why it was created.</p>
<p>The vcli basically gives us one command, Vue create, and our project name, and then it creates a whole project for us.</p>
<p>It walks us through a setup wizard asks us what features we want.</p>
<p>And then we'll create all of the files, folders and build tools necessary for a robust front end single page application.</p>
<p>So in the next video, we are going to take all of our code currently in HTML files and our JavaScript file and convert it to a Vue COI application.</p>
<p>I'll see you in the next video.</p>
<p>Let's get started with the Vue COI, I am at sea ally dot Vue j s.org.</p>
<p>And I'm just going to click getting started.</p>
<p>And if I go over to the side, click on installation, I can see that it is prompting me to globally install this Vue COI package at Vue slash c li so that from my command line or terminal, I will be able to use a Vue command to create projects.</p>
<p>Now you might see some places on the internet that install a different package without the at sign in slash dist Vue dash c li or something like that.</p>
<p>That is an older version of the package Vue basically has its own namespace and then each one of its packages are after the forward slash.</p>
<p>So to install vcli you can copy this command here.</p>
<p>I'm going to go to my terminal.</p>
<p>Now I have the Vue COI installed, I can check and make sure that it's installed by checking the version.</p>
<p>Right now I have version 4.5 point 11.</p>
<p>And now I want to use it to create an actual Vue project.</p>
<p>And I can do this through the Vue, create command, and then give it the name of the project that I'm going to create.</p>
<p>If you want to see the documentation for this command, you can come over here under basics to creating a project and read about how Vue create works here.</p>
<p>I'm going to go ahead and say Vue create product and cart as the name of my project and click Enter.</p>
<p>Now, if you've used some tools like create react app, you will notice that here, it's a little bit different.</p>
<p>It doesn't just bootstrap the whole project for you right away, you actually get to pick your own options, and the packages that you want to install and use.</p>
<p>These top four options here are actually custom options that I have created myself.</p>
<p>Vue gives us these two defaults right now one is for version two of you, and one is for version three.</p>
<p>And then it also gives us the option at the bottom to manually select features.</p>
<p>So I'm going to go ahead and do that just to show you how it works.</p>
<p>So I basically use the arrow keys to go down and then I can click enter when I want to select something.</p>
<p>Now you'll notice that this list here is multi select.</p>
<p>And if I press spacebar, I can select or deselect an item.</p>
<p>Of course I want to choose my Vue version because I want to use version three.</p>
<p>I definitely need to have Babel setup for me for transpiling my Vue code, I'm going to need routing in this application.</p>
<p>I'm also going to use state management with Vue x.</p>
<p>But I'm going to add that later to show you how to add a Vue COI package after you've already set up your application, CSS preprocessors or things like sass, if you think you will want To use sass in the future, it's a good idea to go ahead and set it up.</p>
<p>Now, I believe this also works with less and stylus as well.</p>
<p>And then I definitely want linting and formatting in this project.</p>
<p>And I can optionally select testing if I want, which, but I'm not going to do that this time.</p>
<p>So once I'm ready, I'm going to hit enter, it takes me to the next step, I can choose the version of uJs, arrow down.</p>
<p>And I'm going to choose version three, use history mode for the router.</p>
<p>This is a pretty small coding change.</p>
<p>But it's usually what you want to in a project.</p>
<p>This basically only affects the URL of your project from a user point of Vue.</p>
<p>So if you want your routes to be after a hashtag, it will use hash router.</p>
<p>If you want your ads to be after just a normal forward slash, like any website, you would navigate to in your browser, then you can just go ahead and use history router.</p>
<p>And I'm going to use history router.</p>
<p>Now it's asking me to pick a linter, and formatter, so I'm going to go ahead and pick es lint plus the standard config that it has for VJs.</p>
<p>Click enter lint files when they're saved, I'm going to choose to put my configuration in the package dot JSON this time, just so I don't have a bunch of extra config files.</p>
<p>Usually when you have larger projects, you want dedicated config files.</p>
<p>So it's not cluttering up your package dot JSON.</p>
<p>Do I want to save this as a preset? No, I do not this time.</p>
<p>But if you remember at the beginning of this walkthrough, the four top options, those were presets that I had saved in the past, but here I'm just going to say no.</p>
<p>Here, it's basically setting up my whole project with the file structure and everything.</p>
<p>And it's also running an npm install, you can see it successfully created my project.</p>
<p>If I list the folders inside now, I have this new folder that was created for me by Vue JS called product and cart.</p>
<p>I'm going to go into that folder.</p>
<p>And you can see when you spawn up the project for me, it also initialize a git repository for me, and saved all of the changes that it did initially as a commit.</p>
<p>So let me open this up in VS code.</p>
<p>And I have my complete project created for me by Vue.</p>
<p>In the next video, we will look through all of these folders and files and give you a little bit of a tour of how your Vue project is laid out.</p>
<p>Let's look at all of these files and folders Have you spun up for us.</p>
<p>Now looking at this, this looks pretty much like the last project that we worked on with static HTML, CSS and JavaScript files.</p>
<p>And that was by design, to give you the same style of coding and file structure that you would be using in a real Vue application.</p>
<p>This however, is much much nicer.</p>
<p>Starting with the Vue, see ally gives us a lot more features out of the box that we can see in the package dot JSON, we have three scripts here by default, there would be more if you choose to install the testing packages as well, because we installed a linter, the vcli gives us this link command.</p>
<p>And then it also gives us our main two commands for the Vue application for development locally, it gives us this serve command, which basically calls this package vcli service.</p>
<p>That's from Vue, j s gives it the serve command and it will run a development server for us.</p>
<p>So there's no more of the old complicated server setup that we had in the last version of this in the last application.</p>
<p>The build command is really for when we want to host our project live.</p>
<p>This will generate production ready files for you like your HTML, CSS, and JavaScript.</p>
<p>So you can deploy them and have a live website somewhere.</p>
<p>We're just going to be talking about this command in this video.</p>
<p>And to give you an idea of what it does, let's go ahead and run it.</p>
<p>I can use NPM to run the command.</p>
<p>So NPM run serve.</p>
<p>And now my app is running at Port 8080.</p>
<p>If I highlight something on the terminal, it automatically copies when it come to my browser, open a new tab and I can see it gives me an app or already set up out of the box.</p>
<p>And because we chose to install a router as well, it installed the default Vue router, which is also called Vue router.</p>
<p>And you can see I can go to different page routes.</p>
<p>Now this isn't the same as our last application, because there's no page refresh in between page routes.</p>
<p>These are not HTML links.</p>
<p>This is just a JavaScript router, rendering hiding or showing different pages of this application.</p>
<p>You also notice from the homepage, it's just Port 8080.</p>
<p>When you go to the about page at ad slash about, if we look in the public folder here, you can see here's our HTML page.</p>
<p>And we have a div of ID app.</p>
<p>And this is where our app will be injected.</p>
<p>But also when our application is built.</p>
<p>Under the hood, this Vue COI service command is running Webpack, and bundling all of our files together, and also handling running Babel to transpile our files, and so all of the JavaScript and everything will be injected as script tags as well here.</p>
<p>But we generally don't have to worry about this index dot HTML file in a Vue project.</p>
<p>Because again, most of what we will be doing is in the source folder right here.</p>
<p>So we have a main dot j.</p>
<p>s file that is always created for us.</p>
<p>So this is basically the same thing that we did in the previous application.</p>
<p>If you do c Vue to code, this file will look a little bit different.</p>
<p>But you'll still be able to see the different parts, just the organization and syntax is a little bit different.</p>
<p>Just like before, we have to pass in a root component, we chain on any packages that we want to use, in this case, the router, and then we mount that to the DOM.</p>
<p>So inside of the div with ID of app.</p>
<p>And you could also rewrite this as const app.</p>
<p>And then app dot use router, and then app dot mount.</p>
<p>That's a bit easier to parse through as you add more packages.</p>
<p>Now, when we are looking at this initial page, where does all of this come from? Let's take a look.</p>
<p>So we have our main component app.</p>
<p>But you'll notice in app, there's no real content here.</p>
<p>All it is, is a div.</p>
<p>This is basically the top navigation.</p>
<p>Now, where did this router link come from? This is a custom component actually.</p>
<p>And if you look at our main j s, when we use App dot use router, we are actually given some components like router link, as well as router Vue.</p>
<p>Now router link is actually a substitution for using the anchor tag to link to another page.</p>
<p>Except router link is made by Vue router, specifically for single page application routing, where our JavaScript handles the routing.</p>
<p>Instead of linking to a separate HTML page.</p>
<p>Of course, we only have one HTML page.</p>
<p>And all of our static content is injected into that one page.</p>
<p>And the router handles intercepting the route and making it appear as though you've navigated to another page.</p>
<p>While really it's just showing and hiding different elements on the DOM.</p>
<p>So we have these two router links.</p>
<p>And then what does router Vue do? So router Vue, is actually our page content.</p>
<p>And our router will handle replacing this router Vue tag with whatever component we tell it to in our routes file that we are about to look at.</p>
<p>So router Vue is just a temporary placeholder for whatever we put on the page.</p>
<p>And you'll see as we navigate to different pages, those home and about links at the top of this file.</p>
<p>Those will stay no matter what page we navigate to.</p>
<p>But all of the content below it will change because those are the components getting injected into this router Vue area here.</p>
<p>If we look into our router index.js file here, we can see that we are using the Vue router API to create a router and when we create a router here, we are passing in two things.</p>
<p>So the routes, which is an array of all our routes that we have in the application, and then history mode, it set this up for us because we chose to use history mode.</p>
<p>And Vue is handling all of that under the hood.</p>
<p>But let's talk about the routes here.</p>
<p>So we have the default home route, which is this page.</p>
<p>And then we also have the about page, which is found at this route.</p>
<p>Now, you don't have to worry about code splitting, and lazy loading and all of that other stuff.</p>
<p>Those are more advanced routing concepts.</p>
<p>So I'm going to get rid of that line.</p>
<p>And then just import the about component.</p>
<p>Just like the home component.</p>
<p>Now you basically define routes here.</p>
<p>And instead of importing the components that you want to show on a page into your app dot Vue, you just use a router Vue tag here.</p>
<p>And then you import any of your Vue components, like home and about into this file, you define the path where that component can be found it the name of that component, now the name is mostly used for routing, and then you tell it which component will be found at that path.</p>
<p>So at the home path, we're going to find the home component.</p>
<p>Now, where's the home component, you can see that it is in Vues slash home.</p>
<p>So let's go in here.</p>
<p>And we can see that this is the component, it has an image, which is the Vue logo on top.</p>
<p>And then it also imports another component into itself.</p>
<p>Now this component is not in the Vues folder, it's in the components directory.</p>
<p>Now why is it in the components directory, instead of just one folder for all Vue files, basically, in front end applications, files are usually split up between Vues, or pages.</p>
<p>So basically, anything in this Vues folder will be connected to the router.</p>
<p>So they will have their own routes, there'll be their own pages.</p>
<p>Anything in the components folder are things that are imported into other components.</p>
<p>They're meant to be parts of pages or reusable components that you use throughout your application.</p>
<p>Basically, anything in the Vues folder is connected to the router.</p>
<p>And if it's not connected to the router, and just imported into another component, then put it in the components folder.</p>
<p>And you'll see at the home route, there's a Vue image at the top.</p>
<p>And then there are all of these links here.</p>
<p>And that's exactly what we see in the home route.</p>
<p>Now if we go to the about page, it's not importing any other components or doing anything fancy.</p>
<p>There's only this h1.</p>
<p>So I header with that text, which is what we see when we go to the about page.</p>
<p>assets, of course, are a place for usually CSS images, anything like that to live.</p>
<p>Sometimes you will see other folders created here in Vue projects.</p>
<p>But these are the basic ones.</p>
<p>The only one that we are going to add later is the store folder.</p>
<p>And we'll talk about that in a few videos.</p>
<p>In the next video, we are going to start transferring our content over from our old static application into our Vue application.</p>
<p>Let's start moving things over one by one starting with the homepage.</p>
<p>I'm going to go over to my original code here into source and then go into my app dot html here.</p>
<p>The first thing that I need to grab is this header.</p>
<p>Now I do have some JavaScript functionality in here and I'll handle hooking that up in a minute.</p>
<p>But let me just copy paste for right now.</p>
<p>And move this over to a new file.</p>
<p>Now I'm going to need it on this homepage here.</p>
<p>But since this header is actually my app wide navigation, I am actually going to want to replace the navigation here.</p>
<p>So that I can use this and see this on any page.</p>
<p>For right now I'm going to get rid of these.</p>
<p>Now there's a bit of cleanup that I need to do here.</p>
<p>Because these anchor tags need to be changed to the Vue router router link tags.</p>
<p>And now I need an actual route.</p>
<p>So instead of pointing to an HTML file, I am going to give it a route that will be in my router here linked to a component.</p>
<p>So I have this products dot html here, what I'm going to do is changed that to slash products.</p>
<p>Of course, this can't be an H ref, this will be two, since that's expected by the router link, also need to change this from h ref to two.</p>
<p>And I can just call this route past orders get rid of the dot html.</p>
<p>And here as well change this to two.</p>
<p>And this should just be a forward slash.</p>
<p>I'm not going to worry about this yet.</p>
<p>This last router link at the bottom, I'm going to just comment that for right now.</p>
<p>And basically I need to create these three components that are linked to the routes.</p>
<p>Now I already have the home route here that is linked to the home component, I'm actually going to get rid of about and I'm going to change this to products.</p>
<p>I'm going to have to create a new component.</p>
<p>Now let me delete about from here.</p>
<p>And let me create a new file.</p>
<p>I'll call this products dot Vue.</p>
<p>Now this is a little bit different.</p>
<p>Instead of calling this just a regular JavaScript file, with the extension j s Vue has a custom file extension, which is dot Vue.</p>
<p>All of these dot Vue files are parsed by the Vue and web pack setup, that the Vue COI sets up for us.</p>
<p>So using these dot Vue files, we can put our HTML template, our JavaScript, and even our CSS all in the same file that gets parsed and all put together and bundled by the tools that vcli sets up for us.</p>
<p>Now I have a new file, I'm just going to create a template in here.</p>
<p>And I have four spaces, I'm going to switch to using two spaces for tab spacing.</p>
<p>And I'm just gonna put h1 products for right now.</p>
<p>Alright, before we get too far, let's see how this looks.</p>
<p>And we do have a Products page and home page now.</p>
<p>But of course, this is completely unstyled.</p>
<p>Let's pause here and start to bring over some of the styles in the next video.</p>
<p>Let's start to move our styles over.</p>
<p>Now our styles are going to live inside of this assets folder.</p>
<p>And I can go ahead and create a folder inside of there called styles.</p>
<p>Now how do I use styles in my project.</p>
<p>If you come to this app component here, you will notice that there is a style tag at the bottom of the component.</p>
<p>And these are what is providing custom styles for the application.</p>
<p>If I look in my browser, this is what is styling and centering the elements.</p>
<p>If I get rid of these styles, this is what it looks like without any of those custom styles.</p>
<p>In any Vue component, you can add styles directly inside of that component.</p>
<p>So if I wanted to do something I could change all h1 tags to the color of Blue.</p>
<p>And you'll notice this is just plain CSS here that you can write inside of these Vue files.</p>
<p>Now, if I go here, you can see that this is an h1 tag, and it has changed to being blue.</p>
<p>Also on the products tag that is blue as well, because that is another h1.</p>
<p>Now, if I look at this, though, those h1 elements are nowhere to be found in this component.</p>
<p>Those are actually in other components.</p>
<p>But by default, the style tag globally affects anything in the application.</p>
<p>So if I put a style tag here, even though it's in the app dot Vue file, anywhere in my application that has an h1 tag can be affected by this.</p>
<p>Now, this is generally not good practice.</p>
<p>Because if you want to globally change a style, you should put that in a separate style sheet.</p>
<p>So in some other dot CSS file, here, if I'm putting styles inside of my app dot Vue file, generally, what I intend to do is only let it affect the app dot Vue file.</p>
<p>So it won't change styles in any other component.</p>
<p>Right, it will only affect whatever is in my template in this file.</p>
<p>And that's why I use the scope keyword here.</p>
<p>Now, now that I've added the scope keyword, so you can see that the text changed back to black.</p>
<p>Because now that I've scoped this, it is only affecting styles within this Vue component, not in other components throughout the application.</p>
<p>Now, if I wanted to add an external stylesheet, let me just go ahead and create a temporary one here.</p>
<p>I'll call this main dot CSS.</p>
<p>And let me paste in my last style.</p>
<p>And I'll change the color.</p>
<p>This will not affect my application yet, because I have to import the CSS file.</p>
<p>Now instead of importing this into one of my HTML files, what Vue does is allow me to import it directly into my JavaScript.</p>
<p>So generally, that would be this main.js file, what I can do is import from assets, styles.</p>
<p>And then that main dot CSS, and the Vue, see ally set up Webpack for me in such a way that I can import styles directly into my JavaScript.</p>
<p>And it is all handled by the tooling.</p>
<p>So now if I go back to my browser, it's a little bit darker.</p>
<p>But you can tell that this is purple now.</p>
<p>Because I am importing it globally, into my project from this main dot CSS file.</p>
<p>Those are the basics of how you import styles into an application.</p>
<p>Now, if I come back to my original static application with our HTML files that we were using, if I come to styles here, you can see that these aren't just CSS files.</p>
<p>They are sass files, for the most part.</p>
<p>So how do I get these into my project if they aren't standard CSS files.</p>
<p>So Vue also has built in ways of handling this, let me copy these styles.</p>
<p>And I'm going to delete this styles folder here.</p>
<p>And I'm going to paste.</p>
<p>So I pasted in this styles folder from my other project.</p>
<p>And now if I look in this folder, there is one file called style dot SCSS, which is a sass file.</p>
<p>And this imports all of the rest of the files here, all of my other sass files.</p>
<p>Now it is this file that I really want to import into my project to get all of my styles.</p>
<p>I'm going to comment this out.</p>
<p>And now I'll import that sass file directly from assets slash styles, slash style dot s CSS.</p>
<p>I'll save that.</p>
<p>And now you can see that it is giving me an error saying can't resolve sass loader so it's trying to load those sass files.</p>
<p>But since they aren't regular CSS, we have to add another module to be able to import those files.</p>
<p>And that is like it says SAS loader.</p>
<p>If we look in the Vue COI documentation, and go to working with CSS under development, we can see that it has this section on pre processors.</p>
<p>Now, as it mentioned, we can select our preprocessor when we're creating the project, meaning when we ran that first Vue, create a project name, that command would take us through setting up SAS automatically.</p>
<p>Now, since we did not choose SAS back, then when we were setting it up, there are ways of adding these packages, which you can do through this command, npm install, and then installing the sass loader.</p>
<p>And also the sass package.</p>
<p>Now, if I scroll down a little bit, it is giving me this note about Webpack four, which is what I'm using in vcli.</p>
<p>Four, I have to make sure I have a compatible version of these loaders.</p>
<p>So I am going to go ahead and grab this npm install command where I can install sass loader at a specific version and also sass and installed those packages for me.</p>
<p>Now I should be able to run my server once again.</p>
<p>NPM run serve.</p>
<p>Now it is complaining that I don't have one specific CSS module, because I haven't installed it in my node modules.</p>
<p>But that is actually a good sign because that means that it is reading through the rest of my file here, it's reading through this, getting to this line and saying, Hey, I can't find that file.</p>
<p>So I'm just going to comment that out for right now.</p>
<p>And now we have one more error here.</p>
<p>And that is it's looking for images that it can't find right now.</p>
<p>Let's go ahead and resolve those.</p>
<p>And they're coming from this file.</p>
<p>So if I go to splash dot sass, now you'll notice the syntax is a little bit different here.</p>
<p>You can basically think of it as just an indented syntax without curly braces.</p>
<p>Either way, you can see that the attributes are the same here.</p>
<p>So I have a background image, it's looking for this image.</p>
<p>And again, there's a background image, which is looking for this green image.</p>
<p>So I'm going to create an images folder here, an IMG folder, and put those two images inside of the IMG folder, and then update this path.</p>
<p>So back in my old application, they were in my public directory, I have green, and splash.</p>
<p>I'm gonna copy those and paste them here.</p>
<p>And I should be able to reference the relative path here.</p>
<p>close this file.</p>
<p>And you can see I have the styles for my main application in here.</p>
<p>Now, let me do one more thing and get rid of this boilerplate here.</p>
<p>So I can be ready to put my own content there.</p>
<p>So let me get out of here.</p>
<p>And go to source slash Vues and home, I'll get rid of this image, also get rid of that component.</p>
<p>I'm just going to put home here for now and get rid of the component everywhere.</p>
<p>Now if I go back to this page, you can see that it is ready to add my own custom content.</p>
<p>And I can see the Products page in navigates as well.</p>
<p>One more thing I'll go ahead and do is add a past orders page to the router at this route.</p>
<p>And all I have to do is basically copy the products route.</p>
<p>This will be past orders.</p>
<p>I can call it past orders.</p>
<p>Past orders.</p>
<p>Now I need to create this component.</p>
<p>It's connected to my router.</p>
<p>So I'm going to create it in the Vues folder.</p>
<p>Call it past orders that Vue and I have a shortcut snippet here.</p>
<p>I'll show you To use us and second, but if I click enter, it just created the template tag for me.</p>
<p>And I'm going to put an h1 in here that says, past orders.</p>
<p>And now I have this page working.</p>
<p>So all three pages are there.</p>
<p>In the next video, I'll be putting content on these pages, and then hooking them up to JavaScript to be functional.</p>
<p>Now, let's work on putting actual content on this homepage.</p>
<p>I'm in the original application.</p>
<p>Now, let me go to source inside of Vues here, I have my pages, actually, the main page is still in app dot html.</p>
<p>So I'm going to go ahead and grab these two container elements here, the div and the main container, copy those, go over to my new code, my vcli project.</p>
<p>And here, I can come to my homepage, and just paste that in here.</p>
<p>Alright, now take this, just the indentation, get rid of that old word.</p>
<p>And now I have my splash container.</p>
<p>And also my main container.</p>
<p>And nothing is showing up on the page.</p>
<p>So if I look in the dev tools, it says cannot read property slice of undefined.</p>
<p>And I can search for where that is being used.</p>
<p>And inventory dot slice.</p>
<p>So of course, it is broken right now because I don't have any inventory.</p>
<p>So let me grab that from my original code base.</p>
<p>If I go here, I can see in food dot JSON, this file is really where I have my inventory items.</p>
<p>So I'm going to copy this file, copy, go over here.</p>
<p>And inside of source, I'm just going to paste that file.</p>
<p>And now I need to import this into my Vue j s.</p>
<p>So if I want this right now in my home component, I need to import it at the bottom here.</p>
<p>So let me import my data.</p>
<p>So import food from go up a directory food, that JSON.</p>
<p>Let's set it equal to a data variable.</p>
<p>So data and then I can return.</p>
<p>And then I can set inventory equal to food.</p>
<p>Okay, let's try this out.</p>
<p>And now we see the banner displays just fine.</p>
<p>And we can see our recommended Products section at the bottom, which is already displaying real data.</p>
<p>Because we already set this up.</p>
<p>And this is basically the same logic as with the other app.</p>
<p>But we've only rewritten this in a component structure.</p>
<p>Now let's pull in the other pages really quick.</p>
<p>So we have past orders, and also products.</p>
<p>Let's go to products.</p>
<p>And if I go to the Products page, I can just grab this main section here, go back over to my code, and then paste that in.</p>
<p>Now this page should work as it is because if I look at all of the code here, we never made that dynamic.</p>
<p>So that's something that we will have to change later.</p>
<p>But this is all hard coded.</p>
<p>Let me grab the past orders page real quick.</p>
<p>And then we can take a look at it in the browser.</p>
<p>So if I go to past orders, let me fold this main section.</p>
<p>I'm gonna copy this and go over here to my code.</p>
<p>Paste that.</p>
<p>And now let's take a look at these pages.</p>
<p>Okay, so our past orders page has an error.</p>
<p>And it's complaining that this eye tag, which was used for icons generally that it doesn't have a closing tag, meaning it's not explicitly self closing and I not explicitly closing it either, like this TD dag here has a closing TD tag there.</p>
<p>So I'll have to fix that.</p>
<p>That's just how Vue templates work.</p>
<p>So let me search for I, and seems like it's only in two places, which is good.</p>
<p>All I have to do to fix that is either I could do a closing tag, things like IMG and I and certain tags don't really have closing tags.</p>
<p>So all I have to do is make them self closing, since you're never going to nest anything inside of this tag in general.</p>
<p>So I'm just adding the forward slash at the end.</p>
<p>And I will do that with this AI as well.</p>
<p>And that fixed my error.</p>
<p>And now here's the Products page.</p>
<p>And the past orders page as well.</p>
<p>This is kind of a table Vue of previous orders.</p>
<p>Now what about the sidebar? Let's add that logic back in in the next video.</p>
<p>In our original application, we had this sidebar on the right to display our cart.</p>
<p>In this video, we're going to move that over to our new Vue see ally application.</p>
<p>So I'm in the original code base here.</p>
<p>If I go to any of my files, I can see there's a sidebar component, which is a custom Vue component that I define in my app dot j s file, this sidebar component that I register, and I can basically use it globally throughout my application.</p>
<p>Now, of course, this is just regular Vue code.</p>
<p>So I could absolutely do the same thing in my new application.</p>
<p>But there are other ways that I can now create reusable components.</p>
<p>So I'm actually going to put it in my components folder.</p>
<p>instead.</p>
<p>I'm going to copy all of that.</p>
<p>Let me go to components, I have this old HelloWorld component, I'm going to delete it because I don't need it anymore.</p>
<p>And then I'm going to create a new file here and call this sidebar dot Vue.</p>
<p>In here, of course, I need the template.</p>
<p>And I'm going to paste all of that code.</p>
<p>And this is basically all of the cart logic.</p>
<p>Now there are a few things I will need to add, pass in a dynamic toggle here when the button is clicked.</p>
<p>So let me go ahead and set that up.</p>
<p>Now the first thing I need to do is import this sidebar component into my application.</p>
<p>And it's going to be globally available across all my pages.</p>
<p>So I'm going to import it into my app dot Vue file.</p>
<p>And I'll do it below.</p>
<p>Actually I do at the bottom here.</p>
<p>I'm going to put sidebar, it has to be of course self closing here.</p>
<p>And also the convention is to capitalize custom components.</p>
<p>So you can easily see them and see they're even highlighted differently than anything that is lowercase that I've pulled in from a library or that is just standard HTML.</p>
<p>I'm going to get rid of my style tag here and add a script tag.</p>
<p>And now I can import that component.</p>
<p>So I'm going to import sidebar from that slash components slash sidebar dot Vue.</p>
<p>Now another way of writing this and what you'll see, a lot of times see in Vue applications.</p>
<p>Instead here you'll see an add sign.</p>
<p>Now this is a shortcut kind of a reference to the source folder.</p>
<p>So that way anywhere in my application, no matter how many files deep my components are, I don't have to do anything like dot dot slash dot, dot slash dot, dot, etc.</p>
<p>I can always reference the source folder with an at symbol.</p>
<p>So it will be source slash components slash sidebar dot Vue.</p>
<p>Now any component that I import into another component, I need to register it and tell my Vue application I'm going to be using this component.</p>
<p>And I can do that by setting a Component Object on this default options object in Vue.</p>
<p>And I can set the sidebar component here, registering it here or including it in the list of component notes here just means that I can use it up here in my template.</p>
<p>So how this works basically this whole object here, it's called the options object.</p>
<p>And any kind of JavaScript functions or data will get set on this object, I just want to point out that this is the exact same as the options object you used in custom components like this one, except the template in our dot Vue file is just included at the top up here inside of this template.</p>
<p>And if we look at this main app component here, everything inside this object, all of this data, computed methods, all of this stuff is the options object.</p>
<p>But here we have it to be used globally.</p>
<p>And when we create a vcli application, we basically get one template, and one options object per component that we use to define everything on.</p>
<p>Now the thing about this is that each component only knows about the JavaScript inside the options object of that component.</p>
<p>So if I create a function here, I can only use it up here and in no other component, unless I explicitly pass it into that component to be used.</p>
<p>Just the same way that we pass the data and functions around to different components when we were building the static application.</p>
<p>And here, we're going to need to do that, again, because sidebar requires certain things to be passed in.</p>
<p>Now, if we look, here, we can see that first there is a V, if Boolean, there's a function to toggle the sidebar, when it's clicked, or when the button is clicked to open or close it.</p>
<p>There is also a cart object for what is currently inside the cart.</p>
<p>There are all of our inventory items, and then there is a remove item function.</p>
<p>So I'm going to copy all of these things and paste them over here.</p>
<p>And now I need to define these properties.</p>
<p>The first thing is Vf, I need to create a show sidebar data property here.</p>
<p>And I'm gonna set this just default as true for right now.</p>
<p>So I can see the sidebar.</p>
<p>Now I need a toggle sidebar function.</p>
<p>Now, where does this come from? It has to come from my app component up here, because I'm passing it in, basically from app to the sidebar component.</p>
<p>So here's my toggle sidebar function.</p>
<p>And I'm just going to grab all of these functions right now.</p>
<p>And I'll create that methods object.</p>
<p>And I pasted in all of my methods here.</p>
<p>Now, here's another tricky part because I want to reference inventory here.</p>
<p>But unfortunately, I only have it in my home component, which I just kind of quickly put there to fix my issue of basically inventory being undefined.</p>
<p>So I'm going to have to restructure my application.</p>
<p>So I'm not importing inventory separately into each component.</p>
<p>So let me actually take this import.</p>
<p>And I'm going to just import inventory into my app dot Vue component.</p>
<p>So I'm importing it here.</p>
<p>And then my logic here, so inventory food.</p>
<p>And I'm going to add that to that as well.</p>
<p>So inventory is food.</p>
<p>Now I need to get it to my home component.</p>
<p>But it's not really a registered component on this page, like sidebar, I can easily pass elements into sidebar as props, because it's a registered component right here.</p>
<p>But home is a little bit different because the router is dynamically putting the home component there.</p>
<p>So how do I pass props through the router then, to whatever component the router loads, what we're going to do is pass in inventory into basically any router Vue component.</p>
<p>So I'm going to pass in the inventory variable And of course, I need to V bind this to make it actually look for a variable, and not consider it to just be a string here.</p>
<p>So now I'm passing in inventory.</p>
<p>And I need to accept that in the child component.</p>
<p>So instead of data here, I'm actually going to have to use props just as I did before, and have a props object, or I'll just do it as an array actually.</p>
<p>And I have to call it inventory.</p>
<p>There are few more broken elements that I will have to fix here that the sidebar is expecting, I have my inventory and remove item.</p>
<p>And I really just need my cart at this point.</p>
<p>Now, if I look in the original version, I can see the cart is just an empty object.</p>
<p>And then things can be dynamically added to the cart.</p>
<p>But we're going to worry about dynamically adding things in a minute.</p>
<p>But first, I'll just set it to an empty object.</p>
<p>So let me go to data here and set cart to an empty object.</p>
<p>Really quick, let's go ahead and grab this computed property as well, because we will need it.</p>
<p>So I'll come down here and put computed.</p>
<p>And let's check this out in the browser.</p>
<p>So it's complaining right now that it can't find this JSON file.</p>
<p>And that's because we are importing it from the wrong place.</p>
<p>And yeah, the app is running products, past orders, everything seems to be working okay.</p>
<p>However, we don't have the sidebar yet.</p>
<p>So let me go ahead and uncomment, this code here.</p>
<p>So we have toggle sidebar, and also showing the quantity and the button here.</p>
<p>So here, I should be able to see the button that we had before in our previous application.</p>
<p>Alright, when I come here, and refresh, nothing shows up.</p>
<p>So we have some kind of an issue.</p>
<p>It says uncaught type error kept by path of undefined.</p>
<p>So the path, this is referring to the router.</p>
<p>So I think it's giving us an error in the router link, because we are not properly using the router link.</p>
<p>So let me just change this to a div, we basically aren't telling it to route anywhere, we are just using it as a clickable element.</p>
<p>So we might as well be using something else.</p>
<p>And now it is working.</p>
<p>Except I can't click on the cart button that's not working yet.</p>
<p>But everything else is working.</p>
<p>Let me scroll up to see my original error here.</p>
<p>So it says cannot convert undefined or null to an object.</p>
<p>And this loop is basically inside of my sidebar component.</p>
<p>So it's complaining about this line here, line 25.</p>
<p>I'm trying to loop through a cart object, get the quantity and key as well as the index.</p>
<p>And basically it's saying that cart must be undefined value.</p>
<p>So let me take a look in my app here.</p>
<p>It's not opening.</p>
<p>So let me actually take a look at the original code.</p>
<p>And inside of my app dot j s, I have all of this code moved over except this mounted here, but I don't need that anymore, because I can now directly import the JSON file.</p>
<p>I don't need to fetch it.</p>
<p>So here's my sidebar component.</p>
<p>And actually, I didn't copy over any of the methods here and I'm also forgetting to add in the props.</p>
<p>So let me go ahead and do that.</p>
<p>Just copy this.</p>
<p>Go back here to sidebar and I do need a script tag at the bottom here.</p>
<p>So I'm going to add a script tag, paste in the props.</p>
<p>And then I also want the methods from here so I'm going to grab those as well.</p>
<p>Now calculate total and get price are defined Then I also have all of the props here.</p>
<p>So let's see if this works.</p>
<p>Yay.</p>
<p>And the toggle is perfectly working.</p>
<p>Of course, it's starting off as open.</p>
<p>If I refresh it, it just automatically opens.</p>
<p>So let me change that in app dot Vue.</p>
<p>I'll come here and say show sidebar is false.</p>
<p>All right, let me see if we can use this.</p>
<p>So it's not dynamically adding items to the cart yet.</p>
<p>So we will fix that in the next video.</p>
<p>In this video, we are going to hook up the add to cart functionality so that when we add to cart here, it will show up in the sidebar.</p>
<p>If I look in the terminal, right now, you can see that this add to cart, it's saying it's not a function.</p>
<p>So I'm getting an error when I click this Add to Cart button.</p>
<p>Now I can see why I'm getting that, because that is in my homepage component.</p>
<p>And if I go down here, I can see this add to cart function that I'm calling when I click that button is not defined anywhere in this component.</p>
<p>Where is that function defined? It is in the app dot Vue file.</p>
<p>So if I go to my methods, I can see I have an Add To Cart method right here, I basically need to pass this function into my homepage for my homepage to be able to use.</p>
<p>So I'm going to also pass that through the router, as I did before.</p>
<p>And then in my homepage, I can also receive that as a prop.</p>
<p>add that on to the props list, add to cart.</p>
<p>So I should have access to the function that I passed into this home component now through the router Vue.</p>
<p>And let me refresh and see if this works.</p>
<p>Add To Cart.</p>
<p>And you can see that the function is working because the quantity changed down to zero.</p>
<p>The cart says two items.</p>
<p>And if I open it, it does indeed list two items here.</p>
<p>Now, why are there forward slashes here, we can actually see in the homepage, that in regular JavaScript, this is actually in the sidebar component, that in order to put $1 sign before the variable we needed to escape it.</p>
<p>But we don't have to do that in a Vue j s application.</p>
<p>Because it's no longer in a regular JavaScript file.</p>
<p>It's in our Vue, j s template.</p>
<p>So I can get rid of all of these escaping characters.</p>
<p>And now that looks much better.</p>
<p>Now if I want to delete this, it deletes I no longer have any items in the cart, I can add a couple items and I get items in the cart.</p>
<p>If I go to another page, the cart should still work.</p>
<p>Because that is a shared component that I can see across any page.</p>
<p>In simple applications.</p>
<p>This type of data sharing works pretty well, we can keep all of our variables in a parent component.</p>
<p>So in this case, in our app dot Vue component, we pass functions and variables down to children.</p>
<p>And then children can call functions, like add to cart that will then update the state of the parent component.</p>
<p>Now in more complicated applications, we would need something a little bit more robust for state management, and being able to share all of this data throughout our application.</p>
<p>And we will talk about that in a future series where we cover Vue x, which is Vue j s is default state management library.</p>
<p>But for right now, we are going to leave the application as it is and work on it in future series and lessons.</p>
<p>So we have the homepage, the cart sidebar.</p>
<p>Now we really need to hook up some of the information on this page.</p>
<p>So the Products page And it's really exactly the same as the product section.</p>
<p>Here, on the homepage, we have all of the same kind of cards and information.</p>
<p>So since we have the same thing pretty much in multiple places of the application, it makes sense to pull out all of this UI that makes up these cards into its own component.</p>
<p>And then we can share it across the application and on any page that we want.</p>
<p>So let's go ahead and create a card component.</p>
<p>Now in components here, I'm going to create a new file.</p>
<p>And I'm going to call this product card dot Vue.</p>
<p>I'll start with a template.</p>
<p>And now I'm going to go to my home page.</p>
<p>And I can see there's a for loop here that is looping through and displaying all of the cards.</p>
<p>So I'm going to grab this whole card here and paste it in my product card file.</p>
<p>Now this is just an individual card.</p>
<p>So I don't need a for loop in here.</p>
<p>Let me get rid of this logic.</p>
<p>And this will just be one card.</p>
<p>Now I will need the product information for this card to display correctly.</p>
<p>So I'm going to have to accept that as a prop in my component.</p>
<p>So let me create a script tag.</p>
<p>I'll create props here, just an array of props.</p>
<p>And I'm going to say, product.</p>
<p>So I accept the product props into my component.</p>
<p>And now I can use it in my template.</p>
<p>Now, I can remove all of this logic from here.</p>
<p>And the only thing I need is actually to import that component.</p>
<p>So I need to import product card from, I'm going to use my source folder shortcut slash components, and slash product card dot Vue.</p>
<p>And now I need to register this as a component so I can use it.</p>
<p>And now in my code up here, I'm going to use product card.</p>
<p>I'll clean up the lines a little bit here.</p>
<p>And I need to make this self closing.</p>
<p>Because all tags in Vue templates need to either be self closing or having a closing tag.</p>
<p>Now I am no longer using this index here, I'm going to see in my product, if I'm using the index anywhere.</p>
<p>And I am indeed passing in the index.</p>
<p>So I will need to accept the index as a prop as well.</p>
<p>Let me change this to index that's a little bit more clear.</p>
<p>And I will get index here.</p>
<p>And I'm going to pass that in here.</p>
<p>Of course index is a variable, not a string, so have to V bind that.</p>
<p>And that should work here.</p>
<p>Let's see if this works.</p>
<p>And we are getting an error here.</p>
<p>Now that is because product is now a prop.</p>
<p>And of course we cannot mutate props from the parent component.</p>
<p>So we can actually fix this by not mapping to the product prop at all, we're actually going to create a local variable inside of this product component.</p>
<p>So each component each time we use the product card component, it will have its own local variable.</p>
<p>And we can do that by adding a data prop here.</p>
<p>And in the method, we need it return returns an object.</p>
<p>And now we can simply map quantity because each card only has one input box.</p>
<p>So we'll just map it internally in the card.</p>
<p>And we can check that this works.</p>
<p>Not sure why it only has two cards right now.</p>
<p>But let's try this.</p>
<p>So I pressed the number two.</p>
<p>And I can look in my Vue, j.</p>
<p>s, Dev Tools.</p>
<p>And I'm getting an error here.</p>
<p>And it says I can't read property name of undefined.</p>
<p>So product name.</p>
<p>Yes, I believe I have forgotten to pass in the correct props here.</p>
<p>So let me add those, I need to pass in product equals product.</p>
<p>And then while I'm here, let me also add the add to cart function equals Add To Cart.</p>
<p>There we go.</p>
<p>And now let's check it the page loads and the page is loading.</p>
<p>Alright, so now we have all of the cards loading.</p>
<p>And let me just look, in my Vue dev tools, I can see all of my product card components.</p>
<p>So let me just take a look.</p>
<p>If I change this to two, and I can see the quantity is two.</p>
<p>If I change it to 22, it's now 22.</p>
<p>Alright, so that is mapping correctly.</p>
<p>Now I need to get this quantity, the value up through the home component to the app component, where I am actually performing the function of adding it to the cart.</p>
<p>So what I'm going to do, for right now, I'm just going to pass in a third parameter, and I will pass in quantity.</p>
<p>And now let's take a look at our function, our Add To Cart function in the app component.</p>
<p>So we are adding items on to the cart, if they're not already there.</p>
<p>And then we are basically incrementing the number here.</p>
<p>So now that we have that third parameter being passed in, which is the quantity, all we have to do is changed this line to B plus equals quantity, which is now getting passed in.</p>
<p>And then of course, we don't need this line, because we are no longer mapping to a nested quantity.</p>
<p>Rather, we have the quantity variable right here.</p>
<p>This also means that we don't need to pass up the index anymore.</p>
<p>So we can remove that from this function.</p>
<p>We only need the name and the quantity basically, so that we can add it to the cart.</p>
<p>Let's check and see if this works.</p>
<p>If I come here, the number still maps to the component.</p>
<p>Now if I click Add to cart, it is not in my cart.</p>
<p>Let's see if we got an error.</p>
<p>Add to cart is not a function.</p>
<p>Let me look inside of my home dot Vue.</p>
<p>I have add to cart that I am getting from the parent component.</p>
<p>So from the app component, I'm passing that in to the product card.</p>
<p>And I should have it Oh right, I didn't accept it as a prop inside of the product card.</p>
<p>So now let's see if this works.</p>
<p>Let me refresh and go into my Vue dev tools.</p>
<p>And now I can see it's properly working here.</p>
<p>If I want to add 10 artichokes, and I have two radishes, and I have 12 items in the cart.</p>
<p>Now my rounding functionality isn't properly working, as you can see, but it is properly adding and displaying the quantity and the total in the cart.</p>
<p>But I don't just want this functionality on the homepage.</p>
<p>I also want it on the Products page.</p>
<p>So let me import those components into the Products page now.</p>
<p>So if I come to my product stock Vue file, I actually have access to inventory already in here.</p>
<p>Because if you remember in my app dot Vue Passing inventory and the add to cart function into anything displayed by the router Vue, which is basically any of our pages here home, past orders or products.</p>
<p>They're all connected to our router.</p>
<p>So let's accept those props in the Products page to start with.</p>
<p>First, let me fold up all of these cards, get them out of the way.</p>
<p>So let me do a script tag, props.</p>
<p>And I'm going to accept inventory and add to cart.</p>
<p>One more thing I need to do is import this product card.</p>
<p>So I'm going to go to the home component, and just copy this import and paste it into product or into the Products page.</p>
<p>And now I need to define this as a component here.</p>
<p>Product card.</p>
<p>And this should be components not component.</p>
<p>And I also have one more error here, which this should be a capital P.</p>
<p>And now if I see if I highlight this, all of these highlight, let me take a look at what this error is here.</p>
<p>The product card component has been registered, but not us.</p>
<p>So let's fix that.</p>
<p>So I basically have all of these cards here.</p>
<p>For the different items that show up on the page, I'm actually going to just delete all of these right now.</p>
<p>And instead, I'm going to add the product card.</p>
<p>So if I go to home, I can take a look at my product card that I'm actually using inside the template.</p>
<p>And I'm just going to copy that and paste it here.</p>
<p>But instead of slicing at three here, let me just do the first six elements instead.</p>
<p>Now because we already have inventory being passed in, as well as the add to cart function, of course inside the loop, we're taking care of the product variable, there's really no other state that we have locally on the products component.</p>
<p>So this should pretty much work out of the box for us.</p>
<p>Let's check here.</p>
<p>And we can see that it does indeed loop through and display all of the cards on the Products page.</p>
<p>Now, let me add a couple of these items to the cart here.</p>
<p>And you can see the cart just updated with five.</p>
<p>If I add few artichokes, let's add some cherries, and some cabbage, carrots.</p>
<p>everything right, we have 17 items in the cart now.</p>
<p>And we can see that it added all of these items.</p>
<p>Now if I go to the homepage, I can still see 17 items in the cart.</p>
<p>Because we moved to a single page application.</p>
<p>All of our routing is handled by the Vue JS JavaScript.</p>
<p>And we are actually sharing state between components.</p>
<p>So all of the state for our cart lives in the app component, which is the parent component of all the other pages, the home page, the product page.</p>
<p>And that's why all of the items in the cart all of the data that we save here, in our application, it stays no matter what page we navigate to.</p>
<p>And even though this is displayed, or this card is on multiple pages, you can see how have you made it very easy for us to reuse the same code and the same template to loop through and display wherever we wanted on the application.</p>
<p>And that's basically how reusable components work in Vue js.</p>
<p>I hope you enjoyed this course.</p>
<p>And you learned a lot about Vue js, learning it on three different levels through this course.</p>
<p>We started off working in a basic index dot HTML file.</p>
<p>And then we went on to a static site of grading it a little bit with some Vue js.</p>
<p>And then we moved on to using the Vue COI and creating a fully dynamic single page application that we have here.</p>
<p>definitely reach out to me if you have any feedback, comments or questions about this course.</p>
<p>You can find me on Twitter and pretty much everywhere online as Gwen Faraday or at Faraday Academy.</p>
<p>Have a great day and I hope to see you in the next course. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Accessible Vue Applications ]]>
                </title>
                <description>
                    <![CDATA[ By Abiola Farounbi Developing web pages used to involve writing HTML, CSS, and a little scripting code like JavaScript for functionality.  But over time, we've developed new and more advanced technologies and frameworks to create webpages. We now use... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-accessible-vue-applications/</link>
                <guid isPermaLink="false">66d45d593dce891ac3a967aa</guid>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 08 Jul 2021 16:23:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/07/Article-Poster-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Abiola Farounbi</p>
<p>Developing web pages used to involve writing HTML, CSS, and a little scripting code like JavaScript for functionality. </p>
<p>But over time, we've developed new and more advanced technologies and frameworks to create webpages. We now use things like reusable components, routing, and rendering to the document object model (DOM). </p>
<p>These new frameworks have helped developers make web accessibility an integral part of their applications. </p>
<p>In this article, we'll examine the concept of web accessibility, explore some accessible features for Vue apps, and build a demo Vue project that incorporates all these accessibility features. </p>
<p>To follow the tutorial portion of this article, you should have some experience with Vue and JavaScript. </p>
<h2 id="heading-what-is-web-accessibility">What is Web Accessibility?</h2>
<p>Web accessibility is the practice of designing and developing web applications and tools that are accessible to people with any type of disability. </p>
<p>In simple terms, web accessibility means making the web available and accessible to everyone. The web should be accessible to everyone to provide equal access to users, so anyone can experience the web's full benefits and capacity. </p>
<p>One benefit of making your web application accessible is to improve your site's SEO (search engine optimization). This makes it easier to find in different search engines.</p>
<p><a target="_blank" href="https://www.w3.org/WAI/WCAG21/quickref/">Web Content Accessibility Guidelines (WCAG)</a> provides an international set of principles for web accessibility. You can use it to guide your development to make the web accessible for all. </p>
<h2 id="heading-web-accessibility-principles">Web Accessibility Principles</h2>
<p>WCAG consists of four principles known as POUR: </p>
<p>P - Perceivable </p>
<p>O - Operable </p>
<p>U - Understandable </p>
<p>R - Robust </p>
<h3 id="heading-make-your-site-perceivable">Make Your Site Perceivable</h3>
<p>The perceivable principle means that users should be able to identify contents and interact with the interface using one or more of their senses (vision, touch, and hearing) through the browser or through assistive technologies like screen readers. </p>
<h3 id="heading-make-your-site-operable">Make Your Site Operable</h3>
<p>Making your site operable means users can interact with all controls and interactive elements using a mouse, keyboard, or assistive device.
Focus should also be enabled in the different sections of the page.</p>
<h3 id="heading-make-your-site-understandable">Make Your Site Understandable</h3>
<p>To make a website understandable, we should use clear and concise language. We should try to eliminate spelling errors and complex grammar. The content and functions should all be easy to understand. </p>
<h3 id="heading-make-your-site-robust">Make Your Site Robust</h3>
<p>To be robust, your site should be compatible across all platforms, devices, and browsers. The web content should be compatible with current and future software and tools. A wide range of technologies should be able to access web page content without limitations. </p>
<h2 id="heading-accessibility-features-to-implement-in-your-vue-apps">Accessibility Features to Implement in Your Vue Apps</h2>
<p>When you develop a Vue.js application, you should put some important features in place to make your web application accessible to everyone. </p>
<h3 id="heading-set-the-page-title-for-each-page">Set the Page Title for Each Page</h3>
<p>The page title gives users an overview of the page. Search engines also rely on it to determine if a page is relevant to their search. </p>
<p>When you provide a unique and concise title, it helps assistive technology users understand what the web page is about. </p>
<p>In a Vue app, you can do this by declaring meta tags in your routes: </p>
<p>```   routes: [ </p>
<p>    { </p>
<p>      path: '/', </p>
<p>      name: 'home', </p>
<p>      component: HomePage, </p>
<p>      meta: { </p>
<p>        title: 'Home' </p>
<p>      } </p>
<p>    }, </p>
<p>   { </p>
<p>      path: '/login', </p>
<p>      name: 'login', </p>
<p>      component: LoginPage, </p>
<p>      meta: { </p>
<p>        title: 'Login' </p>
<p>      } </p>
<p>    },  </p>
<p>]</p>
<pre><code>

For the meta tags to display, use the <span class="hljs-string">`beforeEach`</span> hook Vue-router provides:
</code></pre><p>router.beforeEach((to, from, next) =&gt; { </p>
<p>  document.title = to.meta.title </p>
<p>  next() </p>
<p>}) </p>
<pre><code>

To learn more about the router package, check the [official vue router website](https:<span class="hljs-comment">//router.vuejs.org/guide/essentials/dynamic-matching.html#reacting-to-params-changes)</span>

Over time, Vue community members have developed packages such <span class="hljs-keyword">as</span> [vue-head](https:<span class="hljs-comment">//github.com/ktquez/vue-head) and [vue-meta](https://github.com/declandewet/vue-meta) to add metadata when instantiating a component. </span>


### Specify the Text Content<span class="hljs-string">'s Language 

When you use the HTML lang attribute, it is easy for screen readers to identify the text content language. The lang attribute takes an [ISO language](https://www.loc.gov/standards/iso639-2/php/code_list.php) code as its value.

You can implement this in the index.html file:</span>
</code></pre><p> </p>
<pre><code>
If the application does not specify a language, the screen reader uses its <span class="hljs-keyword">default</span> language. This leads to an issue <span class="hljs-keyword">if</span> the page isn<span class="hljs-string">'t actually in the default language. The screen reader might not announce the page'</span>s text correctly. 

### Use Landmarks to Help Users Navigate to Sections

Landmarks provide easy access to sections within a Vue app. Assistive technology users can navigate to each section <span class="hljs-keyword">of</span> the application and skip over the content. 

You can enable <span class="hljs-built_in">this</span> using HTML5 semantic elements or Accessible Rich Internet Applications (ARIA) roles. 

Here are the HTML5 semantic elements and alternative ARIA you can use <span class="hljs-keyword">in</span> your application: 

![Landmarks](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2021/07/Landmarks.png)</span>

### Use Headings <span class="hljs-keyword">in</span> the Proper Hierarchical Order 

Your web application should include headings such <span class="hljs-keyword">as</span>:
</code></pre><h1 id="heading-"></h1> 

<h2 id="heading-"></h2> 

<h3 id="heading-"></h3> 

<h4 id="heading-"></h4> 

<h5 id="heading-"></h5> 

<p></p><h6 id="heading-"></h6> <p></p>
<pre><code>
To structure your content <span class="hljs-keyword">for</span> easy accessibility, your headings must follow the proper hierarchical order, <span class="hljs-keyword">from</span> H1 potentially down to H6, <span class="hljs-keyword">if</span> needed. Also, your headings should be brief, clear, informative, and unique. 

### Use Adequate Color Contrast <span class="hljs-keyword">in</span> Your Application 

![goodcontrast](https:<span class="hljs-comment">//www.freecodecamp.org/news/content/images/2021/07/goodcontrast.png)</span>

It<span class="hljs-string">'s important to ensure that the colors on your application have adequate contrast. The contrast between the colors of the text and the background must be distinct to make content readable.

### Use Alternative Text for Images 

In image code like below, adding the "alt" section enables you to describe the image.</span>
</code></pre><p><img src="image-url" alt=" description of the image" width="600" height="400" loading="lazy"> </p>
<pre><code>
Including alternate text <span class="hljs-keyword">for</span> an image makes it easy <span class="hljs-keyword">for</span> people who cannot see to understand the image using a screen reader. 

Use the <span class="hljs-string">`&lt;img&gt;`</span> tag only to show content images, such <span class="hljs-keyword">as</span> photos or illustrations, that are meaningful to the content. Also, use <span class="hljs-literal">null</span> alt text on purely decorative images. 

### Create Accessible Forms 

Making accessible Vue application forms may involve: 

- Using HTML5 Semantic elements <span class="hljs-keyword">for</span> forms elements, <span class="hljs-attr">like</span>: 

  <span class="hljs-string">``</span><span class="hljs-string">`&lt;form&gt;, &lt;label&gt;,&lt;input&gt;, &lt;textarea&gt;, and &lt;button&gt;</span>
</code></pre><ul>
<li>Including labels for form elements: </li>
</ul>
<pre><code>&lt;label <span class="hljs-keyword">for</span>=<span class="hljs-string">"name"</span>&gt;Name&lt;/label&gt;  
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"name"</span>  /&gt;</span></span>
</code></pre><p>An input field's "for" attribute must be the same as its "id" attribute to bind them together, as shown above. This enables the screen reader to notify the user when they click on the associated name's text field. </p>
<h3 id="heading-use-aria-attributes">Use ARIA Attributes</h3>
<p>Accessible Rich Internet Applications (ARIA) is an extension to the HTML syntax that passes extra information to assistive technologies. You can use ARIA attributes to describe custom elements. </p>
<pre><code>&lt;button aria-label=<span class="hljs-string">"close"</span>  @click=<span class="hljs-string">"modalClose"</span> &gt; X &lt;/button&gt;
</code></pre><p>In the example above, the aria-label provides a description to help assistive technologies know the application will close when you click the X button. </p>
<h3 id="heading-use-keyboard-handlers">Use Keyboard Handlers</h3>
<p>For every mouse event handler, there should be a corresponding keyboard handler. This is important for users who would rather navigate through the platform with their keyboard. For example: </p>
<pre><code>&lt;button type=<span class="hljs-string">"submit"</span>  

            @keydown.enter=<span class="hljs-string">"displayMessage"</span> 

            @click.prevent=<span class="hljs-string">"displayMessage"</span> &gt; 

             Submit 
&lt;/button&gt;
</code></pre><p>You can do this by simply adding the “Vue-directive" keyup and the modifier ".enter" as demonstrated above. </p>
<h3 id="heading-manage-focus-and-make-elements-focus-able">Manage Focus and Make Elements Focus-able</h3>
<p>People who use screen readers also use the keyboard to access information. You need to make your application keyboard accessible by making elements focus-able. </p>
<p>Giving elements focus works in different ways, such as: </p>
<ul>
<li>Using Vue refs: 
To focus an element in Vue, we use the ref attribute, which enables you to directly access the underlying DOM nodes. </li>
</ul>
<pre><code>&lt;template&gt; 
          <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span> 
             <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">'projectList'</span>&gt;</span> Vue project   <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span> 
          <span class="hljs-tag">&lt;/<span class="hljs-name">ul</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"> 
    mounted() { 
       <span class="hljs-keyword">const</span> projectListRef = <span class="hljs-built_in">this</span>.$refs.projectList; 
        projectListRef.focus(); 
       } 

</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre><p>In the code snippet above, we are able to add focus to the list element once the component is mounted to the DOM. </p>
<ul>
<li>Using tabindex: 
You can also use tabindex to add focus to an element. To use tabindex: 
1) If given a value of 0, the element can be focused via the keyboard and falls into the tabbing flow of the page. </li>
</ul>
<p>2) If given a value of ""-1"", the element can't be tabbed. </p>
<p>3) Values greater than 1 create a priority level, with 1 being the most important.</p>
<pre><code>&lt;input type=<span class="hljs-string">'search"   id='</span>searchBar<span class="hljs-string">' tabindex="0"  /&gt;</span>
</code></pre><p>In web pages where there are multiple links, it's a good idea to add a skip to main content link. This saves the user's time and gives them the ability to focus on the main content. Skip links are usually hidden until they are focused. </p>
<p>Here is the code snippet to implement skip links in Vue: </p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/coded_fae/embed/MWppaBG" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h2 id="heading-the-vue-announcer-library">The Vue Announcer Library</h2>
<p>For large Vue applications consisting of various pages, the <a target="_blank" href="https://announcer.vue-a11y.com/"> vue announcer  Library</a> provides an easy way for people using screen readers to tell what's going on in your application. </p>
<p>To use the library: </p>
<pre><code><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> VueAnnouncer <span class="hljs-keyword">from</span> <span class="hljs-string">'@vue-a11y/announcer'</span> 

Vue.use(VueAnnouncer)
</code></pre><p>You can explore the <a target="_blank" href="https://announcer.vue-a11y.com/">official documentation guide.</a> to learn more.</p>
<hr>
<h2 id="heading-demo-vue-project">Demo Vue Project</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/07/lighthouse-accessibilty-report.png" alt="lighthouse-accessibilty-report" width="600" height="400" loading="lazy"></p>
<p>In this section, we'll build a single page app following all accessibility features and principles. Check out the <a target="_blank" href="https://accessibile-vue-app.netlify.app/">Demo</a> and code repository on <a target="_blank" href="https://github.com/Abiola-Farounbi/Accessibile-vue-app">Github</a>. </p>
<p>This application is simple. It is divided into different components and we will build each component following accessibility standards. </p>
<p>To build the application, follow these steps: </p>
<h3 id="heading-create-a-vue-project">Create a Vue project</h3>
<p>First, install the Vue command-line interface (CLI): </p>
<p><code>npm install -g @vue/cli</code></p>
<p>Then, create the Vue app using this command: </p>
<p><code>vue create accessibile-vue-app</code> </p>
<p>cd into accessible-vue-app, and run the command below to start the application: </p>
<p><code>npm run serve</code></p>
<h3 id="heading-how-to-create-the-different-components">How to Create the Different Components</h3>
<p>The page is divided into different components and rendered into the App.vue file.</p>
<ul>
<li><a target="_blank" href="https://github.com/Abiola-Farounbi/Accessible-vue-app/blob/master/src/components/Header.vue">Header Component</a></li>
<li><a target="_blank" href="https://github.com/Abiola-Farounbi/Accessible-vue-app/blob/master/src/components/welcomeCard.vue">welcomeCard Component</a></li>
<li><a target="_blank" href="https://github.com/Abiola-Farounbi/Accessible-vue-app/blob/master/src/components/Form.vue">Form Component</a></li>
<li><a target="_blank" href="https://github.com/Abiola-Farounbi/Accessible-vue-app/blob/master/src/components/Footer.vue">Footer Component</a></li>
</ul>
<p>For each component, semantic HTML defines the structure. Then we render them all in <code>App.vue</code> as one. </p>
<p>App.vue:</p>
<pre><code class="lang-<template>">  &lt;Header&gt;&lt;/Header&gt; 
  &lt;main&gt; 
&lt;section class='pageOptions'&gt; 
   &lt;button @click="selectedComponent = 'WelcomeCard'" &gt; Welcome Message &lt;/button&gt; 
  &lt;button @click="selectedComponent = 'Form'" &gt; Contact Form &lt;/button&gt;  
&lt;/section&gt; 
  &lt;!-- binding the current component to the property  --&gt; 
  &lt;component :is="selectedComponent"&gt;&lt;/component&gt; 
 &lt;/main&gt; 
  &lt;Footer&gt;&lt;/Footer&gt; 
&lt;/template&gt;
</code></pre>
<p>You can explore the demo on <a target="_blank" href="https://accessible-vue-app.netlify.app/">Netlify</a> here.</p>
<h2 id="heading-accessibility-tools-to-test-vue-applications">Accessibility Tools to Test Vue Applications</h2>
<p>There are lots of different tools you can use to test if your web content meets accessibility guidelines. </p>
<p>Here are some tools and websites you can use to check if a website is accessible: </p>
<ul>
<li>Lighthouse in Chrome dev tools </li>
<li><a target="_blank" href="https://wave.webaim.org/">Web Accessibility Evaluation Tool (WAVE)</a> </li>
<li>Screen Readers on <a target="_blank" href="https://chrome.google.com/webstore/detail/screen-reader/kgejglhpjiefppelpmljglcjbhoiplfn?hl=en">Chrome Vox</a> </li>
<li><a target="_blank" href="https://www.a11yproject.com/checklist/#global-code">Accessibilty Checklist</a> </li>
<li>Accessibility auditing for Vue.js applications on <a target="_blank" href="https://axe.vue-a11y.com/#links">Vue axe</a></li>
<li>Color Contrast Checker Tool on <a target="_blank" href="https://webaim.org/resources/contrastchecker/">WebAIM</a>.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we have learned about web accessibility, what it is, and why it is important to make our web pages accessible. </p>
<p>We also looked at different accessibility features to add to your Vue.js applications and learned how to implement them. </p>
<p>Using this information, you can successfully build a Vue application that everyone can use. </p>
<p>To learn more about how to make your Vue applications more accessible, explore the <a target="_blank" href="https://v3.vuejs.org/guide/a11y-standards.html">Vue.js website</a>. </p>
<p>You can also reach out to me on <a target="_blank" href="https://twitter.com/abiolaesther_?s=08">Twitter</a> for questions. Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add Authentication to a Vue App Using AWS Amplify ]]>
                </title>
                <description>
                    <![CDATA[ By Jennifer Bland In this article, we’re going to create a very simple Vue application using the Vue CLI. We’ll modify the default scaffolded application so it provides a form to register as a new user, a login page, and a dashboard page only shown t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-authentication-to-a-vue-app-using-aws-amplify/</link>
                <guid isPermaLink="false">66d460ced7a4e35e384349b5</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 14 Jan 2021 22:37:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/01/0_QrOUXeTdCaxjv6o_-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jennifer Bland</p>
<p>In this article, we’re going to create a very simple Vue application using the Vue CLI. We’ll modify the default scaffolded application so it provides a form to register as a new user, a login page, and a dashboard page only shown to people that are logged in.</p>
<p>Users will be able to register using an email and password. Once they’ve registered and logged in, they’ll be presented with the dashboard page.</p>
<h1 id="heading-how-to-create-our-project">How to Create Our Project</h1>
<p>I’ll be using the Vue CLI to scaffold out a project for us to start with. To do that, you need to have the Vue CLI installed on your system. If you don’t have it installed, you can install it globally with this command:</p>
<pre><code>npm install -g @vue/cli
</code></pre><p>Now we can use the Vue CLI to create our project. Create a new project using this command:</p>
<pre><code>vue create vue-amplify-auth-tutorial
</code></pre><p>You’ll be asked to pick a preset. Choose “Manually select features,” and then select “babel,” “Router,” and “Linter / Formatter.”</p>
<p>You’ll be asked if you want to use the history mode for the router. Choose “Yes” (should be the default).</p>
<p>For a linter, I’m selecting “ESLint with error prevention only.”</p>
<p>After the Vue CLI is finished, it’ll give you the commands to change into the new directory that was just created and the command to start the server. Follow those directions. </p>
<p>Once the server is started you can open your browser to <code>localhost:8080</code>. You should see this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_S9E-Jj_1zY76iZBj.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h1 id="heading-what-is-aws-amplify">What is AWS Amplify?</h1>
<p>AWS Amplify is an open-source framework created by Amazon that contains a set of tools and services that can be used together or on their own. </p>
<p>One of the tools is Amplify Auth. Amplify Auth lets you quickly set up secure authentication and control what users have access to in your application.</p>
<p>The Amplify framework uses Amazon Cognito as the main authentication provider. Amazon Cognito is a robust user-directory service that handles user registration, authentication, account recovery, and other operations.</p>
<h1 id="heading-create-an-aws-account">Create an AWS Account</h1>
<p>To get started, you’ll need to create an AWS account here. If you don’t have an AWS account, <a target="_blank" href="https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/">follow the directions here to create one</a>.</p>
<h1 id="heading-install-and-configure-the-amplify-cli">Install and Configure the Amplify CLI</h1>
<p>The Amplify CLI is a unified toolchain to create AWS cloud services for your app. You can install it globally with this command:</p>
<pre><code>npm install -g @aws-amplify/cli
</code></pre><p>Next, we need to configure Amplify by running the following command:</p>
<pre><code>amplify configure
</code></pre><p>This command will open up a new browser window and ask you to sign into the AWS console. Once you’re signed in, return to your terminal, and press <code>Enter</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_SBiQgDy2bw0OGeX3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You’ll be asked to specify the AWS Region. Select the region closest to you.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_Wx3wr2Ohnd7_2RAG.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You’ll need to specify the username of the new IAM user. It’ll provide a default name you can use by hitting enter or you can specify your own name. I’m going to call my user <code>auth-demo</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_z0qKKxKSjp_1K98H.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>When you hit <code>Enter</code>, you’ll be taken back to your browser.</p>
<p>Click the Next: Permissions button.</p>
<p>Click the Next: Tags button.</p>
<p>Click the Next: Review button.</p>
<p>Click the Create User button.</p>
<p>Now go back to your terminal and press <code>Enter</code> to continue.</p>
<p>Type in the <code>accessKeyId</code> of the user you just created, and press <code>Enter</code>.</p>
<p>Type in the <code>secretAcessKey</code> of the user you just created, and press <code>Enter</code>.</p>
<p>You’ll be asked to enter a profile name. I’ll accept the supplied value (the default) by just pressing <code>Enter</code>.</p>
<p>When everything is finished, you should get a message in your terminal that the new user was successfully set up.</p>
<h1 id="heading-initialize-a-new-back-end">Initialize a New Back End</h1>
<p>Now that we have a running Vue app, it’s time to set up Amplify so we can create the necessary back-end services needed to support the app. From the root of your Vue application, run:</p>
<pre><code>amplify init
</code></pre><h1 id="heading-create-the-authentication-service">Create the Authentication Service</h1>
<p>We need to add an authentication service to our Vue application. In the root directory of your Vue application, enter this command:</p>
<pre><code>amplify add auth
</code></pre><p>When you initialize Amplify, you’ll be prompted for some information about your application. Enter a project name.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_0Q7RiIPnBCAo90Kf.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Set the back-end environment name to be <code>dev</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_SMbI1iNM5XELFdfp.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Sometimes the CLI will prompt you to edit a file — it’ll use this editor to open those files. Select your preferred code-editor software.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_juPUaS2SIkR0UnxL.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Amplify will provide configuration files for your front-end application to connect to this back-end environment. Since Vue is based on JavaScript, we’ll select that here.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_enPauC_uAMYzoDFV.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We’re using Vue, so select that as our JavaScript framework.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_xOxbC5xEGdudv-ej.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The Vue CLI sets up the source files for your project under a <code>./src</code> folder. Select <code>src</code> for the Source Directory Path.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_iLN4pnHKGUGB3tCz.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>When your project is ready to be hosted, Vue will generate your website, ready for public use, into a folder called <code>dist</code>. This is the default, so you can just press <code>Enter</code> to continue.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_u1tw63qKuNAsPJ9B.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Amplify’s automated deployment needs to know what steps are needed to build your application for publishing. Here, we’ll set that to be the Vue CLI’s default build script.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_SqFEoy03S2eingpb.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If Amplify needs to run the application in development mode, it needs to know how to start the development server. Again, we’ll use the Vue CLI’s default scripts.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_WR5XjxUw9TmYlTUv.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Finally, Amplify needs an AWS account to connect to so we can begin creating the back-end services. This is the profile you created with the <code>amplify configure</code> command earlier. Select “yes” by typing <code>y</code> and pressing <code>Enter</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_oTD19eyWt9KdCb6J.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Proceed to select your profile from the list, and press <code>Enter</code>. Amplify will now begin deploying your back-end framework.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_fX2wHxziZZil6sJ3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>When you initialize a new Amplify project, a few things happen:</p>
<ul>
<li>It creates a top-level directory called <code>amplify</code> that stores your back-end definition. During the tutorial, you'll add capabilities such as authentication, the GraphQL API, storage, and the authorization rules for the API. As you add features, the <code>amplify</code> folder will grow with infrastructure-as-code templates that define your back-end stack. Infrastructure-as-code is a best-practice way to create a replicable back-end stack.</li>
<li>It creates a file called <code>aws-exports.js</code> in the <code>src</code> directory that holds all of the configuration for the services you create with Amplify. This is how the Amplify client is able to get the necessary information about your back-end services.</li>
<li>It modifies the <code>.gitignore</code> file, adding some generated files to the ignore list</li>
<li>A cloud project is created for you in the AWS Amplify Console that can be accessed by running <code>amplify console</code>. The console provides a list of back-end environments, deep links to provisioned resources per Amplify category, the status of recent deployments, and instructions on how to promote, clone, pull, and delete back-end resources</li>
</ul>
<p>To deploy the service, run the <code>push</code> command.</p>
<h1 id="heading-install-amplify-libraries">Install Amplify Libraries</h1>
<p>We need to install the Amplify dependencies in our Vue application. You can install them with this command:</p>
<pre><code>npm install aws-amplify
</code></pre><h1 id="heading-configure-our-application">Configure Our Application</h1>
<p>We need to add Amplify to our Vue application. Open up the <code>main.js</code> file, and add the following after the last import line:</p>
<pre><code><span class="hljs-keyword">import</span> Amplify <span class="hljs-keyword">from</span> <span class="hljs-string">'aws-amplify'</span>;
<span class="hljs-keyword">import</span> awsconfig <span class="hljs-keyword">from</span> <span class="hljs-string">'./aws-exports'</span>; 
Amplify.configure(awsconfig);
</code></pre><p>The above code successfully configures Amplify. As you add or remove categories and make updates to your back-end configuration using the Amplify CLI, the configuration in <code>aws-exports.js</code> will update automatically.</p>
<h1 id="heading-create-a-sign-up-page">Create a Sign-Up Page</h1>
<p>We need a page that’ll allow new users to register with our application. In the views folder, create a new file called <code>Register.vue</code>.</p>
<p>We need to add this new page to our routes and then display it in the navigation. Open up the <code>index.js</code> file in the <code>router</code> folder. Add this to the routes array.</p>
<pre><code>{
    <span class="hljs-attr">path</span>: <span class="hljs-string">'/register'</span>,
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Register'</span>,
    <span class="hljs-attr">component</span>: <span class="hljs-function">() =&gt;</span>
        <span class="hljs-keyword">import</span>(<span class="hljs-comment">/* webpackChunkName: "register" */</span> <span class="hljs-string">'../views/Register.vue'</span>),
},
</code></pre><p>Now add this to our navigation. Open up the <code>App.vue</code> file, and add an entry for <code>Register</code> in the nav. Your nav should look like this:</p>
<pre><code>&lt;div id=<span class="hljs-string">"nav"</span>&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/about"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/register"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><p>Go back to your <code>Register.vue</code> file. This page will have a form for a user to put their email and a password to register as a new user. Here’s the code you need to put in the template section:</p>
<pre><code>&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"container"</span>&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> @<span class="hljs-attr">submit.prevent</span>=<span class="hljs-string">"register"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Email address..."</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"password..."</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><p>If you look at our form, the two input fields and the button are right next to each other.</p>
<p>Want to add some spacing between the three fields? I could add CSS to this page, but it’d only apply to this page. We’re going to use this form again on the login page we’ll be creating next. </p>
<p>To get styles that work on both pages, let’s put the following CSS in the <code>App.vue</code> file. Open up the <code>App.vue</code> file, and add the following style:</p>
<pre><code>:input {   
  margin-right: <span class="hljs-number">10</span>px; 
}
</code></pre><p>Go back to the <code>Register.vue</code> file. We’re capturing the values the user enters for their email and password, so we need to add them to the data object. Add them to the data object so it looks like this:</p>
<pre><code>data() { 
  <span class="hljs-keyword">return</span> { 
    <span class="hljs-attr">email</span>: <span class="hljs-string">''</span>, 
    <span class="hljs-attr">password</span>: <span class="hljs-string">''</span>, 
  }; 
},
</code></pre><p>When a user submits the form it calls the <code>register</code> method. Here’s the code for that method:</p>
<pre><code><span class="hljs-keyword">async</span> register() {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">await</span> Auth.signUp({
            <span class="hljs-attr">username</span>: <span class="hljs-built_in">this</span>.email,
            <span class="hljs-attr">password</span>: <span class="hljs-built_in">this</span>.password,
        });
        alert(<span class="hljs-string">'User successfully registered. Please login'</span>);
    } <span class="hljs-keyword">catch</span> (error) {
        alert(error.message);
    }
},
</code></pre><p>This method uses <code>Auth</code> from the <code>aws-amplify</code> package we installed. Add this import for it at the beginning of the script section.</p>
<pre><code><span class="hljs-keyword">import</span> { Auth } <span class="hljs-keyword">from</span> <span class="hljs-string">'aws-amplify'</span>;
</code></pre><p>Now open up your application, and register a new user. If successful, you’ll get an alert saying the user was registered.</p>
<h1 id="heading-create-a-login-page">Create a Login Page</h1>
<p>Once a user has registered an account with our application, they need a page through which they can log in. In the <code>views</code> folder, create a new file called <code>Login.vue</code>.</p>
<p>We need to add this new page to our routes and then display it in the navigation. Open up the <code>index.js</code> file in the <code>router</code> folder. Add this to the routes array.</p>
<pre><code>{
    <span class="hljs-attr">path</span>: <span class="hljs-string">'/login'</span>,
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Login'</span>,
    <span class="hljs-attr">component</span>: <span class="hljs-function">() =&gt;</span>
        <span class="hljs-keyword">import</span>(<span class="hljs-comment">/* webpackChunkName: "login" */</span> <span class="hljs-string">'../views/Login.vue'</span>),
},
</code></pre><p>Now add this to our navigation. Open up the <code>App.vue</code> file, and add an entry for <code>Register</code> in the nav. Your nav should look like this:</p>
<pre><code>&lt;div id=<span class="hljs-string">"nav"</span>&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/about"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/register"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/login"</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> 
&lt;/div&gt;
</code></pre><p>Go back to your <code>Login.vue</code> file. You can copy the HTML code in the template section of the <code>Register.vue</code> file and paste it into this new file. Change all references of <code>Register</code> to <code>Login</code>. Your template section should look like this:</p>
<pre><code>&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"container"</span>&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> @<span class="hljs-attr">submit.prevent</span>=<span class="hljs-string">"login"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Email address..."</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"password..."</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><p>In the script section, add the import for <code>Auth</code> and the data object for the email and password. Your script section should look like this:</p>
<pre><code>&lt;script&gt;
<span class="hljs-keyword">import</span> { Auth } <span class="hljs-keyword">from</span> <span class="hljs-string">'aws-amplify'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Login'</span>,
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">email</span>: <span class="hljs-string">''</span>,
      <span class="hljs-attr">password</span>: <span class="hljs-string">''</span>
    }
  },
}
&lt;/script&gt;
</code></pre><p>The last thing we need to implement is the login method. Here’s the code:</p>
<pre><code><span class="hljs-keyword">async</span> login() {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">await</span> Auth.signIn(<span class="hljs-built_in">this</span>.email, <span class="hljs-built_in">this</span>.password);
        alert(<span class="hljs-string">'Successfully logged in'</span>);
    } <span class="hljs-keyword">catch</span> (error) {
        alert(error.message);
    }
},
</code></pre><p>Now if you open up your application, you’ll be able to log in with the user you previously registered.</p>
<h1 id="heading-add-a-logout-method">Add a Logout Method</h1>
<p>We need to add a button so users can log out of our application. Open up the <code>App.vue</code> file. Add a button to log out in the nav. Your nav should look like this:</p>
<pre><code>&lt;div id=<span class="hljs-string">"nav"</span>&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/about"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/register"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/login"</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</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">button</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><p>In the script section, add a <code>methods</code> object, and include the <code>logout</code> method. It should look like this:</p>
<pre><code>methods: {
    <span class="hljs-keyword">async</span> logout() {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">await</span> Auth.signOut();
        } <span class="hljs-keyword">catch</span> (error) {
            alert(error.message);
        }
    },
},
</code></pre><p>Congratulations, you’ve successfully added AWS Amplify authentication to your Vue application.</p>
<h1 id="heading-get-the-code">Get the Code</h1>
<p>I have the <a target="_blank" href="https://github.com/ratracegrad/Vue-Amplify-Auth-Tutorial">complete code on my GitHub account here</a>.</p>
<h1 id="heading-using-other-authentication-methods">Using Other Authentication Methods</h1>
<p>I’ve written several follow up articles on adding authentication to your Vue application using other authentication methods.</p>
<ul>
<li><a target="_blank" href="https://www.jenniferbland.com/how-to-add-authentication-to-a-vue-app-using-firebase/">Using Firebase for authentication</a></li>
<li><a target="_blank" href="https://www.jenniferbland.com/how-to-add-authentication-to-a-vue-app-using-auth0/">Using Auth0 for authentication</a></li>
</ul>
<h1 id="heading-conclusion">Conclusion</h1>
<p>AWS Amplify is a a great tool allowing you to add authentication to your application.</p>
<p>Hope you enjoyed this article. Thanks for reading.</p>
<p><em>Originally published at</em> <a target="_blank" href="https://www.jenniferbland.com/how-to-add-authentication-to-a-vue-app-using-auth0/"><em>https://www.jenniferbland.com</em></a> <em>on December 31, 2020.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add Authentication to a Vue App Using Auth0 ]]>
                </title>
                <description>
                    <![CDATA[ By Jennifer Bland Auth0 is a flexible, drop-in solution to add authentication and authorization services to your applications. See how easy it is to add to your Vue application so you can register and login users with their email address and a passwo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-authentication-to-a-vue-app-using-auth0/</link>
                <guid isPermaLink="false">66d460cca326133d12440a67</guid>
                
                    <category>
                        <![CDATA[ Auth0 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 12 Jan 2021 20:11:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/01/0_j4pVnDlQTDvfWtw_-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jennifer Bland</p>
<p>Auth0 is a flexible, drop-in solution to add authentication and authorization services to your applications. See how easy it is to add to your Vue application so you can register and login users with their email address and a password.</p>
<h1 id="heading-what-we-will-be-creating">What we will be creating</h1>
<p>We are going to create a very simple Vue application using the Vue CLI. We will modify the default scaffolded application so that we can use Auth0 to either register a new user or login an existing user. Once a user is logged in then they will have access to view the <strong>About</strong> page.</p>
<p>User’s will be able to register with the application using the email and password authentication system in Auth0.</p>
<h1 id="heading-creating-our-project">Creating our Project</h1>
<p>I will be using the Vue CLI to scaffold out a project for us to start with. To do that you need to have the Vue CLI installed on your system. If you <strong>DO NOT</strong> have it installed, you can install it globally with this command:</p>
<pre><code>npm install -g @vue/cli
</code></pre><p>Now we can use the Vue CLI to create our project. Create a new project using this command:</p>
<pre><code>vue create vue-authentication-auth0
</code></pre><p>You will be asked to pick a preset. Choose “Manually select features” and then select “babel”, “Router” and “Linter / Formatter”.</p>
<p>You will be asked if you want to use history mode for router. Choose “Yes” (should be the default).</p>
<p>You can select any linter you want but for this tutorial I will be selecting “Eslint + Prettier”.</p>
<p>After the Vue CLI is finished, it will give you the commands to change into the new directory that was just created and the command to start the server. Follow those directions. Once the server is started you can open your browser to <code>localhost:8080</code>. You should see this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_aULwhJQrKCD0RZ8t.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h1 id="heading-how-to-set-up-an-auth0-account">How to Set Up An Auth0 Account</h1>
<p>The first thing you will need to do is to create an account with Auth0 if you don’t already have one. It is free to create an account. You can <a target="_blank" href="https://auth0.com/signup">create your free account here</a>.</p>
<h1 id="heading-how-to-create-our-auth0-application">How to Create our Auth0 Application</h1>
<p>Once you have created your free Auth0 account, login to your account. In the left-hand navigation, click on Applications.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_dx-jheyJRHChE5ET.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>From here click on the Create Application button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_zXLpqqkLENVyAASt.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You will be presented with a dialog box for you to provide a name for your application and to specify what type of application you will be creating.</p>
<p>The name of my application is <strong>Vue Authentication Auth0</strong>. You can put whatever you want for the name of your application.</p>
<p>For the application type, select <strong>Single Page Web Application</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_44vQOJ9golspep06.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After your application is created, the Quick Start tab will provide instructions on how to implement Auth0 in your web App using the most popular JavaScript frameworks.</p>
<p>Since we are using Vue.js for our application click on the Vue icon.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_jGC1dkmWfYbUhXQL.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Auth0 provides very detailed instructions on how to implement their Authentication-As-A-Service product. For this tutorial we will implement their instructions in the Vue app that we have already created.</p>
<h1 id="heading-how-to-configure-your-application-settings">How to Configure Your Application Settings</h1>
<p>You can access your settings by clicking on the Settings tab at the top of the page.</p>
<p>You will see your Domain and Client ID under Basic Information. We will come back to this later on because we will need to store these values for our application to work.</p>
<p>Under the Application URIs section we will need to define our <strong>Allowed Callback URLs</strong>, <strong>Allowed Logout URLs</strong>, and <strong>Allowed Web Origins</strong>.</p>
<p>For testing our application locally we will be using the URL of <strong>http://localhost:8080</strong>.</p>
<p><strong>NOTE:</strong> if you decide to host your application somewhere like on Netlify or Heroku then you will need to update all of these settings with the URL of your hosted application.</p>
<p>Set your strong&gt;Allowed Callback URLs, <strong>Allowed Logout URLs</strong>, and <strong>Allowed Web Origins</strong> to be <strong>http://localhost:8080</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_nX1DoL-RXVC1x4oD.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h1 id="heading-how-to-install-the-auth0-sdk">How to Install the Auth0 SDK</h1>
<p>Go back to your Vue application and add the Auth0 Client SDK with this command:</p>
<pre><code>npm install @auth0/auth0-spa-js
</code></pre><h1 id="heading-how-to-create-an-authentication-wrapper">How to Create an Authentication Wrapper</h1>
<p>The Auth0 SDK requires that it be initialized before your Vue application has started. </p>
<p>Vue has lifecycle hooks that we could potentially use to initialize the SDK. You might think we could use a <strong>beforeCreate</strong> hook in the <strong>App.vue</strong> file but that won't work. Let me show you why.</p>
<p>Here is an image of the Vue lifecycle hooks.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_NuSvkkm1kohKVJbt.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>beforeCreate</strong> is the very first Vue lifecycle hook to fire. But notice in that image that it fires after the Vue application is created with <strong>new Vue()</strong>.</p>
<p>We need to be able to initialize the Auth0 SDK before the <strong>new Vue()</strong> that creates our Vue application. Vue provides a mechanism to do this with the Vue plugin.</p>
<p>In order to use a plugin you must call it with the <strong>Vue.use()</strong> command. This command must be done before your start your app by calling <strong>new Vue()</strong>.</p>
<p>The Authentication Wrapper we will be creating will actually be a Vue plugin.</p>
<p>In the <strong>src</strong> directory create a new directory called <strong>auth</strong>. Inside that auth directory create a file called <strong>index.js</strong>.</p>
<p>We will copy the code provided from the QuickStart tab and paste it into this file. Here is the code:</p>
<pre><code><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> createAuth0Client <span class="hljs-keyword">from</span> <span class="hljs-string">"@auth0/auth0-spa-js"</span>;
<span class="hljs-comment">/** Define a default action to perform after authentication */</span>
<span class="hljs-keyword">const</span> DEFAULT_REDIRECT_CALLBACK = <span class="hljs-function">() =&gt;</span>
  <span class="hljs-built_in">window</span>.history.replaceState({}, <span class="hljs-built_in">document</span>.title, <span class="hljs-built_in">window</span>.location.pathname);
<span class="hljs-keyword">let</span> instance;
<span class="hljs-comment">/** Returns the current instance of the SDK */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getInstance = <span class="hljs-function">() =&gt;</span> instance;
<span class="hljs-comment">/** Creates an instance of the Auth0 SDK. If one has already been created, it returns that instance */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useAuth0 = <span class="hljs-function">(<span class="hljs-params">{
  onRedirectCallback = DEFAULT_REDIRECT_CALLBACK,
  redirectUri = <span class="hljs-built_in">window</span>.location.origin,
  ...options
}</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (instance) <span class="hljs-keyword">return</span> instance;
<span class="hljs-comment">// The 'instance' is simply a Vue object</span>
  instance = <span class="hljs-keyword">new</span> Vue({
    data() {
      <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">loading</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">isAuthenticated</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">user</span>: {},
        <span class="hljs-attr">auth0Client</span>: <span class="hljs-literal">null</span>,
        <span class="hljs-attr">popupOpen</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">error</span>: <span class="hljs-literal">null</span>
      };
    },
    <span class="hljs-attr">methods</span>: {
      <span class="hljs-comment">/** Authenticates the user using a popup window */</span>
      <span class="hljs-keyword">async</span> loginWithPopup(options, config) {
        <span class="hljs-built_in">this</span>.popupOpen = <span class="hljs-literal">true</span>;
<span class="hljs-keyword">try</span> {
          <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.auth0Client.loginWithPopup(options, config);
        } <span class="hljs-keyword">catch</span> (e) {
          <span class="hljs-comment">// eslint-disable-next-line</span>
          <span class="hljs-built_in">console</span>.error(e);
        } <span class="hljs-keyword">finally</span> {
          <span class="hljs-built_in">this</span>.popupOpen = <span class="hljs-literal">false</span>;
        }
<span class="hljs-built_in">this</span>.user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.auth0Client.getUser();
        <span class="hljs-built_in">this</span>.isAuthenticated = <span class="hljs-literal">true</span>;
      },
      <span class="hljs-comment">/** Handles the callback when logging in using a redirect */</span>
      <span class="hljs-keyword">async</span> handleRedirectCallback() {
        <span class="hljs-built_in">this</span>.loading = <span class="hljs-literal">true</span>;
        <span class="hljs-keyword">try</span> {
          <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.auth0Client.handleRedirectCallback();
          <span class="hljs-built_in">this</span>.user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.auth0Client.getUser();
          <span class="hljs-built_in">this</span>.isAuthenticated = <span class="hljs-literal">true</span>;
        } <span class="hljs-keyword">catch</span> (e) {
          <span class="hljs-built_in">this</span>.error = e;
        } <span class="hljs-keyword">finally</span> {
          <span class="hljs-built_in">this</span>.loading = <span class="hljs-literal">false</span>;
        }
      },
      <span class="hljs-comment">/** Authenticates the user using the redirect method */</span>
      loginWithRedirect(o) {
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.auth0Client.loginWithRedirect(o);
      },
      <span class="hljs-comment">/** Returns all the claims present in the ID token */</span>
      getIdTokenClaims(o) {
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.auth0Client.getIdTokenClaims(o);
      },
      <span class="hljs-comment">/** Returns the access token. If the token is invalid or missing, a new one is retrieved */</span>
      getTokenSilently(o) {
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.auth0Client.getTokenSilently(o);
      },
      <span class="hljs-comment">/** Gets the access token using a popup window */</span>
getTokenWithPopup(o) {
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.auth0Client.getTokenWithPopup(o);
      },
      <span class="hljs-comment">/** Logs the user out and removes their session on the authorization server */</span>
      logout(o) {
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.auth0Client.logout(o);
      }
    },
    <span class="hljs-comment">/** Use this lifecycle method to instantiate the SDK client */</span>
    <span class="hljs-keyword">async</span> created() {
      <span class="hljs-comment">// Create a new instance of the SDK client using members of the given options object</span>
      <span class="hljs-built_in">this</span>.auth0Client = <span class="hljs-keyword">await</span> createAuth0Client({
        ...options,
        <span class="hljs-attr">client_id</span>: options.clientId,
        <span class="hljs-attr">redirect_uri</span>: redirectUri
      });
<span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// If the user is returning to the app after authentication..</span>
        <span class="hljs-keyword">if</span> (
          <span class="hljs-built_in">window</span>.location.search.includes(<span class="hljs-string">"code="</span>) &amp;&amp;
          <span class="hljs-built_in">window</span>.location.search.includes(<span class="hljs-string">"state="</span>)
        ) {
          <span class="hljs-comment">// handle the redirect and retrieve tokens</span>
          <span class="hljs-keyword">const</span> { appState } = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.auth0Client.handleRedirectCallback();
<span class="hljs-comment">// Notify subscribers that the redirect callback has happened, passing the appState</span>
          <span class="hljs-comment">// (useful for retrieving any pre-authentication state)</span>
          onRedirectCallback(appState);
        }
      } <span class="hljs-keyword">catch</span> (e) {
        <span class="hljs-built_in">this</span>.error = e;
      } <span class="hljs-keyword">finally</span> {
        <span class="hljs-comment">// Initialize our internal authentication state</span>
        <span class="hljs-built_in">this</span>.isAuthenticated = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.auth0Client.isAuthenticated();
        <span class="hljs-built_in">this</span>.user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.auth0Client.getUser();
        <span class="hljs-built_in">this</span>.loading = <span class="hljs-literal">false</span>;
      }
    }
  });
<span class="hljs-keyword">return</span> instance;
};
<span class="hljs-comment">// Create a simple Vue plugin to expose the wrapper object throughout the application</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Auth0Plugin = {
  install(Vue, options) {
    Vue.prototype.$auth = useAuth0(options);
  }
};
</code></pre><h1 id="heading-how-to-create-a-config-file">How to Create a Config File</h1>
<p>The options object passed to the plugin is used to provide the values for <strong>clientId</strong> and <strong>domain</strong> which I mentioned earlier and said we would get to later.</p>
<p>In the root directory of your application create a new file called <strong>auth_config.json</strong>. We will populate the values from your application for <strong>domain</strong> and <strong>clientId</strong>. Put this code into auth_config.json file and be sure to update it with the values for your application.</p>
<pre><code>{   
  <span class="hljs-string">"domain"</span>: <span class="hljs-string">"yourAppValuesHere"</span>,   
  <span class="hljs-string">"clientId"</span>: <span class="hljs-string">"yourAppValuesHere"</span>
}
</code></pre><p>This configuration file contains non-sensitive values relating to your Auth0 application. This file should not be committed into source control. We can do that by adding the filename to the <strong>.gitignore</strong> file.</p>
<p>Open the <strong>.gitignore</strong> file and add <code>auth_config.json</code> in the file.</p>
<h1 id="heading-how-to-add-the-plugin-to-our-vue-application">How to Add the Plugin to Our Vue Application</h1>
<p>Now that we have created our plugin we need to tell Vue to use it. Open up the <strong>main.js</strong> file. Add these two import statements which import our plugin as well as our domain and clientId from the <strong>auth_config.json</strong> file.</p>
<pre><code><span class="hljs-comment">// Import the Auth0 configuration</span>
<span class="hljs-keyword">import</span> { domain, clientId } <span class="hljs-keyword">from</span> <span class="hljs-string">"../auth_config.json"</span>;
<span class="hljs-comment">// Import the plugin here</span>
<span class="hljs-keyword">import</span> { Auth0Plugin } <span class="hljs-keyword">from</span> <span class="hljs-string">"./auth"</span>;
</code></pre><p>Next we need to tell Vue to use our plugin. After the import statements add this code:</p>
<pre><code><span class="hljs-comment">// Install the authentication plugin here</span>
Vue.use(Auth0Plugin, {
  domain,
  clientId,
  <span class="hljs-attr">onRedirectCallback</span>: <span class="hljs-function"><span class="hljs-params">appState</span> =&gt;</span> {
    router.push(
      appState &amp;&amp; appState.targetUrl
        ? appState.targetUrl
        : <span class="hljs-built_in">window</span>.location.pathname
    );
  }
});
</code></pre><h1 id="heading-how-to-login-to-the-app">How to Login to the App</h1>
<p>If you look at the plugin code in the <strong>auth/index.js</strong> file you will notice that there are two different login methods provided: <strong>loginWithPopup</strong> and <strong>loginWithRedirect</strong>.</p>
<p>Auth0 provides a hosted login page that any application can use to login or register users for their application. </p>
<p>The <strong>loginWithRedirect</strong> method will access the hosted login page. That means that when users click the login button the URL will change to point to the Auth0 website where the user will enter their login details. After they have successfully authenticated they will be redirected back to our application.</p>
<p>If we don’t want to do this redirect, Auth0 provides the option to login or register users via a popup that shows on our website.</p>
<p>I will show you how to use both of these login methods.</p>
<p>Open up the <strong>App.vue file</strong>. The nav currently has two entries for the Home and About pages. We need to add two buttons to Login. Add this code in the nav which should look like this:</p>
<pre><code>&lt;div id=<span class="hljs-string">"nav"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Home <span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span>|
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/about"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!$auth.loading"</span>&gt;</span>
    |
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"login"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!$auth.isAuthenticated"</span>&gt;</span>
      Login
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    |
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"loginPopup"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!$auth.isAuthenticated"</span>&gt;</span>
      Login Popup
    <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;/div&gt;
</code></pre><p>Notice that the buttons are wrapped in a directive that makes sure <strong>$auth.loading</strong> is false. If you review the code for our plugin there is a data section with a value of <strong>isAuthenticated</strong>. This value is set if a user successfully authenticates with Auth0. If the user is authenticated then we do not want to show the two login buttons.</p>
<p>When we add the div then the buttons appear on the row below the links for the Home and About button. I want them to all be on the same line so I update the CSS styles to be this:</p>
<pre><code>#nav { 
  <span class="hljs-attr">display</span>: flex; 
  justify-content: center; 
  padding: <span class="hljs-number">30</span>px; 
} 
#nav a { 
  font-weight: bold; 
  color: #<span class="hljs-number">2</span>c3e50; 
  padding: <span class="hljs-number">0</span> <span class="hljs-number">5</span>px; 
}
</code></pre><p>Now when you view the application you will see the two buttons.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_LyHE1bybFhyso-Db.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The two buttons are calling methods <strong>login</strong> and <strong>loginPopup</strong>. Let’s implement them now.</p>
<p>Add a methods object with two methods. Here is the code:</p>
<pre><code>methods: { 
  login() { 
    <span class="hljs-built_in">this</span>.$auth.loginWithRedirect(); 
  }, 
  loginPopup() { 
    <span class="hljs-built_in">this</span>.$auth.loginWithPopup(); 
  }, 
}
</code></pre><p>The <strong>this.$auth</strong> is a handle for our plugin. We are then calling the methods available in our plugin.</p>
<p>Now go back to your application. If you click the login button you should be taken to Auth0’s hosted login page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_BopphiRqeQ3ReXlI.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you click on the Login Popup button you will see a login modal in your application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_e40CPdd19xjobDw-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Regardless of which one you choose, you will see that you have the option to either log in or sign up. Go ahead and create an account. When you return to the application you will see that both the login buttons are hidden. They are hidden because the <strong>isAuthenticated</strong> value in the plugin is now true.</p>
<h1 id="heading-how-to-implement-logout">How to Implement Logout</h1>
<p>The next step is to implement a Logout. Open up the <strong>App.vue</strong> file. Add a button for logout like this:</p>
<pre><code>&lt;button @click=<span class="hljs-string">"logout"</span> v-<span class="hljs-keyword">if</span>=<span class="hljs-string">"$auth.isAuthenticated"</span>&gt;
  Logout
&lt;/button&gt;
</code></pre><p>Here we have a directive to only show this button if the user is currently authenticated. Go back to your application and you should now see the Logout button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_qp0QOUNUP-wz3iUn--1-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Add this method to implement the logout functionality:</p>
<pre><code>logout() { 
  <span class="hljs-built_in">this</span>.$auth.logout(); 
  <span class="hljs-built_in">this</span>.$router.push({ <span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span> }); 
}
</code></pre><p>In this method we call the logout function in our plugin. In case the user was on a page that is only visible to users that are authenticated, we redirect the user to the home page.</p>
<h1 id="heading-how-to-only-show-pages-to-authenticated-users">How to Only Show Pages to Authenticated Users</h1>
<p>Currently our application on has a Home page and an About page. Instead of creating a new page, let’s set the About page to be only visible if a user is logged in.</p>
<p>We only want to show the About page in the nav if the user is logged in. We will take the same directive we use for displaying the Logout button and put it on the About page in the nav. Update the nav to be this:</p>
<pre><code>&lt;router-link v-<span class="hljs-keyword">if</span>=<span class="hljs-string">"$auth.isAuthenticated"</span> to=<span class="hljs-string">"/about"</span>&gt;About&lt;/router-link&gt;
</code></pre><h1 id="heading-how-to-add-a-route-guard">How to Add a Route Guard</h1>
<p>We have hidden the link to the About page in the nav if a user is not currently authenticated. But a user can type in the url <strong>/about</strong> to go directly to the page. This shows that an unauthenticated user can access that page. You can avoid this by using a route guard.</p>
<p>In the auth directory create a new file called <strong>authGuard.js</strong>.</p>
<p>Add this code to the file:</p>
<pre><code><span class="hljs-keyword">import</span> { getInstance } <span class="hljs-keyword">from</span> <span class="hljs-string">"./index"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> authGuard = <span class="hljs-function">(<span class="hljs-params">to, <span class="hljs-keyword">from</span>, next</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> authService = getInstance();
<span class="hljs-keyword">const</span> fn = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// If the user is authenticated, continue with the route</span>
    <span class="hljs-keyword">if</span> (authService.isAuthenticated) {
      <span class="hljs-keyword">return</span> next();
    }
<span class="hljs-comment">// Otherwise, log in</span>
    authService.loginWithRedirect({ <span class="hljs-attr">appState</span>: { <span class="hljs-attr">targetUrl</span>: to.fullPath } });
  };
<span class="hljs-comment">// If loading has already finished, check our auth state using `fn()`</span>
  <span class="hljs-keyword">if</span> (!authService.loading) {
    <span class="hljs-keyword">return</span> fn();
  }
<span class="hljs-comment">// Watch for the loading property to change before we check isAuthenticated</span>
  authService.$watch(<span class="hljs-string">"loading"</span>, <span class="hljs-function"><span class="hljs-params">loading</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (loading === <span class="hljs-literal">false</span>) {
      <span class="hljs-keyword">return</span> fn();
    }
  });
};
</code></pre><p>This code checks to see if the user is currently authenticated. If they are not it brings up the Auth0 hosted login page for the user to login. If the user fails to login or is not able to successfully login, then it redirects the user away from the page they were trying to access that has the route guard.</p>
<p>Now let’s implement this route guard in our Vue router. Open up the <strong>index.js</strong> file in the router directory.</p>
<p>At the top of the file add an import for the authGuard file we just created:</p>
<pre><code><span class="hljs-keyword">import</span> { authGuard } <span class="hljs-keyword">from</span> <span class="hljs-string">"../auth/authGuard"</span>;
</code></pre><p>Next we need to add the route guard to the /about route. Update the /about route to be 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>: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-comment">/* webpackChunkName: "about" */</span> <span class="hljs-string">'../views/About.vue'</span>), 
  <span class="hljs-attr">beforeEnter</span>: authGuard 
}
</code></pre><p>Go back to your application. If you are not currently authenticated then login to your application. You should see the About entry in the Nav. Now logout of the application. Manually try to go the url <strong>/about</strong>. You should be redirected to the Auth0 hosted login page.</p>
<p>Congratulations! You have successfully added Auth0 authentication to your Vue application.</p>
<h1 id="heading-get-the-code">Get The Code</h1>
<p>I have the <a target="_blank" href="https://github.com/ratracegrad/Vue-Auth0-Authentication-Tutorial">complete code in my GitHub account here</a>. If you get the code please do me a favor and star my repo. Thank you!</p>
<h1 id="heading-using-other-authentication-methods">Using Other Authentication Methods</h1>
<p>I have written several follow up articles on adding Authentication to your Vue application using other authentication methods.</p>
<p>Want to use Firebase for authentication, <a target="_blank" href="https://www.freecodecamp.org/news/how-to-add-authentication-to-a-vue-app-using-firebase/">read this article</a>.</p>
<p>Want to use AWS Amplify for authentication, <a target="_blank" href="https://www.freecodecamp.org/news/how-to-add-authentication-to-a-vue-app-using-aws-amplify/">read this article</a>.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Auth0 is an Authentication-As-A-Service product that you can add to your application. It provides very easy to use Authentication.</p>
<p>Hope you enjoyed this article. If you like it please share it. Thanks for reading. And you can read more of my tutorials on <a target="_blank" href="https://www.jenniferbland.com/">my personal website</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add Authentication to a Vue App Using Firebase ]]>
                </title>
                <description>
                    <![CDATA[ By Jennifer Bland Firebase provides a very simple and quick way to add authentication to your Vue.js application. In this article I will show you how easy it is to allow users to register with your application using their email and password. What we ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-authentication-to-a-vue-app-using-firebase/</link>
                <guid isPermaLink="false">66d460d0787a2a3b05af43fa</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vue ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 11 Jan 2021 15:36:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/01/0_zPahR_9e795a1Vpp-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jennifer Bland</p>
<p>Firebase provides a very simple and quick way to add authentication to your Vue.js application. In this article I will show you how easy it is to allow users to register with your application using their email and password.</p>
<h1 id="heading-what-we-will-be-creating">What we will be creating</h1>
<p>We are going to create a very simple Vue application using the Vue CLI. We will modify the default scaffolded application so that it provides a form to register as a new user, a login page, and a dashboard page only shown to people that are logged in.</p>
<p>User’s will be able to register with the application using the email and password authentication system in Firebase. Once they have registered and logged in they will be presented with the dashboard page.</p>
<h1 id="heading-how-to-create-our-project">How to Create our Project</h1>
<p>I will be using the Vue CLI to scaffold out a project for us to start with. To do that you need to have the Vue CLI installed on your system. If you <strong>DO NOT</strong> have it installed, you can install it globally with this command:</p>
<pre><code>npm install -g @vue/cli
</code></pre><p>Now we can use the Vue CLI to create our project. Create a new project using this command:</p>
<pre><code>vue create vue-firebase-auth-tutorial
</code></pre><p>You will be asked to pick a preset. Choose “Manually select features” and then select “babel”, “Router” and “Linter / Formatter”.</p>
<p>You will be asked if you want to use history mode for router. Choose “Yes” (should be the default).</p>
<p>You can select any linter you want but for this tutorial I will be selecting “Eslint + Prettier”.</p>
<p>After the Vue CLI is finished, it will give you the commands to change into the new directory that was just created and the command to start the server. Follow those directions. </p>
<p>Once the server is started you can open your browser to <code>localhost:8080</code>. You should see this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/vueapp.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h1 id="heading-firebase">Firebase</h1>
<p>For this tutorial I am assuming you have already created an account with Firebase. If not, you need to do that before continuing.</p>
<p>We will be using the Firebase SDK in our application to provide the authentication functionality. You can install Firebase in your application using this command:</p>
<pre><code>npm install firebase
</code></pre><h1 id="heading-how-to-create-the-project-in-firebase">How to Create the Project in Firebase</h1>
<p>The next step is to add a project in your Firebase console. Login in to your Firebase console. Click the button to add a new project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/addProject.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you want to add Google Analytics to your project you can, but I will not add it for this tutorial. Click the “Create Project” button.</p>
<p>Once Firebase has created your new project, you will need to add Firebase to your app. Click on the web icon.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/addFirebase.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You will be asked to enter a nickname for your app. I have entered a nickname of “Vue Firebase Auth Tutorial”. After entering your nickname, click the “Register app” button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/registerApp.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>For Step 2, it will provide you instructions on adding the Firebase SDK to your application. We only need to copy the firebaseConfig and the line to initialize the app.</p>
<p>Open up your <strong>main.js</strong> file. We will initialize Firebase in our Vue application. Below the existing import lines, paste in the firebaseConfig and the line to initialize the app. You will need to add an import for Firebase. Your <strong>main.js</strong> file should look like this:</p>
<pre><code><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> 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> firebase <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase"</span>;

<span class="hljs-keyword">var</span> firebaseConfig = {
  <span class="hljs-attr">apiKey</span>: <span class="hljs-string">"YourConfigHere"</span>,
  <span class="hljs-attr">authDomain</span>: <span class="hljs-string">"YourConfigHere"</span>,
  <span class="hljs-attr">projectId</span>: <span class="hljs-string">"YourConfigHere"</span>,
  <span class="hljs-attr">storageBucket</span>: <span class="hljs-string">"YourConfigHere"</span>,
  <span class="hljs-attr">messagingSenderId</span>: <span class="hljs-string">"YourConfigHere"</span>,
  <span class="hljs-attr">appId</span>: <span class="hljs-string">"YourConfigHere"</span>
};
<span class="hljs-comment">// Initialize Firebase</span>
firebase.initializeApp(firebaseConfig);

Vue.config.productionTip = <span class="hljs-literal">false</span>;

<span class="hljs-keyword">new</span> Vue({
  router,
  <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><h1 id="heading-how-to-set-the-authentication-method">How to Set the Authentication Method</h1>
<p>Open your Firebase console in your browser. From the console, find the project that you just created and click on it.</p>
<p>In the top of the left side navigation click on Authentication.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_kYC_j73ZH7guuLxQ.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click the “Get Started” button.</p>
<p>From the Authentication menu, click on the “Sign-in method” tab.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_eFqUqK5d8_jt6O_v.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Hover over the first entry “Email/Password”. Click on the pencil icon to open up a dialog. Select enable.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_3z3Aj1_Sut_C5WHg.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click the “Save” button. You have now added the ability to create and authenticate users using their email address and a password.</p>
<h1 id="heading-how-to-add-new-components">How to Add New Components</h1>
<p>When we created our application with Vue Router, it automatically created two routes for our application — <strong>Home</strong> and <strong>About</strong>. We will use <strong>Home</strong> as the login for our application. We will use the <strong>About</strong> as the page to register as a new user for our application.</p>
<p>When a registered user logs in to our application we want to show them the dashboard page. We also want to provide a way for a user to log out of our application. Currently neither of these options are available in our application so let’s add them now.</p>
<p>Open up the <strong>App.vue</strong> file. Currently the nav has two entries for <strong>Home</strong> and <strong>About</strong>. We will change About to be register and add two new entries for <strong>Dashboard</strong> and <strong>Logout</strong>. Update your nav so it looks like this:</p>
<pre><code>&lt;div id=<span class="hljs-string">"nav"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/register"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">router-link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/dashboard"</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">router-link</span>&gt;</span></span> |
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</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">button</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><p>When you click the logout button it calls the logout method. We will be defining that later.</p>
<h1 id="heading-how-to-create-our-login-component">How to Create Our Login Component</h1>
<p>Open up the <strong>Home.vue</strong> file in the views folder. Delete all the HTML code in the template section. Replace it with this code that provides a very basic login form. Here is the code:</p>
<pre><code>&lt;div&gt;   
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> @<span class="hljs-attr">submit.prevent</span>=<span class="hljs-string">"login"</span>&gt;</span>     
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>     
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>       
      <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>       
      <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Email address..."</span>       
      <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span>     
    /&gt;</span>     
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>       
      <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>       
      <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"password..."</span>       
      <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span>     
    /&gt;</span>     
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>
       Login
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>   
  <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span> 
&lt;/div&gt;
</code></pre><p>Now if you view our application you will see the login form on the home page like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_WZxgr8K-wj5VSgpg.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Our form is a little bit crowded with the input fields and button touching each other. We can change this by adding some CSS styling. We can add the CSS styling in the <strong>Home.vue</strong> file. </p>
<p>Since we are going to use this same form for registering a user we would need to duplicate the same CSS styling in that component. So instead we can put styling in the <strong>App.vue</strong> file and it will style both our Login and Register forms.</p>
<p>Open the <strong>App.vue</strong> file. In the style add this:</p>
<pre><code>input {   
  margin-right: <span class="hljs-number">20</span>px; 
}
</code></pre><p>Now our login form looks better.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_bM6cZIRgjfNfrvqd.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h1 id="heading-how-to-create-our-register-form">How to Create Our Register Form</h1>
<p>Open up the <strong>About.vue</strong> file in the views folder. You can copy the HTML code from the <strong>Home.vue</strong> file and paste it into this file. Change every reference of <strong>Login</strong> to <strong>Register</strong>. Your <strong>About.vue</strong> file should look like this:</p>
<pre><code>&lt;div&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> @<span class="hljs-attr">submit.prevent</span>=<span class="hljs-string">"register"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
      <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Email address..."</span>
      <span class="hljs-attr">v-model</span>=<span class="hljs-string">"email"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
      <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"password..."</span>
      <span class="hljs-attr">v-model</span>=<span class="hljs-string">"password"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Register<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><h1 id="heading-how-to-update-our-routes">How to Update Our Routes</h1>
<p>Currently the URL to display our Register page is <strong>/about</strong>. Let’s change that to be <strong>/register</strong>. Open up the <strong>index.js</strong> file in the router folder. Change the second route for <strong>/about</strong> to be <strong>/register</strong>. Your routes array should look like this:</p>
<pre><code><span class="hljs-keyword">const</span> routes = [
    {
        <span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">'Home'</span>,
        <span class="hljs-attr">component</span>: Home,
    },
    {
        <span class="hljs-attr">path</span>: <span class="hljs-string">'/register'</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">'Register'</span>,
        <span class="hljs-attr">component</span>: <span class="hljs-function">() =&gt;</span>
            <span class="hljs-keyword">import</span>(<span class="hljs-comment">/* webpackChunkName: "about" */</span> <span class="hljs-string">'../views/About.vue'</span>),
    },
];
</code></pre><p>While we are in this file let’s go ahead and add an entry to display our dashboard component. Add a 3rd route to display <strong>/dashboard</strong>. Your routes array should now look like this:</p>
<pre><code><span class="hljs-keyword">const</span> routes = [
    {
        <span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">'Home'</span>,
        <span class="hljs-attr">component</span>: Home,
    },
    {
        <span class="hljs-attr">path</span>: <span class="hljs-string">'/register'</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">'Register'</span>,
        <span class="hljs-attr">component</span>: <span class="hljs-function">() =&gt;</span>
            <span class="hljs-keyword">import</span>(<span class="hljs-comment">/* webpackChunkName: "about" */</span> <span class="hljs-string">'../views/About.vue'</span>),
    },
    {
        <span class="hljs-attr">path</span>: <span class="hljs-string">'/dashboard'</span>,
        <span class="hljs-attr">name</span>: <span class="hljs-string">'Dashboard'</span>,
        <span class="hljs-attr">component</span>: <span class="hljs-function">() =&gt;</span>
            <span class="hljs-keyword">import</span>(<span class="hljs-comment">/* webpackChunkName: "dashboard" */</span> <span class="hljs-string">'../views/Dashboard.vue'</span>),
    },
];
</code></pre><h1 id="heading-how-to-create-the-dashboard-component">How to Create the Dashboard Component</h1>
<p>Create a new file called <strong>Dashboard.vue</strong> in the views folder. This page should only be visible to users that have logged on to our application.</p>
<p>In the template section add the following HTML code that says that.</p>
<pre><code>&lt;div&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This page is only visible to users that are currently logged in<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><h1 id="heading-how-to-register-users">How to Register Users</h1>
<p>Earlier when we updated the <strong>About.vue</strong> file to register users we had a call to a method called <strong>Register</strong>. We need to add the functionality to register new users.</p>
<p>First let’s check out the <a target="_blank" href="https://firebase.google.com/docs/auth/web/password-auth">Firebase documentation on how to create a password-based account</a>. Firebase Auth has a method called <strong>createuserWithEmailAndPassword</strong>. You need to pass in the user’s email and password. This method will either register the user and return a user object or it will return an error message. Let’s implement this method now.</p>
<p>Open up the <strong>About.vue</strong> file. We need to add email and password to our data object. In your script section add the following data object:</p>
<pre><code>data() { 
  <span class="hljs-keyword">return</span> { 
    <span class="hljs-attr">email</span>: <span class="hljs-string">''</span>, 
    <span class="hljs-attr">password</span>: <span class="hljs-string">''</span>, 
  }; 
},
</code></pre><p>Next add a methods object with one method called <strong>register</strong>. We can literally copy the example from the Firebase documentation for this method. We will need to make the following changes to the code from the documentation:</p>
<ul>
<li>We will not use the user object</li>
<li>Display an alert if login fails</li>
<li>If user is registered redirect them to login page</li>
</ul>
<p>Here is the code for the register method:</p>
<pre><code>methods: {
  register() {
    firebase
      .auth()
      .createUserWithEmailAndPassword(<span class="hljs-built_in">this</span>.email, <span class="hljs-built_in">this</span>.password)
      then(<span class="hljs-function">() =&gt;</span> {
        alert(<span class="hljs-string">'Successfully registered! Please login.'</span>);
        <span class="hljs-built_in">this</span>.$router.push(<span class="hljs-string">'/'</span>);
      })
      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
        alert(error.message);
      });
  },
},
</code></pre><p>Let’s test registering our first user for our application. Click on the <strong>Register</strong> in the navigation. Enter an email address and password and click the <strong>Register</strong> button.</p>
<p>If the user was successfully registered you should get an alert and be redirected to the login page.</p>
<p>If the registration fails you should get an alert with an error message.</p>
<p>To check if the user was registered successfully, go to your Firebase console and click on your project. In the left side navigation click on <strong>Authentication</strong>. Then click on the <strong>Users</strong> tab. You will see your user listed:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/0_zBdB2l8pNamJpc-h.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now that we have successfully implemented registering new users for our application, we need to implement the ability for the users to login.</p>
<h1 id="heading-how-to-log-in-users">How to Log In Users</h1>
<p>We used the code provided by Firebase to register a new user. On the <a target="_blank" href="https://firebase.google.com/docs/auth/web/password-auth">Firebase documentation page</a> it provides sample code to log in a user with an email address and password. The Firebase auth method we will use is <strong>signInWithEmailAndPassword</strong>.</p>
<p>Like Register, we will make the same changes to the sample code. We will alert the user if they are logged in successfully and redirect them to the <strong>Dashboard</strong> page.</p>
<p>If login fails, then we display an alert with an error message.</p>
<p>Here is the <strong>login</strong> method which you should have in your <strong>Home.vue</strong> file.</p>
<pre><code>methods: {
  login() {
    firebase
      .auth()
      .signInWithEmailAndPassword(<span class="hljs-built_in">this</span>.email, <span class="hljs-built_in">this</span>.password)
      .then(<span class="hljs-function">() =&gt;</span> {
        alert(<span class="hljs-string">'Successfully logged in'</span>);
        <span class="hljs-built_in">this</span>.$router.push(<span class="hljs-string">'/dashboard'</span>);
      })
      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
        alert(error.message);
      });
  },
},
</code></pre><h1 id="heading-how-to-create-a-route-guard">How to Create A Route Guard</h1>
<p>We don’t want users to be able to navigate to <strong>/dashboard</strong> unless they have logged in. We can do this by adding a route guard for /dashboard.</p>
<p>Open up the <strong>index.js</strong> file in the router folder. We will add a meta key to the <strong>/register</strong> route that will say that authentication is required. Here is the updated route:</p>
<pre><code>{
  <span class="hljs-attr">path</span>: <span class="hljs-string">'/dashboard'</span>,
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Dashboard'</span>,
  <span class="hljs-attr">component</span>: <span class="hljs-function">() =&gt;</span>
    <span class="hljs-keyword">import</span>(<span class="hljs-comment">/* webpackChunkName: "dashboard" */</span> <span class="hljs-string">'../views/Dashboard.vue'</span>),
  <span class="hljs-attr">meta</span>: {
    <span class="hljs-attr">authRequired</span>: <span class="hljs-literal">true</span>,
  },
},
</code></pre><p>Before Vue Router processes a route it has a method called <strong>beforeEach</strong>. We can check to see if the route requires authentication by checking the meta value.</p>
<p>If authentication is required, we need to be able to check if the user is logged in or not. Luckily there is a <strong>currentUser</strong> object in Firebase Auth. We will use that to check if the user is logged in or not.</p>
<p>If they are currently logged in then we will display the <strong>Dashboard</strong> page.</p>
<p>If not we will display an alert telling the user they must be logged in and redirect them to the <strong>Home</strong> page for them to login.</p>
<p>Here is the code:</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> (firebase.auth().currentUser) {
      next();
    } <span class="hljs-keyword">else</span> {
      alert(<span class="hljs-string">'You must be logged in to see this page'</span>);
      next({
        <span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>,
      });
    }
  } <span class="hljs-keyword">else</span> {
    next();
  }
});
</code></pre><h1 id="heading-how-to-logout-users">How to Logout Users</h1>
<p>The last thing we need to add to our application is the logout method. Firebase Auth provides a signOut method that we will use.</p>
<p>Open up the <strong>App.vue</strong> file. We will logout the user. If successful, they will receive an alert and be redirected to the <strong>Home</strong> page.</p>
<p>If the logout fails we display an alert with the error message and redirect them to the <strong>Home</strong> page.</p>
<p>Add this code for the <strong>logout</strong> method:</p>
<pre><code>methods: {
  logout() {
    firebase
      .auth()
      .signOut()
      .then(<span class="hljs-function">() =&gt;</span> {
        alert(<span class="hljs-string">'Successfully logged out'</span>);
        <span class="hljs-built_in">this</span>.$router.push(<span class="hljs-string">'/'</span>);
      })
      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
        alert(error.message);
        <span class="hljs-built_in">this</span>.$router.push(<span class="hljs-string">'/'</span>);
      });
  },
},
</code></pre><p>In the code above, we are using Firebase but we do not have any reference to it in our index.js file. We need to add that. Scroll up to the top of the file where the existing import lines are. Add this line:</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>Now with that added, you can practice registering a new user. Then login with that user and verify that you are redirected to the <strong>Dashboard</strong> page. Then logout and verify you are redirected to the <strong>Home</strong> page.</p>
<p>Congratulations – you have successfully added Firebase Authentication to your Vue application!</p>
<h1 id="heading-get-the-code">Get The Code</h1>
<p>I have the <a target="_blank" href="https://github.com/ratracegrad/Vue-Firebase-Auth-Tutorial">complete code in my GitHub account here</a>. If you get the code please do me a favor and star my repo. Thank you!</p>
<h1 id="heading-using-other-authentication-methods">Using Other Authentication Methods</h1>
<p>I have written several follow up articles on adding Authentication to your Vue application using other authentication methods. </p>
<p>If you want to use Auth0 for authentication, <a target="_blank" href="https://www.freecodecamp.org/news/how-to-add-authentication-to-a-vue-app-using-auth0/">read this article</a>.</p>
<p>If you want to use AWS Amplify for authentication, <a target="_blank" href="https://www.freecodecamp.org/news/how-to-add-authentication-to-a-vue-app-using-aws-amplify/">read this article</a>.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Firebase is a very efficient method of adding authentication to your Vue applications. It allows you to add Authentication without having to write your own Backend service and implementing Authentication yourself.</p>
<p>Hope you enjoyed this article. If you like it please share it. Thanks for reading.</p>
<p><em>Originally published at</em> <a target="_blank" href="https://www.jenniferbland.com/how-to-add-authentication-to-a-vue-app-using-firebase/"><em>https://www.jenniferbland.com</em></a> <em>on December 28, 2020.</em></p>
<h2 id="heading-jennifer-bland">Jennifer Bland</h2>
<h4 id="heading-software-engineer-google-developers-expert-keynote-speaker-entrepreneur-mountain-climber-neil-diamond-fan-world-traveler-jenniferblandcomhttpjenniferblandcom-amp-codeprepiohttpcodeprepio">Software Engineer. Google Developers Expert. Keynote Speaker. Entrepreneur. Mountain Climber. Neil Diamond fan. World traveler. <a target="_blank" href="http://jenniferbland.com/">jenniferbland.com</a> &amp; <a target="_blank" href="http://codeprep.io/">codeprep.io</a></h4>
<h4 id="heading-57">57</h4>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
