<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Sample Apps on Techformist</title>
    <link>https://techformist.com/categories/sample-apps/</link>
    <description>Recent content in Sample Apps on Techformist</description>
    <image>
      <url>https://techformist.com/logo.svg</url>
      <link>https://techformist.com/logo.svg</link>
    </image>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 06 Jan 2021 06:30:00 +0000</lastBuildDate><atom:link href="https://techformist.com/categories/sample-apps/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Get Started on NextJS</title>
      <link>https://techformist.com/get-started-nextjs/</link>
      <pubDate>Wed, 06 Jan 2021 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/get-started-nextjs/</guid>
      <description>&lt;p&gt;Welcome to 2021. For me this will be an exciting year when I embrace ReactJS and Svelte as friends. And, what better way to start with React than NextJS..? In this post, we will see why and how we can get started on NextJS, and a few good learning resources.&lt;/p&gt;
&lt;h2 id=&#34;but-why&#34;&gt;But, why?&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;React continues to be a leader with ~50% market share. It enjoys a lot of developer confidence, community contribution and widespread adoption&lt;/li&gt;
&lt;li&gt;More users have meant more support for the smallest of issues&lt;/li&gt;
&lt;li&gt;React and associated frameworks have been at the forefront of new developments - that may be in the way pages interact with data (Hooks, Suspense), in how front-end gets/updates data (React Server Components), or how the latest technologies can speed up development and enable you to use hybrid frameworks to get things done (Next)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Vue will not be completely replaced in my toolbox - not unless I find a shiny new thing that can completely replace it. In today&amp;rsquo;s world everyone learns from each other and adapts rather quickly - so that scenario is not likely to play out.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Welcome to 2021. For me this will be an exciting year when I embrace ReactJS and Svelte as friends. And, what better way to start with React than NextJS..? In this post, we will see why and how we can get started on NextJS, and a few good learning resources.</p>
<h2 id="but-why">But, why?</h2>
<ol>
<li>React continues to be a leader with ~50% market share. It enjoys a lot of developer confidence, community contribution and widespread adoption</li>
<li>More users have meant more support for the smallest of issues</li>
<li>React and associated frameworks have been at the forefront of new developments - that may be in the way pages interact with data (Hooks, Suspense), in how front-end gets/updates data (React Server Components), or how the latest technologies can speed up development and enable you to use hybrid frameworks to get things done (Next)</li>
</ol>
<p>Vue will not be completely replaced in my toolbox - not unless I find a shiny new thing that can completely replace it. In today&rsquo;s world everyone learns from each other and adapts rather quickly - so that scenario is not likely to play out.</p>
<h2 id="why-next">Why Next?</h2>
<ul>
<li>Next is a hybrid framework. From the same code base you can -
<ul>
<li>fetch content and generate pages on the server-side at runtime. Rapidly changing sites incl. eCommerce sites.</li>
<li>enable client-side data fetching for classic single page applications</li>
<li>generate static sites. Just fetch data and create final HTML pages at build time. Useful for Blogs, documentation sites. Oor, go rogue with incremental static files that can generate pages and hold on to them for specified time (I love this!)</li>
</ul>
</li>
<li>Built-in router that needs you to just create pages to enable routing. Not really a problem in the Vue world (Vue router becomes second nature), but I see React as more fragmented. Router in Next is easy to understand and scale</li>
<li>Many features that optimize applications incl. code splitting, ability to use HTML or JSON to deliver pages, and so on</li>
<li>Many, many features that make development of large apps easier</li>
<li>Super active development and large community.</li>
</ul>
<h2 id="how-to-get-started">How to get started?</h2>
<p>Here&rsquo;s the complicated ceremonty to initiate a Next project.</p>
<ol>
<li>Install NodeJS</li>
<li>Enter command <code>npx create-next-app do-awesome</code></li>
</ol>
<p>Run your app with <code>npm run dev</code> to meet this screen.</p>
<p><img loading="lazy" src="/2021/create-next-app-starting-page.jpg" type="" alt="create-next-app-starting-page"  /></p>
<p>You have the standard SPA development experience - change page content to see the changes reflected immediately.</p>
<ol>
<li>Add new page <code>pages/todo.js</code></li>
<li>Enter below code -
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">Todo</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="o">&lt;</span><span class="nx">h3</span><span class="o">&gt;</span><span class="nx">Todo</span> <span class="nx">Awesome</span><span class="o">&lt;</span><span class="err">/h3&gt;;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ol>
<p>Navigate to <code>http://localhost:3000/todo</code> to see the new page.</p>
<p>Let&rsquo;s write some simple code in <code>todos</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Todo</span><span class="p">({</span> <span class="nx">todos</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">h2</span><span class="o">&gt;</span><span class="nx">Todo</span> <span class="nx">Awesome</span><span class="o">&lt;</span><span class="err">/h2&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span><span class="nx">todos</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">todo</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">li</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">index</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">description</span><span class="p">}</span><span class="o">&amp;</span><span class="nx">emsp</span><span class="p">;</span><span class="err">⇋</span> <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">status</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="err">/li&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">))}</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kd">function</span> <span class="nx">getServerSideProps</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;Write blog post&#34;</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Open&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;Learn magic trick&#34;</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Open&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;Profit from blog&#34;</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Cancelled&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">todos</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Todo</span><span class="p">;</span>
</span></span></code></pre></div><p>We did good in a few lines of code -</p>
<ol>
<li>Created some static data in <code>todos</code> as part of <code>getServerSideProps</code> and returned that as <code>props</code></li>
<li><code>getServerSideProps</code> gets executed for every function call, i.e., everytime we visit the route <code>/todos</code>. Rendering function <code>Todo</code> gets the data passed in as props</li>
<li><code>Todo</code> takes care of rendering the todos</li>
</ol>
<p>Rather simple and elegant.</p>
<p><img loading="lazy" src="/2021/next-page-basic-todo.jpg" type="" alt="next-page-basic-todo"  /></p>
<h2 id="add-styles">Add Styles</h2>
<p>There is more than one way to do things in Next, just like in React - unfortunately.
I follow three distinct patterns.</p>
<h4 id="global-or-module-level-styles">Global or Module Level Styles</h4>
<p>Include CSS in <code>styles &gt; global.css</code> for all styles applicable globally. Similarly, <code>&lt;your-page&gt;.module.css</code> gets applied to <code>&lt;your-page&gt;</code>.</p>
<p>There&rsquo;s nothing preventing you from going old school and simple do -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;../styles.css&#34;</span><span class="p">;</span>
</span></span></code></pre></div><p>.. in any component, but the previous pattern is simpler to use.</p>
<h4 id="global-or-module-level-css-with-cdn">Global or Module Level CSS with CDN</h4>
<p>Use the Next <code>&lt;Head&gt;&lt;/Head&gt;</code> tag anywhere - in <code>_app</code> for global styles or in any modules. Introduce CSS within the <code>HEAD</code> component.</p>
<p>Let us go ahead and do this for our app. Change <code>_app.js</code> to-</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;../styles/globals.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Head</span> <span class="nx">from</span> <span class="s2">&#34;next/head&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">MyApp</span><span class="p">({</span> <span class="nx">Component</span><span class="p">,</span> <span class="nx">pageProps</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">Head</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">link</span> <span class="nx">rel</span><span class="o">=</span><span class="s2">&#34;stylesheet&#34;</span> <span class="nx">href</span><span class="o">=</span><span class="s2">&#34;https://unpkg.com/chota&#34;</span> <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/Head&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-1&#34;</span><span class="o">&gt;&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-10&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">Component</span> <span class="p">{...</span><span class="nx">pageProps</span><span class="p">}</span> <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-1&#34;</span><span class="o">&gt;&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">MyApp</span><span class="p">;</span>
</span></span></code></pre></div><p><code>chota</code> is a small CSS framework that provides you some cool things like class-less styling, grids, out-of-the-box icons - good enough for our small project.</p>
<p>Remember that we are dealing with JSX, so we use <code>className</code> instead of <code>class</code> in normal HTML.</p>
<h4 id="style-libraries-from-npm">Style Libraries from NPM</h4>
<p>Install any CSS library through NPM. You can now include the library in <code>_app.js</code> for global styles.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;bootstrap/dist/css/bootstrap.css&#34;</span><span class="p">;</span>
</span></span></code></pre></div><h2 id="add-a-db">Add a DB!</h2>
<p>Our <code>todo</code> page is static and shows the same data each time. Let us change that.</p>
<p>First, let us add prisma to our project to make database access a breeze.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i -D @prisma/cli
</span></span><span class="line"><span class="cl">npm i @prisma/client
</span></span></code></pre></div><p>Create a new folder <code>data</code> under project root.</p>
<p>Initialize prisma -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx prisma init
</span></span></code></pre></div><p>Prisma CLI creates a few files including -</p>
<ul>
<li><code>.env</code> file (if it doesn&rsquo;t exist) with a database URL</li>
<li><code>prisma/schema.prisma</code> contains the database connection parameters and DB models</li>
</ul>
<p>Open <code>prisma/schema.prisma</code> and replace its contents with the below code -</p>
<pre tabindex="0"><code>datasource db {
  provider = &#34;sqlite&#34;
  url      = &#34;file:../data/data.db&#34;
}

generator client {
  provider = &#34;prisma-client-js&#34;
}

model todo {
  id Int @id @default(autoincrement())
  description String
  status String
}
</code></pre><p>Run the below command to create migration and sync model to database.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx prisma migrate dev --preview-feature
</span></span></code></pre></div><p><code>preview-feature</code> flag may not be required in later versions of prisma. You can provide any name for the migration.</p>
<p>Finally, run the <code>generate</code> command to generate client that can be used in your application.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx prisma generate
</span></span></code></pre></div><p>You can connect to the SQLite database using a client like <a href="https://www.heidisql.com/">HeidiSQL</a> and verify whether all your changes are applied to the table.</p>
<p><img loading="lazy" src="/2021/heidi-sql-sqlite.jpg" type="" alt="heidi-sql-sqlite"  /></p>
<p>Or, you could simply do -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx prisma studio
</span></span></code></pre></div><p>.. to open the database with a simple UI.</p>
<p><img loading="lazy" src="/2021/prisma-studio.jpg" type="" alt="prisma-studio"  /></p>
<p>You are all set to work with the SQLite database from Next using Prisma!</p>
<h2 id="get-todos">Get Todos</h2>
<p>Change <code>pages/todos.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@prisma/client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Todo</span><span class="p">({</span> <span class="nx">todos</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">h2</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-12 list-title is-center&#34;</span><span class="o">&gt;</span><span class="nx">My</span> <span class="nx">Todos</span><span class="o">&lt;</span><span class="err">/h2&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-12&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="nx">todoArr</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">todo</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">index</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-1 list-desc&#34;</span> <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;id&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-5 list-desc&#34;</span> <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;description&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">description</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-4&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="nx">select</span>
</span></span><span class="line"><span class="cl">                <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;status&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="nx">id</span><span class="o">=</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">status</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">handleStatusChange</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="nx">onBlur</span><span class="o">=</span><span class="p">{</span><span class="nx">handleSubmit</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;Open&#34;</span><span class="o">&gt;</span><span class="nx">Open</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;In Progress&#34;</span><span class="o">&gt;</span><span class="nx">In</span> <span class="nx">Progress</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;Cancelled&#34;</span><span class="o">&gt;</span><span class="nx">Cancelled</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="err">/select&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">))}</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">getServerSideProps</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">orderBy</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">id</span><span class="o">:</span> <span class="s2">&#34;desc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;todos: &#34;</span><span class="p">,</span> <span class="nx">todos</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">todos</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Todo</span><span class="p">;</span>
</span></span></code></pre></div><p>The above code is straight-forward -</p>
<ul>
<li><code>getServerSideProps</code> includes logic that executes on the server side when a request is made to <code>http://localhost:3000/todos</code> (remember that the file is at <code>pages/todos.js</code>)</li>
<li>Next passes the data from <code>getServerSideProps</code> to render function <code>function Todo({ todos })</code></li>
<li>We display the <code>todos</code> data using JSX</li>
</ul>
<h2 id="createedit-todos">Create/Edit Todos</h2>
<p>We need Prisma (i.e., any DB operations) to run on the server. Next makes an easy task of creating backend APIs - no separate server needed (you could have your custom server though).</p>
<h3 id="create-apis">Create APIs</h3>
<h4 id="api-new-todo">API: New Todo</h4>
<p>Create new file <code>pages/api/todos/index.js</code> with below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@prisma/client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">handle</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Processing todo request..&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">==</span> <span class="s2">&#34;GET&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s2">&#34;hello&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">==</span> <span class="s2">&#34;POST&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">data</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">newTodo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Open the Developer Console in Chrome (<code>Ctrl+Shift+i</code>) and enter -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">await</span> <span class="nx">fetch</span> <span class="p">(</span><span class="s1">&#39;http://localhost:3000/api/todos&#39;</span><span class="p">)</span><span class="sb">`
</span></span></span></code></pre></div><p>.. to see &ldquo;hello&rdquo; returned. And oh.. we added the actual method to accept data from frontend and create a new record using Prisma. All it took was a couple of lines of code.</p>
<h4 id="api-updatedelete-todo">API: Update/Delete Todo</h4>
<p>While we are here, we will also handle -</p>
<ol>
<li>Record-specific deletes (<code>DELETE</code> method that will use <code>/api/todos/1</code> to delete record with <code>id</code>=1)</li>
<li>Record-specific updates (<code>PATCH</code> method to <code>/api/todos/2</code> to update record with <code>id</code>=2)</li>
</ol>
<p>The depicted URLs are standard REST resource URLs - nothing fancy here.</p>
<p>Create new file <code>pages/api/todos/index.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@prisma/client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">handle</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">==</span> <span class="s2">&#34;DELETE&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Processing todo delete..&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">todo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="k">delete</span><span class="p">({</span> <span class="nx">where</span><span class="o">:</span> <span class="p">{</span> <span class="nx">id</span><span class="o">:</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">todo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">==</span> <span class="s2">&#34;PATCH&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Processing todo update..&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">update</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">data</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">newTodo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You might have noticed one key difference between the <code>GET</code> and <code>POST/DELETE/PATCH</code>. While we coded <code>GET</code> within the page itself, we used <code>api</code> folder to house update operations.</p>
<ul>
<li>While <code>prisma</code> was used in the <code>todos.js</code> page, <code>getServerSideProps</code> executes on server. So, we did not have any issues placing backend-specific logic there</li>
<li>Updates are not tied to backend in such fashion. Instead we create APIs in the <code>api</code> folder and call them using <code>fetch</code></li>
</ul>
<h3 id="change-ui-to-call-apis">Change UI to Call APIs</h3>
<p>Before we go ahead with UI changes, you would have noticed a problem with our file structure. While APIs had <code>index</code> and <code>[id]</code> files grouped under a parent <code>todos</code>, we do not have this structure in the frontend yet. Let&rsquo;s change that.</p>
<p>Create a new folder <code>pages/todos</code> - this will house all functions for <code>todos</code>. Move <code>pages/todos.js</code> to <code>pages/todos/</code> and rename it to <code>index.js</code>.</p>
<h4 id="todo-list">Todo List</h4>
<p>Replace current code in <code>pages/todos/index.js</code> with -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useState</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;react&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@prisma/client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Link</span> <span class="nx">from</span> <span class="s2">&#34;next/link&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">Todo</span><span class="p">({</span> <span class="nx">todos</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">todoIn</span><span class="p">,</span> <span class="nx">setTodoIn</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">[</span><span class="nx">todoArr</span><span class="p">,</span> <span class="nx">setTodoArr</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="nx">todos</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">handleNewTodoChange</span> <span class="o">=</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTodoIn</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">handleSubmit</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span><span class="s2">&#34;/api/todos&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">method</span><span class="o">:</span> <span class="s2">&#34;POST&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">body</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="nx">description</span><span class="o">:</span> <span class="nx">todoIn</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Open&#34;</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTodoArr</span><span class="p">([</span><span class="nx">newTodo</span><span class="p">,</span> <span class="p">...</span><span class="nx">todoArr</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTodoIn</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">handleStatusChange</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;target&#34;</span><span class="p">,</span> <span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span><span class="s2">&#34;/api/todos&#34;</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">method</span><span class="o">:</span> <span class="s2">&#34;POST&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">body</span><span class="o">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="nx">description</span><span class="o">:</span> <span class="nx">todoIn</span><span class="p">,</span> <span class="nx">status</span><span class="o">:</span> <span class="s2">&#34;Open&#34;</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">newTodo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTodoArr</span><span class="p">([</span><span class="nx">newTodo</span><span class="p">,</span> <span class="p">...</span><span class="nx">todoArr</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">deleteTodo</span> <span class="o">=</span> <span class="p">(</span><span class="nx">todo</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span><span class="sb">`/api/todos/</span><span class="si">${</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">method</span><span class="o">:</span> <span class="s2">&#34;DELETE&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">index</span> <span class="o">=</span> <span class="nx">todoArr</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">todo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">setTodoArr</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">      <span class="p">...</span><span class="nx">todoArr</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">index</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="p">...</span><span class="nx">todoArr</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="nx">index</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">todoArr</span><span class="p">.</span><span class="nx">length</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">]);</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">h2</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-12 list-title is-center&#34;</span><span class="o">&gt;</span><span class="nx">My</span> <span class="nx">Todos</span><span class="o">&lt;</span><span class="err">/h2&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">form</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-12&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-1 list-desc&#34;</span><span class="o">&gt;</span><span class="nx">Add</span><span class="o">&lt;</span><span class="err">/span&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">input</span>
</span></span><span class="line"><span class="cl">            <span class="nx">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">onBlur</span><span class="o">=</span><span class="p">{</span><span class="nx">handleNewTodoChange</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-5&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">handleNewTodoChange</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">todoIn</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">          <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;button col-2&#34;</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">handleSubmit</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="nx">Save</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/form&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-12&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="nx">todoArr</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">todo</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;row&#34;</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">index</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-1 list-desc&#34;</span> <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;id&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-5 list-desc&#34;</span> <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;description&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">description</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-4&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="nx">select</span>
</span></span><span class="line"><span class="cl">                <span class="nx">name</span><span class="o">=</span><span class="s2">&#34;status&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="nx">id</span><span class="o">=</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">todo</span><span class="p">.</span><span class="nx">status</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">handleStatusChange</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="nx">onBlur</span><span class="o">=</span><span class="p">{</span><span class="nx">handleSubmit</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;Open&#34;</span><span class="o">&gt;</span><span class="nx">Open</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;In Progress&#34;</span><span class="o">&gt;</span><span class="nx">In</span> <span class="nx">Progress</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">option</span> <span class="nx">value</span><span class="o">=</span><span class="s2">&#34;Cancelled&#34;</span><span class="o">&gt;</span><span class="nx">Cancelled</span><span class="o">&lt;</span><span class="err">/option&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="err">/select&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;col-2 icon&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;button icon-only&#34;</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">deleteTodo</span><span class="p">(</span><span class="nx">todo</span><span class="p">)}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">img</span>
</span></span><span class="line"><span class="cl">                  <span class="nx">src</span><span class="o">=</span><span class="s2">&#34;https://icongr.am/feather/delete.svg?size=16&amp;color=93939a&#34;</span>
</span></span><span class="line"><span class="cl">                  <span class="nx">alt</span><span class="o">=</span><span class="s2">&#34;delete&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="nx">Link</span> <span class="nx">href</span><span class="o">=</span><span class="p">{</span><span class="sb">`/todos/</span><span class="si">${</span><span class="nx">todo</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="sb">`</span><span class="p">}</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="nx">button</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;button icon-only&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="o">&lt;</span><span class="nx">img</span>
</span></span><span class="line"><span class="cl">                    <span class="nx">src</span><span class="o">=</span><span class="s2">&#34;https://icongr.am/feather/edit-2.svg?size=16&amp;color=93939a&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="nx">alt</span><span class="o">=</span><span class="s2">&#34;edit&#34;</span>
</span></span><span class="line"><span class="cl">                  <span class="o">/&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="o">&lt;</span><span class="err">/button&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="o">&lt;</span><span class="err">/Link&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">))}</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">getServerSideProps</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">orderBy</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">id</span><span class="o">:</span> <span class="s2">&#34;desc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;todos: &#34;</span><span class="p">,</span> <span class="nx">todos</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">todos</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Todo</span><span class="p">;</span>
</span></span></code></pre></div><p>We have added below features -</p>
<ul>
<li>Add an input box and a button to add a new <code>todo</code> record. Add functions to handle changes to input and to respond to the click event</li>
<li>Add functions to handle changes to call backend APIs for inserts and deletes, and make corresponding changes on the UI</li>
<li>Create a button to delete a <code>todo</code> and call API DELETE method</li>
<li>Create a button to navigate to a detail page upon clicking on any todo (the detail page is implemented in the next section)</li>
</ul>
<h4 id="todo-detail">Todo Detail</h4>
<p>With a couple of functions you have created an app to query ( &amp; display), create and delete todos!</p>
<p>Create a new page <code>pages/todos/[id].js</code> and input below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">useRouter</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;next/router&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;@prisma/client&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">Todo</span><span class="p">({</span> <span class="nx">todo</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">useRouter</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">id</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">router</span><span class="p">.</span><span class="nx">query</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="s2">&#34;text-center&#34;</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">h3</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="o">&lt;</span><span class="nx">strong</span><span class="o">&gt;</span><span class="p">{</span><span class="o">!!</span><span class="nx">todo</span> <span class="o">&amp;&amp;</span> <span class="nx">todo</span><span class="p">.</span><span class="nx">description</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/strong&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="err">/h3&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;</span><span class="p">{</span><span class="o">!</span><span class="nx">todo</span> <span class="o">&amp;&amp;</span> <span class="s2">&#34;This todo has migrated to the next universe.&#34;</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="o">&lt;</span><span class="nx">p</span><span class="o">&gt;&lt;</span><span class="err">/p&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="o">&lt;</span><span class="err">/div&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">getServerSideProps</span><span class="p">({</span> <span class="nx">params</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">todo</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">prisma</span><span class="p">.</span><span class="nx">todo</span><span class="p">.</span><span class="nx">findFirst</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">where</span><span class="o">:</span> <span class="p">{</span> <span class="nx">id</span><span class="o">:</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;todo: &#34;</span><span class="p">,</span> <span class="nx">todo</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">todo</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>This page just demonstrates how we could display a single <code>todo</code> on the frontend. We have not added any functionality to it.</p>
<h2 id="what-next">What Next?</h2>
<p>Find the app code at this <a href="https://github.com/prashanth1k/do-awesome-nextjs-sample-app">Github repo</a>.</p>
<p>You could extend the current app by -</p>
<ol>
<li>Introducing update function - status changes should call <code>PATCH</code> method and change UI elements</li>
<li>Enable user to capture thoughts, ideas and other BS against each <code>todo</code>. Doing this would require you to provide functionality to add <code>comments</code> against any specific <code>todo</code> (utilising the <code>Detail page</code>)</li>
</ol>
<h2 id="learning-resources">Learning Resources</h2>
<p>See more of Next and keep rocking.</p>
<ul>
<li><a href="https://nextjs.org/learn/basics/create-nextjs-app">Learn NextJS</a> by Vercel, creator of NextJS</li>
<li><a href="https://www.youtube.com/watch?v=tt3PUvhOVzo">NextJS in 2 hours</a></li>
<li><a href="https://www.youtube.com/watch?v=1GpbdX8aJCU">Create a Snippet Manager in Next</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create Reddit Reader Using Vue 3 &amp; Vite</title>
      <link>https://techformist.com/reddit-reader-vue3-vite/</link>
      <pubDate>Wed, 30 Dec 2020 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/reddit-reader-vue3-vite/</guid>
      <description>&lt;p&gt;Hello everyone! Hope you are all set for the new year. While you are waiting for the Y2020 to end with bated breath, here&amp;rsquo;s a post to kick start your Vue 3 journey. We will create a Reddit reader using Vue3 and Vite!&lt;/p&gt;
&lt;p&gt;This post is more useful for someone with basic knowledge of Vue and Vue 2.&lt;/p&gt;
&lt;h2 id=&#34;get-started-installation&#34;&gt;Get Started: Installation&lt;/h2&gt;
&lt;p&gt;Create a Vue 3 project with Vite..&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmd&#34; data-lang=&#34;cmd&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm create @vitejs/app
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Select the &lt;code&gt;vue&lt;/code&gt; template on prompt to create a new folder for your project. Install dependencies.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Hello everyone! Hope you are all set for the new year. While you are waiting for the Y2020 to end with bated breath, here&rsquo;s a post to kick start your Vue 3 journey. We will create a Reddit reader using Vue3 and Vite!</p>
<p>This post is more useful for someone with basic knowledge of Vue and Vue 2.</p>
<h2 id="get-started-installation">Get Started: Installation</h2>
<p>Create a Vue 3 project with Vite..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm create @vitejs/app
</span></span></code></pre></div><p>Select the <code>vue</code> template on prompt to create a new folder for your project. Install dependencies.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">cd</span> reddit-reader-vite-vue-app
</span></span><span class="line"><span class="cl">npm i
</span></span></code></pre></div><p>Run the project -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm run dev
</span></span></code></pre></div><p>The project starts almost instantaneously.. sweet. Do two more things -</p>
<ul>
<li>Open the project folder in VSCode</li>
<li>Open <code>http://localhost:3000/</code> in your browser</li>
</ul>
<p>Edit the file <code>index.html</code> and include reference to a light-weight CSS framework. I use <a href="https://jenil.github.io/chota/">chota css</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/chota@latest&#34;</span> <span class="p">/&gt;</span>
</span></span></code></pre></div><p>Create a blank file at <code>src/assets/css/styles.css</code> to create custom styles (we will include this file in <code>main.js</code>). I will not explicitly outline any custom styles here, but you should find them here on the Github repo.</p>
<p>Yay.. you have this beautiful app.</p>
<p><img loading="lazy" src="/2020/vite3-initial-page.jpg" type="" alt="vite3-initial-page"  /></p>
<p>You are all set! Let us start coding in the app.</p>
<h2 id="setup-vue-router">Setup Vue Router</h2>
<p>We will have a bunch of links (well, two to be exact) to navigate within the app. Vue Router makes that routing real easy. Let&rsquo;s set it up.</p>
<p>First, install Vue router compatible with Vue3.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i vue-router@4
</span></span></code></pre></div><p>Next, create the router file <code>src/router/index.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">createWebHistory</span><span class="p">,</span> <span class="nx">createRouter</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue-router&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Home</span> <span class="nx">from</span> <span class="s2">&#34;../views/Home.vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">history</span> <span class="o">=</span> <span class="nx">createWebHistory</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">routes</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="nx">component</span><span class="o">:</span> <span class="nx">Home</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/top&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../views/Posts.vue&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">filter</span><span class="o">:</span> <span class="s2">&#34;top&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/controversial&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../views/Posts.vue&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span> <span class="nx">filter</span><span class="o">:</span> <span class="s2">&#34;controversial&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">createRouter</span><span class="p">({</span> <span class="nx">history</span><span class="p">,</span> <span class="nx">routes</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>We will use the same view <code>Posts</code> for both top and controversial posts. The view will decide which data to fetch based on the prop called <code>filter</code>, which gets passed by the router.</p>
<p>Change <code>src/main.js</code> to use the router file and include the custom style file we had created earlier -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">createApp</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">App</span> <span class="nx">from</span> <span class="s2">&#34;./App.vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">router</span> <span class="nx">from</span> <span class="s2">&#34;./router&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="s2">&#34;./assets/css/styles.css&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">createApp</span><span class="p">(</span><span class="nx">App</span><span class="p">).</span><span class="nx">use</span><span class="p">(</span><span class="nx">router</span><span class="p">).</span><span class="nx">mount</span><span class="p">(</span><span class="s2">&#34;#app&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>There&rsquo;s a small problem with the router code - we don&rsquo;t have those views yet. Let&rsquo;s do that now.</p>
<h2 id="setup-views">Setup Views</h2>
<p>We will create two new views and setup <code>App</code> to use the router.</p>
<h4 id="home">Home</h4>
<p>Create a new view for the home page - <code>src/views/Home.vue</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h3</span><span class="p">&gt;</span>Reddit Reader<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>This is a simple Reddit Reader app.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;card hero justify-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;is-center text-light&#34;</span><span class="p">&gt;</span>Start Here!<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">router-link</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/top&#34;</span><span class="p">&gt;</span>Top Posts<span class="p">&lt;/</span><span class="nt">router-link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="ni">&amp;nbsp;</span> | <span class="ni">&amp;nbsp;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">router-link</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/controversial&#34;</span><span class="p">&gt;</span>Controversial Posts<span class="p">&lt;/</span><span class="nt">router-link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><h4 id="posts">Posts</h4>
<p>Create a new view for showing the list of posts - <code>src/views/Posts.vue</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;</span>Posts<span class="p">&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><h4 id="appvue">App.vue</h4>
<p>Change code in <code>src/App.vue</code> to make use of router.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">header</span><span class="p">&gt;&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">router-view</span> <span class="na">:key</span><span class="o">=</span><span class="s">&#34;$route.path&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="nx">Header</span> <span class="nx">from</span> <span class="s2">&#34;./components/Header.vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="nx">Footer</span> <span class="nx">from</span> <span class="s2">&#34;./components/Footer.vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">#</span><span class="nn">app</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">font-family</span><span class="p">:</span> <span class="n">Avenir</span><span class="p">,</span> <span class="n">Helvetica</span><span class="p">,</span> <span class="n">Arial</span><span class="p">,</span> <span class="kc">sans-serif</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kp">-webkit-</span><span class="n">font-smoothing</span><span class="p">:</span> <span class="n">antialiased</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kp">-moz-</span><span class="n">osx-font-smoothing</span><span class="p">:</span> <span class="n">grayscale</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">text-align</span><span class="p">:</span> <span class="kc">center</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">color</span><span class="p">:</span> <span class="mh">#2c3e50</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">margin-top</span><span class="p">:</span> <span class="mi">60</span><span class="kt">px</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Let&rsquo;s also create two new components for header and footer, which display the logo/brand, navbar and footer for the entire site.</p>
<p>Create new file <code>src/components/Header.vue</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav-left&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo-brand&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/&#34;</span><span class="p">&gt;</span>Reddit Reader<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav-right&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;tabs&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">router-link</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/top&#34;</span><span class="p">&gt;</span>Top<span class="p">&lt;/</span><span class="nt">router-link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">router-link</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/controversial&#34;</span><span class="p">&gt;</span>Controversial<span class="p">&lt;/</span><span class="nt">router-link</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create new file <code>src/components/Footer.vue</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">footer</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-grey bg-light&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container is-left&#34;</span><span class="p">&gt;</span>i am groot<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><h2 id="change-post-view">Change Post View</h2>
<p>Let&rsquo;s go back to our posts view and do just one thing - outline a list of <code>top</code> and <code>controversial</code> posts. No pagination, showing the page details - nothing. We just take the user to Reddit when a link is clicked. We will use the all new Vue composition API and features.</p>
<p>Let&rsquo;s start by extending the template created earlier to receive props from router, call Reddit API, and display the results.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">strong</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-light&#34;</span><span class="p">&gt;</span>posts<span class="p">&lt;/</span><span class="nt">strong</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-msg&#34;</span><span class="p">&gt;</span>{{ err }}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{ posts }}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">onMounted</span><span class="p">,</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">defineProps</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">([]);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">err</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">mounted</span> <span class="o">=</span> <span class="nx">onMounted</span><span class="p">(</span><span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Fetching them posts..&#34;</span><span class="p">,</span> <span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetchPosts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;posts.value: &#34;</span><span class="p">,</span> <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="p">({</span> <span class="nx">filter</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;top&#34;</span> <span class="p">}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">fetchPosts</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">query</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="sb">`https://api.reddit.com/</span><span class="si">${</span><span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="si">}</span><span class="sb">?limit=10`</span>
</span></span><span class="line"><span class="cl">      <span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">res</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">resJson</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">resJson</span><span class="o">?</span><span class="p">.</span><span class="nx">data</span><span class="o">?</span><span class="p">.</span><span class="nx">children</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">res</span><span class="p">.</span><span class="nx">statusText</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;data: &#34;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Straight off the bat you will notice a few curiosities.</p>
<h6 id="variables">Variables</h6>
<p>There are no distinct sections that will be exported by default. Instead, we make do with a new function called <code>setup()</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">setup</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>This is further simplified by using <code>&lt;script setup&gt;</code> tag.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">onMounted</span><span class="p">,</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">defineProps</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h6 id="variables-and-state">Variables and State</h6>
<p>Instead of a <code>data()</code> section in Vue2, we directly define variables in <code>script</code> (you could always mix and match, and confuse yourself and others though).</p>
<p>But, we need to tell Vue that we are creating a state variable that may also be reactive. We do that using <code>ref</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">([]);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">err</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h6 id="props">Props</h6>
<p>Define props with -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="p">({</span> <span class="nx">filter</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;top&#34;</span> <span class="p">}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h6 id="life-cycle-hooks">Life Cycle Hooks</h6>
<p>We use <code>onMounted</code> hook to fetch data from Reddit.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">mounted</span> <span class="o">=</span> <span class="nx">onMounted</span><span class="p">(</span><span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Fetching them posts..&#34;</span><span class="p">,</span> <span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetchPosts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;posts.value: &#34;</span><span class="p">,</span> <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><h6 id="methods">Methods</h6>
<p>Methods can be defined anywhere within <code>script</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">fetchPosts</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">query</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="sb">`https://api.reddit.com/</span><span class="si">${</span><span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="si">}</span><span class="sb">?limit=10`</span>
</span></span><span class="line"><span class="cl">      <span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">res</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">resJson</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">resJson</span><span class="o">?</span><span class="p">.</span><span class="nx">data</span><span class="o">?</span><span class="p">.</span><span class="nx">children</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">res</span><span class="p">.</span><span class="nx">statusText</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;data: &#34;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>With a few cosmetic chahges, the final code for <code>Posts.vue</code> is outlined below -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">strong</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-light&#34;</span><span class="p">&gt;</span>{{ props.filter || &#34;&#34; }} posts<span class="p">&lt;/</span><span class="nt">strong</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">h4</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-msg&#34;</span><span class="p">&gt;</span>{{ err }}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">v-if</span><span class="o">=</span><span class="s">&#34;!posts || posts.length &lt;= 0&#34;</span><span class="p">&gt;</span>Loading..<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span>
</span></span><span class="line"><span class="cl">      <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-item card text-left&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">v-for</span><span class="o">=</span><span class="s">&#34;(post, index) in posts&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">:key</span><span class="o">=</span><span class="s">&#34;index&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">v-else</span>
</span></span><span class="line"><span class="cl">    <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-title&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">:href</span><span class="o">=</span><span class="s">&#34;post?.data?.url&#34;</span> <span class="na">target</span><span class="o">=</span><span class="s">&#34;_blank&#34;</span><span class="p">&gt;</span>{{ post?.data?.title }}<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-item-meta&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span>
</span></span><span class="line"><span class="cl">          <span class="na">:href</span><span class="o">=</span><span class="s">&#34;`https://reddit.com/${post?.data?.subreddit_name_prefixed}`&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">target</span><span class="o">=</span><span class="s">&#34;blank&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&gt;</span>{{ post?.data?.subreddit_name_prefixed }}<span class="p">&lt;/</span><span class="nt">a</span>
</span></span><span class="line"><span class="cl">        <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        | {{ post?.data?.num_comments }} comments
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">onMounted</span><span class="p">,</span> <span class="nx">ref</span><span class="p">,</span> <span class="nx">defineProps</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">([]);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">err</span> <span class="o">=</span> <span class="nx">ref</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">mounted</span> <span class="o">=</span> <span class="nx">onMounted</span><span class="p">(</span><span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;Fetching them posts..&#34;</span><span class="p">,</span> <span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetchPosts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;posts.value: &#34;</span><span class="p">,</span> <span class="nx">posts</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="p">({</span> <span class="nx">filter</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;top&#34;</span> <span class="p">}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">fetchPosts</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">query</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">fetch</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="sb">`https://api.reddit.com/</span><span class="si">${</span><span class="nx">props</span><span class="p">.</span><span class="nx">filter</span><span class="si">}</span><span class="sb">?limit=10`</span>
</span></span><span class="line"><span class="cl">      <span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="nx">res</span><span class="p">.</span><span class="nx">ok</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">resJson</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nx">resJson</span><span class="o">?</span><span class="p">.</span><span class="nx">data</span><span class="o">?</span><span class="p">.</span><span class="nx">children</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">res</span><span class="p">.</span><span class="nx">statusText</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;data: &#34;</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">      <span class="nx">err</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Your app is now ready to rock!</p>
<p><img loading="lazy" src="/2021/reddit-reader-posts-vite.gif" type="" alt="reddit-reader-posts-vite"  /></p>
<h2 id="finis">Finis</h2>
<p>You will find the complete code at this <a href="https://github.com/prashanth1k/reddit-reader-vite-vue-app">Github repo</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Build a Simple News App using Adonis v5</title>
      <link>https://techformist.com/create-simple-news-app-adonisjs/</link>
      <pubDate>Wed, 16 Dec 2020 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/create-simple-news-app-adonisjs/</guid>
      <description>&lt;p&gt;AdonisJS has been my framework of choice to get stuff done quickly. The framework has taken a turn for the good with more frequent updates to its latest version - v5, which features Typescript, the same trusted MVC framework, and &amp;ldquo;everything &amp;amp; kitchen sink&amp;rdquo; approach that is quite effective to easily build apps.&lt;/p&gt;
&lt;p&gt;In this post we will create a simple news website using AdonisJS. The focus will be on -&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>AdonisJS has been my framework of choice to get stuff done quickly. The framework has taken a turn for the good with more frequent updates to its latest version - v5, which features Typescript, the same trusted MVC framework, and &ldquo;everything &amp; kitchen sink&rdquo; approach that is quite effective to easily build apps.</p>
<p>In this post we will create a simple news website using AdonisJS. The focus will be on -</p>
<ol>
<li>Creating a site that is publisher-friendly</li>
<li>Login/auth and publish functions</li>
<li>Support user authentication for creating news articles</li>
<li>Basic styling with a classless framework - we will choose <a href="https://milligram.io">milligram</a> at this time</li>
</ol>
<p>Here&rsquo;s how the app will look like -</p>
<p><img loading="lazy" src="/2020/adonisjs-sample-news-app.gif" type="" alt="adonisjs-sample-news-app"  /></p>
<p>Let&rsquo;s get rocking.</p>
<h2 id="why-adonisjs">Why AdonisJS?</h2>
<p>While there are no dearth of frameworks in NodeJS, you may want to consider AdonisJS -</p>
<ol>
<li>Be productive with many decisions made for you. Start creating your apps rather than spending time on tying up various libraries and packages</li>
<li>Create structured, methodical and easy-to-understand code</li>
<li>Use a view layer that can enable you to build something quickly. Or, enable APIs that can be consumed by your SPA or mobile apps</li>
</ol>
<p>There is no dearth of frameworks using NodeJS, and I am a super fan of Node because of that. But AdonisJS has held its own with its developer-friendly approach, similarity with Laravel (which is a super-productive way to do things), and, of course, with the power of Javascript/Typescript.</p>
<h2 id="get-started-installation">Get Started: Installation</h2>
<p>Ensure you have NodeJS installed on your computer. <a href="https://nodejs.org/en/">Download Node</a> and <a href="https://nodejs.dev/learn/how-to-install-nodejs">follow installation instructions</a> if you are into such type of thing.</p>
<p>Although not strictly required, I recommend you choose a nice database to go along with your app. You can choose from Postgres, MySQL, Oracle, or SQLite. Take help from our dear friend, Google, to find out how to install DBs. Or, just download <a href="https://laragon.org/">Laragon</a> that does all the hard work, and expects you to just start the darn thing.</p>
<p>We are now ready to start creating the app. Create your Adonis app with a simple command.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm init adonis-ts-app newsie
</span></span></code></pre></div><p>The command creates a folder called &rsquo;newsie&rsquo; and takes you through a few options.</p>
<p><img loading="lazy" src="/2020/create-new-app-adonisjs.jpg" type="" alt="create-new-app-adonisjs"  /></p>
<p>We will create a <code>Web Application</code> for the news site. The other option is to choose an API, which can be useful to build a single page application (among other things). Choose defaults for other options, or roll a dice to choose values for you. The wizard only asks your input to use ESLint (<code>y</code>) and, possibly, Prettier at this time.</p>
<p>Navigate to the project folder and open the folder in VSCode.</p>
<p>Next, we install a package to enable connecting to a database.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save @adonisjs/lucid@alpha
</span></span></code></pre></div><p>Invoke the configurator.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace invoke @adonisjs/lucid
</span></span></code></pre></div><p>The command will allow you to choose your database, sets up a few essentials, and provide instructions on changing configuration. Follow the instructions to update <code>env.ts</code> file - add below lines to the file:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">rules</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">  <span class="nx">PG_HOST</span>: <span class="kt">Env.schema.string</span><span class="p">({</span> <span class="nx">format</span><span class="o">:</span> <span class="s2">&#34;host&#34;</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">PG_PORT</span>: <span class="kt">Env.schema.number</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">PG_USER</span>: <span class="kt">Env.schema.string</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">PG_PASSWORD</span>: <span class="kt">Env.schema.string.optional</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="nx">PG_DB_NAME</span>: <span class="kt">Env.schema.string</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Open <code>.env</code> file in your project folder and change below lines (varies depending on your options - I chose Postgres).</p>
<pre tabindex="0"><code>DB_CONNECTION=pg
PG_HOST=localhost
PG_PORT=5432
PG_USER=postgres
PG_PASSWORD=
PG_DB_NAME=newsie
</code></pre><p>The above configuration tells Adonis to connect to Postgres DB called <code>newsie</code> running on localhost port 5432, using the user <code>postgres</code>.</p>
<p>Create a new database called <code>newsie</code> in your database server. You can use a client like HeidiSQL or use an application that is bundled with your database (e.g. pgAdmin4 that comes with Postgres).</p>
<p><img loading="lazy" src="/2020/new-db-postgres.jpg" type="" alt="new-db-postgres"  /></p>
<p>Start your app.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace serve --watch
</span></span></code></pre></div><p>The <code>--watch</code> flag watches for any changes in the project and automatically restarts Adonis server. You can now point your browser to and see the below glorious page.</p>
<p><img loading="lazy" src="/2020/adonis-start-page.jpg" type="" alt="adonis-start-page"  /></p>
<p>We now move on to developing the app.</p>
<h2 id="first-steps-develop-article-functionality">First Steps: Develop Article Functionality</h2>
<p>AdonisJS is a MVC framework. That means that our application uses a pattern that consists of three main logical layers -</p>
<ol>
<li>A model layer that takes care of all things database. Create your data structure, define relationships and so forth</li>
<li>A controller layer that allows you to create logic to write and retrieve data through the model layer</li>
<li>A view layer that takes care of presenting data to the user</li>
</ol>
<p>While this may sound too complex in the beginning, it&rsquo;s really making things easier (and standardized) for building real-world applications.</p>
<blockquote>
<p>Sidenote: There are arguably better, simplified architectures available today for building apps. MVC is still my go-to pattern since I find it easier to understand, can provide guidance and training to others to get started quickly, and there is a structure to everything in complex applications.</p>
</blockquote>
<h3 id="create-article-model">Create Article Model</h3>
<p>Let us add a component to store and allow interactions with articles, which is aptly called <code>Article</code>. We can create the model, controller and what is called a &ldquo;migration file&rdquo; in one go.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"> node ace make model Article -cm
</span></span></code></pre></div><p>The command will do three things -</p>
<ol>
<li>Create a model called <code>Article.ts</code></li>
<li>Create an associated controller called <code>ArticlesController.ts</code> in <code>app\Controllers\Http\</code> folder</li>
<li>Create <code>&lt;a_wierd_number&gt;__articles.ts</code> migration file in <code>database\migrations\</code> folder. We can use this migration file to create tables in the database. It is simpler this way since we will be adding new fields, migrating from our dev to production environment, etc. and having a file is easier to manage than using database migration tools</li>
</ol>
<p>Yes, the names of model, controller and the table created through the migration file is similar. Yes, you can change that behaviour though I don&rsquo;t know why you would do that.</p>
<p>Open the migration file and add a few fields.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">BaseSchema</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Lucid/Schema&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">Articles</span> <span class="kr">extends</span> <span class="nx">BaseSchema</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">protected</span> <span class="nx">tableName</span> <span class="o">=</span> <span class="s2">&#34;articles&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">up() {</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">schema</span><span class="p">.</span><span class="nx">createTable</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">tableName</span><span class="p">,</span> <span class="p">(</span><span class="nx">table</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="nx">increments</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="nx">timestamps</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="kt">string</span><span class="p">(</span><span class="s2">&#34;title&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="nx">text</span><span class="p">(</span><span class="s2">&#34;content&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="nx">dateTime</span><span class="p">(</span><span class="s2">&#34;publish_date&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">down() {</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">schema</span><span class="p">.</span><span class="nx">dropTable</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">tableName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The first two lines for <code>increments</code> and <code>timestamps</code> already existed in the file - they signify to the app that we will use a unique <code>id</code> field that is auto-incremented, and we will also use a <code>created_at</code> and <code>updated_at</code> fields that track created and modified dates. We add a couple of more fields and save the file.</p>
<p>Run the migration.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace migration:run
</span></span></code></pre></div><p>You will find a new table in your database with the specified fields.</p>
<p><img loading="lazy" src="/2020/adonis-db-table-created.jpg" type="" alt="adonis-db-table-created"  /></p>
<p>So far we created columns in a table, but the application wouldn&rsquo;t know what to do with them unless we change the model.</p>
<p>Edit <code>app/Models/Article.ts</code> to add more fields.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="kr">public</span> <span class="nx">title</span>:<span class="kt">String</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="kr">public</span> <span class="nx">content</span>:<span class="kt">String</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@column</span><span class="p">.</span><span class="nx">dateTime</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="kr">public</span> <span class="nx">publishDate</span>: <span class="kt">DateTime</span>
</span></span></code></pre></div><h3 id="create-article-controller">Create Article Controller</h3>
<p>You can display a static page without data without any help from controller. But, a real-world app contains data, needs some business logic to be applied, security rules to be enforced and so on. Controller is the place to do all this.</p>
<p>We previously generated the controller file for Article while creating the model. Open <code>app/Controllers/ArticleController.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">HttpContextContract</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Core/HttpContext&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">ArticlesController</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">index</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">create</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">store</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">show</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">edit</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">update</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">destroy</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The file consists of a bunch of functions to facilitate all possible data operations. This controller can be reached through user (or app) actions.</p>
<p>The <code>start/routes.ts</code> file outlines the various resource operations that your Adonis app supports. Let us add a line to inform Adonis of our controller.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/articles&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticleController.index&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>In plain English: whenever someone tries to go to <code>&lt;app&gt;/articles</code>, invoke <code>index</code> function in <code>ArticleController</code>.</p>
<p>Change <code>index</code> function to return something.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">index</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s1">&#39;This is article.&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Point your browser to <code>http://localhost:3333/articles/</code> to see your message. Of course, we can do much more with controllers. Let us retrieve what we have in our <code>articles</code> table and try to show the contents.</p>
<p>Change <code>index</code> function to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">index</span><span class="p">({}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">articles</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">Article</span><span class="p">.</span><span class="nx">all</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">articles</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span></code></pre></div><p>You will see more of these statements in a short while, but here&rsquo;s a rundown -</p>
<ol>
<li>Get all articles through the <code>Article</code> model</li>
<li>Return articles</li>
</ol>
<p>That&rsquo;s about it. If you go to <code>http://localhost:3333/articles/</code>, you will now see a grand <code>[]</code> as the output. It is an empty array since we don&rsquo;t have any records in the table. At this stage, you could create a few records directly in the table and see those records in the browser, or just wait for the next steps to start creating articles through the app.</p>
<h3 id="create-article-view">Create Article View</h3>
<p>Let us now turn focus to display the article through a view. Inspect <code>resources/view/welcome.edge</code>, which is a simple view file. Adonis views use <code>edge</code> templating language - we will see more of it soon.</p>
<p>You would have observed previously that <code>http://localhost:3333</code> in the browser opens up the <code>welcome</code> view. This is done through <code>start/routes.ts</code> file, specifically with the below line.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">).</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;welcome&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>This tells the application to serve a page <code>welcome</code> that will be sent to the browser when user accesses the root page.</p>
<p>Just for fun, create a new file in the same folder <code>resources/view/hello.edge</code>.</p>
<pre tabindex="0"><code>hello world
</code></pre><p>Add a different route to the <code>start/routes.ts</code> file.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s2">&#34;/hello&#34;</span><span class="p">).</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;hello&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>Navigate to <code>http://localhost:3333/hello</code> to see your new page. It&rsquo;s as simple as that.</p>
<p>In the previous section, you had seen that we had invoked the <code>ArticleController.index()</code> method to return something to the view. The difference?</p>
<ul>
<li>Controller can retrieve data and pass it back to view</li>
<li>A view can simply show content - data, images or any HTML that you write therein</li>
<li>Data returned by controller is not directly displayed on the browser. You will pass it along to the view layer to make sense out of that data and display the beautified, organized content to users</li>
</ul>
<p>Let us improve our display a bit.</p>
<p>First, we will take a decision to show articles on the front page. So, let us change <code>welcome.edge</code>. Change the body section to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h1</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>Welcome to newsie!<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;subtitle&#34;</span><span class="p">&gt;</span>Positive news across the world.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      @!section(&#34;page&#34;)
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create a new view <code>resources/views/articles/index.edge</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;welcome&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @each(article in articles)
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h3</span><span class="p">&gt;</span>{{ article.title }}<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  @endeach
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p>Notice that we used the same section names in both <code>welcome.edge</code> and <code>index.edge</code>. As you would have guessed, we pass <code>articles</code> from the controller. Rest of the statements just take care of rendering the article content (ignore the empty <code>href</code> tag - we&rsquo;ll come back to this).</p>
<p>Let us change the <code>routes.ts</code> file to point to the <code>ArticlesController</code>. We can remove the previously used <code>/articles</code> route for now. The <code>routes.ts</code> file will now have -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Route</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Core/Route&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s2">&#34;/hello&#34;</span><span class="p">).</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;hello&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>Edit <code>index</code> function in <code>ArticlesController.ts</code> to return the view rather than plain data.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">index</span><span class="p">(</span><span class="nx">ctx</span>: <span class="kt">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">articles</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">Article</span><span class="p">.</span><span class="nx">all</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">view</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;articles/index&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">articles</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Here&rsquo;s what changed -</p>
<ol>
<li>We are returning the view instead of data</li>
<li>We pass the data along to the view (and the view can render data in a good way)</li>
</ol>
<p>Refresh the page and see the list of articles.</p>
<p><img loading="lazy" src="/2020/adonis-index-page.jpg" type="" alt="adonis-index-page"  /></p>
<h3 id="tie-articles-to-the-article-list">Tie articles to the article list</h3>
<p>We have to link the list of articles so that we can display content when the user clicks on the link.</p>
<blockquote>
<p>Web is just a bunch of links.</p>
<ul>
<li>Mr. Smarty Pants</li>
</ul>
</blockquote>
<p>Let us create a new detail page that can display article content. Create a new view <code>resources/views/articles/_id.edge</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;welcome&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>{{ article.title }}<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>{{ article.content }}<span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p>You know the drill by now - update controller to display this page, which in AdonisJS is the <code>show</code> method.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">show</span><span class="p">(</span><span class="nx">ctx</span>: <span class="kt">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">article</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">Article</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="nx">ctx</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">ctx</span><span class="p">.</span><span class="nx">view</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;articles/_id&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">article</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>Article.find(ctx.params.id)</code> finds a specific article by querying with <code>id</code>. Then, we return the view by passing the said article details to the view.</p>
<p>Remember that I had asked you to ignore the <code>href</code> tag earlier? Let us change that -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;welcome&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @each(article in articles)
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ route(&#39;ArticlesController.show&#39;, {id: article.id})}}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h3</span><span class="p">&gt;</span>{{ article.title }}<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  @endeach
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p>Navigate to the root and click on any news link to see the new detail page.</p>
<p><img loading="lazy" src="/2020/adonis-detail-page.jpg" type="" alt="adonis-detail-page"  /></p>
<p>We have now tied all loose ends -</p>
<ol>
<li><code>welcome</code> is just a container that shows the actual view <code>articles/index</code></li>
<li><code>articles/index.edge</code> shows a list of articles</li>
<li>When user hits the home page (<code>localhost:3333</code>), <code>route.ts</code> invokes <code>ArticlesController.index</code></li>
<li><code>ArticlesController.index</code> queries for all articles and passes it to <code>articles/index.edge</code> to render</li>
<li>Clicking on a link in <code>articles/index</code> will use a route helper to invoke <code>ArticlesController.show</code> and passes the article id to the view</li>
<li><code>ArticlesController.show</code> will return <code>articles/_id.edge</code> view that will display the article content</li>
</ol>
<p>At a high-level:</p>
<ol>
<li>Router ties the route in the URL (e.g. <code>/</code>, <code>/article/1</code>) to a specific action (or can render the view directly)</li>
<li>Actions are implemented in controllers</li>
<li>Controller queries for data and passes it to a view to render the UI</li>
</ol>
<p>We have created UI and functionality for listing posts and showing a specific post, but we have gone through 75% of all there is to learn :)</p>
<p>Before we go any further, let us style our application a bit.</p>
<h2 id="styling-your-adonisjs-app">Styling your AdonisJS app</h2>
<p>Styling a server-generated app is as simple as including the CSS libraries and sprinkling them classes everywhere. While styles can be as complex as they come, I will choose to use a simple, class-less style library in <a href="https://milligram.io/">Milligram</a>.</p>
<p>Add this one line to the base container.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span>
</span></span><span class="line"><span class="cl">  <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">/&gt;</span>
</span></span></code></pre></div><p>Let us create a new css file <code>public/css/styles.css</code> and add that to the mix for customisations. We will not quite discuss styling here - copy and paste CSS from the <a href="https://github.com/prashanth1k/newsie-adonisjs-sample-app/blob/master/public/css/styles.css">Github repo</a>. Add this file to the page.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span>
</span></span><span class="line"><span class="cl">  <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/css/styles.css&#34;</span> <span class="p">/&gt;</span>
</span></span></code></pre></div><p>While we are here, let us rename the container (<code>welcome.edge</code>) to <code>app.edge</code> since that is more near to what the file function is.</p>
<p>Remember to change references to <code>welcome.edge</code> in all views.</p>
<h2 id="enable-authentication">Enable Authentication</h2>
<p>We need our app to support authentication since only registered users can create news articles. Fortunately, Adonis has a powerful authentication module that comes alive with a few code changes.</p>
<p>First, install the additional packages required for auth.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i @adonisjs/auth@alpha phc-argon2 phc-bcrypt
</span></span></code></pre></div><p>Configure auth with the below command.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace invoke @adonisjs/auth
</span></span></code></pre></div><p>Select <code>Web</code> option since we are like to keep things simple. Follow post configuration instructions to change specific sections in <code>kernel.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">Server</span><span class="p">.</span><span class="nx">middleware</span><span class="p">.</span><span class="nx">register</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;Adonis/Core/BodyParserMiddleware&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;App/Middleware/SilentAuth&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Server</span><span class="p">.</span><span class="nx">middleware</span><span class="p">.</span><span class="nx">registerNamed</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">auth</span><span class="o">:</span> <span class="s2">&#34;App/Middleware/Auth&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h3 id="enable-ui-for-login--registration">Enable UI for Login &amp; Registration</h3>
<p>Change the base layout <code>app.edge</code> to include links to login &amp; logout links.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;navbar&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;logo&#34;</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/&#34;</span><span class="p">&gt;</span>Newsie<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/about&#34;</span><span class="p">&gt;</span>about<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        @if(auth.user)
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/logout&#34;</span> <span class="na">onclick</span><span class="o">=</span><span class="s">&#34;event.preventDefault();document.getElementById(&#39;logout&#39;).submit()&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            logout
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">form</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;logout&#34;</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;/logout&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;POST&#34;</span><span class="p">&gt;</span>{{ csrfField() }}<span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/articles/new&#34;</span><span class="p">&gt;</span>new<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        @else
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/login&#34;</span><span class="p">&gt;</span>login<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        @endif
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;content&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      @!section(&#34;page&#34;)
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    (c) Company 42
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">span</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;float:right&#34;</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://github.com/prashanth1k/newsie-adonisjs-sample-app&#34;</span><span class="p">&gt;</span>github<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Remember that edge file supports calculations and inclusion of variables. In addition, we can include simple conditional logic as well. <code> @if(auth.user)</code> checks if a specific object exists and renders the lines until <code>else</code> or <code>endif</code> if the condition is <code>true</code>. We are using the conditional rendering to show <code>login</code> link only if user is not logged in yet.</p>
<p><code>csrfField()</code> is a security function provided by AdonisJS to prevent cross-site forgery. We will use it for all update requests (e.g. POST, PUT, etc.)</p>
<h3 id="user-data-model">User Data Model</h3>
<p>Create user model similar to articles -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"> node ace make model User -cm
</span></span></code></pre></div><p>Change the table migration file <code>database/migrations/&lt;some_num&gt;_users.ts</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">BaseSchema</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Lucid/Schema&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">Users</span> <span class="kr">extends</span> <span class="nx">BaseSchema</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">protected</span> <span class="nx">tableName</span> <span class="o">=</span> <span class="s2">&#34;users&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">up() {</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">schema</span><span class="p">.</span><span class="nx">createTable</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">tableName</span><span class="p">,</span> <span class="p">(</span><span class="nx">table</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="nx">increments</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="nx">timestamps</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="kt">string</span><span class="p">(</span><span class="s2">&#34;email&#34;</span><span class="p">).</span><span class="nx">notNullable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="kt">string</span><span class="p">(</span><span class="s2">&#34;password&#34;</span><span class="p">,</span> <span class="mi">180</span><span class="p">).</span><span class="nx">notNullable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="kt">string</span><span class="p">(</span><span class="s2">&#34;name&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">table</span><span class="p">.</span><span class="kt">string</span><span class="p">(</span><span class="s2">&#34;remember_me&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">async</span> <span class="nx">down() {</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">schema</span><span class="p">.</span><span class="nx">dropTable</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">tableName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Run migrations -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace migration:run
</span></span></code></pre></div><p>Change <code>app/Models/user.ts</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">DateTime</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;luxon&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">BaseModel</span><span class="p">,</span> <span class="nx">column</span><span class="p">,</span> <span class="nx">beforeSave</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Lucid/Orm&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Hash</span> <span class="kr">from</span> <span class="s2">&#34;@ioc:Adonis/Core/Hash&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">User</span> <span class="kr">extends</span> <span class="nx">BaseModel</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">({</span> <span class="nx">isPrimary</span>: <span class="kt">true</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">id</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">.</span><span class="nx">dateTime</span><span class="p">({</span> <span class="nx">autoCreate</span>: <span class="kt">true</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">createdAt</span>: <span class="kt">DateTime</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">.</span><span class="nx">dateTime</span><span class="p">({</span> <span class="nx">autoCreate</span>: <span class="kt">true</span><span class="p">,</span> <span class="nx">autoUpdate</span>: <span class="kt">true</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">updatedAt</span>: <span class="kt">DateTime</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">name</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">email</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">password</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@column</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="nx">rememberMeToken?</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@beforeSave</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">static</span> <span class="kr">async</span> <span class="nx">hashPassword</span><span class="p">(</span><span class="nx">user</span>: <span class="kt">User</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">user</span><span class="p">.</span><span class="nx">$dirty</span><span class="p">.</span><span class="nx">password</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">user</span><span class="p">.</span><span class="nx">password</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">Hash</span><span class="p">.</span><span class="nx">make</span><span class="p">(</span><span class="nx">user</span><span class="p">.</span><span class="nx">password</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>hashPassword</code> will hash plain password so that we can securely store it in our database.</p>
<h3 id="user-login-and-registration-controllers">User Login and Registration Controllers</h3>
<p>Change code in <code>app/Controllers/UsersController.ts</code>.</p>
<h4 id="login">Login</h4>
<p>Add code to handle login events.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">login</span><span class="p">({</span> <span class="nx">request</span><span class="p">,</span> <span class="nx">response</span><span class="p">,</span> <span class="nx">auth</span><span class="p">,</span> <span class="nx">session</span> <span class="p">}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">await</span> <span class="nx">auth</span><span class="p">.</span><span class="nx">attempt</span><span class="p">(</span><span class="nx">request</span><span class="p">.</span><span class="nx">input</span><span class="p">(</span><span class="s1">&#39;email&#39;</span><span class="p">),</span> <span class="nx">request</span><span class="p">.</span><span class="nx">input</span><span class="p">(</span><span class="s1">&#39;password&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">session</span><span class="p">.</span><span class="nx">flash</span><span class="p">(</span><span class="s1">&#39;notification&#39;</span><span class="p">,</span> <span class="s1">&#39;Login failed. Check email/password &amp; retry.&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="s1">&#39;back&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span></code></pre></div><p>Note that -</p>
<ul>
<li><code>await auth.attempt()</code> tries to login using id/password provided by front-end</li>
<li><code>session.flash</code> helps send messages from the business layer back to UI. We will make use of <code>notification</code> in the edge file</li>
<li>successful login will direct user to <code>/</code> = home page. Errors will just go back to the login page</li>
</ul>
<h4 id="register">Register</h4>
<p>It is quite common to validate data sent by the frontend in controllers / models. AdonisJS provides an easy way to validate data but that is not included by default.</p>
<p>Let us install the Adonis Shield package to enable validation in our app -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i @adonisjs/shield@alpha --save
</span></span></code></pre></div><p>Configure shield.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node ace invoke @adonisjs/shield
</span></span></code></pre></div><p>Follow instructions to register <code>'Adonis/Addons/ShieldMiddleware'</code> in <code>start/kernel.ts</code> file.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">Server</span><span class="p">.</span><span class="nx">middleware</span><span class="p">.</span><span class="nx">register</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;Adonis/Core/BodyParserMiddleware&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;Adonis/Addons/ShieldMiddleware&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;App/Middleware/SilentAuth&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]);</span>
</span></span></code></pre></div><p>Now you can include functionality provided by shield in your edge files.</p>
<p>Add another method in <code>UsersController.ts</code> to support registration function -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">register</span><span class="p">({</span> <span class="nx">request</span><span class="p">,</span> <span class="nx">auth</span><span class="p">,</span> <span class="nx">response</span><span class="p">,</span> <span class="nx">session</span> <span class="p">}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">valSchema</span> <span class="o">=</span> <span class="nx">schema</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">email</span>: <span class="kt">schema.string</span><span class="p">({</span> <span class="nx">trim</span>: <span class="kt">true</span> <span class="p">},</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="nx">rules</span><span class="p">.</span><span class="kt">unique</span><span class="p">({</span> <span class="nx">table</span><span class="o">:</span> <span class="s1">&#39;users&#39;</span><span class="p">,</span> <span class="nx">column</span><span class="o">:</span> <span class="s1">&#39;email&#39;</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl">        <span class="nx">rules</span><span class="p">.</span><span class="nx">maxLength</span><span class="p">(</span><span class="mi">255</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="nx">rules</span><span class="p">.</span><span class="nx">email</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">      <span class="p">]),</span>
</span></span><span class="line"><span class="cl">      <span class="nx">password</span>: <span class="kt">schema.string</span><span class="p">({</span> <span class="nx">trim</span>: <span class="kt">true</span> <span class="p">},</span> <span class="p">[</span><span class="nx">rules</span><span class="p">.</span><span class="nx">maxLength</span><span class="p">(</span><span class="mi">180</span><span class="p">),</span> <span class="nx">rules</span><span class="p">.</span><span class="nx">required</span><span class="p">()]),</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">request</span><span class="p">.</span><span class="nx">validate</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">schema</span>: <span class="kt">valSchema</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">messages</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;email.unique&#39;</span><span class="o">:</span> <span class="s1">&#39;Email already exists&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;email.maxLength&#39;</span><span class="o">:</span> <span class="s1">&#39;Email can be upto 255 characters&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;email.email&#39;</span><span class="o">:</span> <span class="s1">&#39;Invalid email&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">user</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">User</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">email</span>: <span class="kt">data.email</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">password</span>: <span class="kt">data.password</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">await</span> <span class="nx">auth</span><span class="p">.</span><span class="nx">login</span><span class="p">(</span><span class="nx">user</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">session</span><span class="p">.</span><span class="nx">flash</span><span class="p">(</span><span class="s1">&#39;notification&#39;</span><span class="p">,</span> <span class="s1">&#39;Registered.&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span></code></pre></div><p>This is very similar to the login method, but has a few more goodies.</p>
<p><code>const valSchema = schema.create()</code> enables us to easily create custom validation rules and messages using Adonis Shield. We check whether the email already exists, email is a valid email string and whether it has max 255 characters. If all validations pass, we login the user and redirect them to the home page.</p>
<p>Both the methods described so far provide the control layer. We need to render the views as well.</p>
<h4 id="show-login-and-register-pages">Show Login and Register Pages</h4>
<p>Add two more methods to show login and registration screens.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">showLogin</span><span class="p">({</span> <span class="nx">view</span> <span class="p">}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">view</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;auth/login&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">user</span><span class="o">:</span> <span class="p">{</span> <span class="nx">email</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nx">password</span><span class="o">:</span> <span class="s1">&#39;&#39;</span> <span class="p">}</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">showRegister</span><span class="p">({</span> <span class="nx">view</span> <span class="p">}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">view</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s1">&#39;auth/register&#39;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">user</span><span class="o">:</span> <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nx">email</span><span class="o">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="nx">password</span><span class="o">:</span> <span class="s1">&#39;&#39;</span> <span class="p">}</span> <span class="p">})</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>We pass dummy objects like <code>user: { email: '', password: '' }</code> to demonstrate that we could pass predefault strings to the UI if desired.</p>
<p>Before we forget - code the logout event as well..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kr">public</span> <span class="kr">async</span> <span class="nx">logout</span><span class="p">({</span> <span class="nx">auth</span><span class="p">,</span> <span class="nx">response</span> <span class="p">}</span><span class="o">:</span> <span class="nx">HttpContextContract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">await</span> <span class="nx">auth</span><span class="p">.</span><span class="nx">logout</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="user-login-and-registration-ui">User Login and Registration UI</h3>
<p>Create edge views to enable user to login / register.</p>
<h4 id="sign-up-screen">Sign up screen</h4>
<p>Create a new file <code>resources/views/auth/register.edge</code>. Input below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kd">@layout</span><span class="p">(</span><span class="s2">&#34;app&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@section</span><span class="p">(</span><span class="s2">&#34;page&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;padding-left: 20%;padding-right: 20%&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-title&#34;</span><span class="p">&gt;</span><span class="nx">Sign</span> <span class="nx">up</span><span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">@if</span><span class="p">(</span><span class="nx">flashMessages</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="s1">&#39;errors.email&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{{</span><span class="nx">flashMessages</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;errors.email&#34;</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">@endif</span>
</span></span><span class="line"><span class="cl">    <span class="kd">@if</span><span class="p">(</span><span class="nx">flashMessages</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="s1">&#39;notification&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;info-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">{{</span><span class="nx">flashMessages</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;notification&#34;</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">@endif</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;{{ `/register`}}&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;POST&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{{</span> <span class="nx">csrfField</span><span class="p">()</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;name&#34;</span><span class="p">&gt;</span><span class="nx">Name</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{user.name}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;name&#34;</span> <span class="na">required</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span><span class="nx">Email</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{user.email}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;email&#34;</span> <span class="na">required</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;password&#34;</span><span class="p">&gt;</span><span class="nx">Password</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{user.password}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">required</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span><span class="p">&gt;</span><span class="nx">Sign</span> <span class="nx">up</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kd">@endsection</span>
</span></span></code></pre></div><p>Note that -</p>
<ol>
<li>We continue using <code>app.edge</code> as the base layout</li>
<li>We used <code>flashMessages</code> to provide a way to show error messages and notifications on the UI</li>
</ol>
<h4 id="login-screen">Login screen</h4>
<p>Create a new file <code>resources/views/auth/register.edge</code>. Input below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="kd">@layout</span><span class="p">(</span><span class="s2">&#34;app&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">@section</span><span class="p">(</span><span class="s2">&#34;page&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;padding-left: 20%;padding-right: 20%&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-title&#34;</span><span class="p">&gt;</span><span class="nx">Login</span><span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="kd">@if</span><span class="p">(</span><span class="nx">flashMessages</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="s1">&#39;errors.title&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">{{</span><span class="nx">flashMessages</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;errors.title&#34;</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">@endif</span>
</span></span><span class="line"><span class="cl">    <span class="kd">@if</span><span class="p">(</span><span class="nx">flashMessages</span><span class="p">.</span><span class="nx">has</span><span class="p">(</span><span class="s1">&#39;notification&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;info-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">{{</span><span class="nx">flashMessages</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;notification&#34;</span><span class="p">)}}</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">@endif</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;{{ `/login`}}&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;POST&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">{{</span> <span class="nx">csrfField</span><span class="p">()</span> <span class="p">}}</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span><span class="nx">Email</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{user.email}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;email&#34;</span> <span class="na">required</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;password&#34;</span><span class="p">&gt;</span><span class="nx">Password</span><span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{user.password}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;password&#34;</span> <span class="na">required</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span><span class="p">&gt;</span><span class="nx">Login</span><span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-meta&#34;</span><span class="p">&gt;</span> <span class="nx">Not</span> <span class="nx">registered</span><span class="o">?</span> <span class="p">&lt;</span><span class="nt">a</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;grey&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/register&#34;</span><span class="p">&gt;</span><span class="nx">Sign</span> <span class="nx">up</span><span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kd">@endsection</span>
</span></span></code></pre></div><h3 id="user-routes">User Routes</h3>
<p>Add below routes to <code>start/routes.ts</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/login&#34;</span><span class="p">,</span> <span class="s2">&#34;UsersController.login&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/login&#34;</span><span class="p">,</span> <span class="s2">&#34;UsersController.showLogin&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/register&#34;</span><span class="p">,</span> <span class="s2">&#34;UsersController.register&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/register&#34;</span><span class="p">,</span> <span class="s2">&#34;UsersController.showRegister&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/logout&#34;</span><span class="p">,</span> <span class="s2">&#34;UsersController.logout&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>And.. you are done just like that. Try out logging in / signin up to use the application.</p>
<h2 id="do-more-with-articles">Do More With Articles</h2>
<p>While our articles functionality is all powerful, our app still lacks a few things-</p>
<ol>
<li>We can provide a way to see &ldquo;proper&rdquo; URLs for individual articles. A &ldquo;slug&rdquo; is a URL-friendly article id that is easier to read</li>
<li>Articles do not have any formatting now. We will support markdown content editing for easier content authoring / assimilation</li>
<li>Make the user experience and navigation better</li>
</ol>
<p>Let&rsquo;s get to it.</p>
<h3 id="list-articles">List Articles</h3>
<p>The home page shows a bunch of links right now. Change that to display news cards with a title and content preview.</p>
<p>Modify <code>resources/views/articles/index.edge</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;app&#34;) 
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">section</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;hero&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;column&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>Welcome to newsie!<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;subtitle&#34;</span><span class="p">&gt;</span>Positive news across the world.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;column center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">img</span>
</span></span><span class="line"><span class="cl">        <span class="na">src</span><span class="o">=</span><span class="s">&#34;/images/smiley.png&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">style</span><span class="o">=</span><span class="s">&#34;width:150px;height:150px;margin:auto;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">class</span><span class="o">=</span><span class="s">&#34;column&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row row-wrap&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @each(article in articles)
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;column column-50&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">aside</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;card&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      @if(auth.user)
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/articles/{{article.id}}/edit&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-meta-small&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&gt;</span>edit<span class="p">&lt;/</span><span class="nt">a</span>
</span></span><span class="line"><span class="cl">      <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      @endif
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;{{ route(&#39;ArticlesController.show&#39;, {id: article.slug}) }}&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          {{ article.title }}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-meta&#34;</span><span class="p">&gt;</span>Updated: {{article.publishDate}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>{{{ article.content ? article.content.substring(0,100) : &#34;&#34; }}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">aside</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @endeach
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p>A couple of interesting things to note -</p>
<ol>
<li>There is an <code>edit</code> link at the top of each article. This shows up only for logged in users</li>
<li>We use a &ldquo;route helper&rdquo; in <code>&lt;a href=&quot;{{ route('ArticlesController.show', {id: article.slug}) }}&quot;&gt;</code> to directly refer to the AdonisJS route rather than use the URL to reach the article detail view</li>
</ol>
<h3 id="show-article-detail">Show Article Detail</h3>
<p>There are two changes to be done at this time -</p>
<ul>
<li>Treat content in <code>content</code> as markdown. To render markdown in HTML, we use a package called &ldquo;marked&rdquo;.</li>
<li>Let us start using a &ldquo;slug&rdquo; instead of a cryptic &ldquo;id&rdquo; field in URL. We will use a package called &ldquo;slugify&rdquo; to convert title to a slug</li>
</ul>
<p>Install packages -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i marked slugify
</span></span></code></pre></div><p>Modify the model <code>app/Models/Article.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="c1">// other lines
</span></span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">Article</span> <span class="kr">extends</span> <span class="nx">BaseModel</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// other lines
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@computed</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">get</span> <span class="nx">fmtContent() {</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">marked</span> <span class="o">=</span> <span class="kr">require</span><span class="p">(</span><span class="s2">&#34;marked&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">content</span> <span class="o">?</span> <span class="nx">marked</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">content</span><span class="p">)</span> <span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// other lines
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kd">@beforeSave</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="kr">public</span> <span class="kr">static</span> <span class="kr">async</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">article</span>: <span class="kt">Article</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">slugify</span> <span class="o">=</span> <span class="kr">require</span><span class="p">(</span><span class="s2">&#34;slugify&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">article</span><span class="p">.</span><span class="nx">$original</span><span class="p">.</span><span class="nx">slug</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">article</span><span class="p">.</span><span class="nx">$attributes</span><span class="p">.</span><span class="nx">slug</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">article</span><span class="p">.</span><span class="nx">slug</span> <span class="o">=</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">article</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span> <span class="p">{</span> <span class="nx">lower</span>: <span class="kt">true</span><span class="p">,</span> <span class="nx">strict</span>: <span class="kt">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">article</span><span class="p">.</span><span class="nx">$dirty</span><span class="p">.</span><span class="nx">slug</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">article</span><span class="p">.</span><span class="nx">slug</span> <span class="o">=</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">article</span><span class="p">.</span><span class="nx">slug</span><span class="p">,</span> <span class="p">{</span> <span class="nx">lower</span>: <span class="kt">true</span><span class="p">,</span> <span class="nx">strict</span>: <span class="kt">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>The changes are fairly straight-forward. We created a computed field to convert markdown to HTML (which can inturn be used in our views), and auto-filled the slug before saving the record.</p>
<p>Change <code>resources/views/articles/_id.edge</code> that shows the detail article to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;app&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @if(auth.user)
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-meta-small&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/articles/{{article.id}}/edit&#34;</span><span class="p">&gt;</span>edit<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  @endif
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h1</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-title&#34;</span><span class="p">&gt;</span>{{ article.title }}<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">article</span><span class="p">&gt;</span>{{{ article.fmtContent }}}<span class="p">&lt;/</span><span class="nt">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p>Note that we have now used <code>fmtContent</code> and <code>{{{ }}}</code> notation to directly create HTML based on the field content.</p>
<h3 id="create-article">Create Article</h3>
<p>Create a new view <code>resources/views/articles/new.edge</code> and input below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;app&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-title&#34;</span><span class="p">&gt;</span>New Article<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @if(flashMessages.has(&#39;errors.title&#39;))
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-text&#34;</span><span class="p">&gt;</span>{{flashMessages.get(&#34;errors.title&#34;)}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @endif @if(flashMessages.has(&#39;notification&#39;))
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;info-text&#34;</span><span class="p">&gt;</span>{{flashMessages.get(&#34;notification&#34;)}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @endif
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;/articles/&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;POST&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      {{ csrfField() }}
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>Title<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{article.title || &#39;&#39;}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;title&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;slug&#34;</span><span class="p">&gt;</span>Slug<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{article.slug || &#39;&#39;}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;slug&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;content&#34;</span><span class="p">&gt;</span>Post Content<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">textarea</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;content&#34;</span> <span class="na">rows</span><span class="o">=</span><span class="s">&#34;10&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{ article.content || &#39;&#39; }}
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">textarea</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span><span class="p">&gt;</span>Save<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p>Nothing we haven&rsquo;t seen before.</p>
<h3 id="update-article">Update Article</h3>
<p>Create a new view <code>resources/views/articles/edit.edge</code> to edit a given article. In our case, the code here will be almost same as <code>new</code>. Input below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="c">&lt;!-- prettier-ignore --&gt;</span>
</span></span><span class="line"><span class="cl">@layout(&#34;app&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@section(&#34;page&#34;)
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;article-title&#34;</span><span class="p">&gt;</span>Update Article<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">article</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @if(flashMessages.has(&#39;errors.title&#39;))
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;error-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{flashMessages.get(&#34;errors.title&#34;)}}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @endif
</span></span><span class="line"><span class="cl">    @if(flashMessages.has(&#39;notification&#39;))
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;info-text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            {{flashMessages.get(&#34;notification&#34;)}}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    @endif
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;{{ `/articles/${article.id}?_method=PATCH`}}&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;POST&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        {{ csrfField() }}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>Title<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{article.title}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;slug&#34;</span><span class="p">&gt;</span>Slug<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;{{article.slug}}&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;slug&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;content&#34;</span><span class="p">&gt;</span>Post Content<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">textarea</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;content&#34;</span> <span class="na">rows</span><span class="o">=</span><span class="s">&#34;10&#34;</span><span class="p">&gt;</span>{{article.content}}<span class="p">&lt;/</span><span class="nt">textarea</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span><span class="p">&gt;</span>Save<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">@endsection
</span></span></code></pre></div><p><code>_method=PATCH</code> in form action is what is called as &ldquo;method spoofing&rdquo;. This allows us to send a <code>patch</code> method in the HTTP POST request. You need to enable method spoofing in AdonisJS by making the below configuration change in <code>app.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">allowMethodSpoofing</span>: <span class="kt">true</span><span class="p">;</span>
</span></span></code></pre></div><h3 id="article-routes">Article Routes</h3>
<p>Finally, change the article routes.</p>
<p>Let us -</p>
<ol>
<li>Support edit, update and new routes to views created so far</li>
<li>Require user to be logged in to create or update articles</li>
</ol>
<p>Modify <code>app/start/routes.ts</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ts" data-lang="ts"><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s2">&#34;/about&#34;</span><span class="p">).</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;about&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="nx">group</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/new&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.create&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/:id/edit&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.edit&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Route</span><span class="p">.</span><span class="nx">patch</span><span class="p">(</span><span class="s2">&#34;/:id&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.update&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Route</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.store&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">prefix</span><span class="p">(</span><span class="s2">&#34;articles&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">.</span><span class="nx">middleware</span><span class="p">(</span><span class="s2">&#34;auth&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Route</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/articles/:id&#34;</span><span class="p">,</span> <span class="s2">&#34;ArticlesController.show&#34;</span><span class="p">);</span>
</span></span></code></pre></div><p>The auth middleware included in the route group takes care of checking for valid user and redirecting user to login screen if not already logged in. Anonymous users can just view the article list and browse articles.</p>
<p>We are done with all changes required to provide a cool-looking app to create, edit and view news articles.</p>
<h2 id="finis">Finis</h2>
<p>While getting to the finish line took a few hundred lines, you will get used to the steps required to enable functionality in AdonisJS in no time. If you have experience with other bare-bones frameworks, you will come to appreciate the ease of customisation and the structured/standardised coding approach that makes life easier for everyone.</p>
<p>Go ahead - make your news app available to the world, spread positivity and create more awesome apps.</p>
<p>The repository with full code is at <a href="https://github.com/prashanth1k/newsie-adonisjs-sample-app">https://github.com/prashanth1k/newsie-adonisjs-sample-app</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Create a Blog With Express, Markdown and Postgres</title>
      <link>https://techformist.com/create-blog-express-markdown-postgres/</link>
      <pubDate>Wed, 09 Dec 2020 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/create-blog-express-markdown-postgres/</guid>
      <description>&lt;p&gt;Express is like a dear friend who does not leave your side during happy or sad times in your life. She may not help you reach enlightenment, but she&amp;rsquo;s there and she&amp;rsquo;s super supportive. And, that&amp;rsquo;s all you need many a time.&lt;/p&gt;
&lt;p&gt;In this post we create a blog with ExpressJS and friends - oh how exciting. Our blog is going to look beautiful with -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ExpressJS (of course)&lt;/li&gt;
&lt;li&gt;Ejs for templating. Has SSR built-in - for you SPA crazies&lt;/li&gt;
&lt;li&gt;Supports content authoring in markdown&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&amp;rsquo;s how it looks -&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Express is like a dear friend who does not leave your side during happy or sad times in your life. She may not help you reach enlightenment, but she&rsquo;s there and she&rsquo;s super supportive. And, that&rsquo;s all you need many a time.</p>
<p>In this post we create a blog with ExpressJS and friends - oh how exciting. Our blog is going to look beautiful with -</p>
<ol>
<li>ExpressJS (of course)</li>
<li>Ejs for templating. Has SSR built-in - for you SPA crazies</li>
<li>Supports content authoring in markdown</li>
</ol>
<p>Here&rsquo;s how it looks -</p>
<p><img loading="lazy" src="/2020/express-postgress-blog-sample-app.gif" type="" alt="express-postgress-blog-sample-app"  /></p>
<h2 id="why-expressjs">Why ExpressJS?</h2>
<p>First, I am kind of sad that this question came up - I mean, re-read [paragraph 1]. But since you asked - I continue to chose ExpressJS because-</p>
<ol>
<li>It is so darn easy to start and continue rocking</li>
<li>Large community = lot of solved problems</li>
<li>A tonne of useful code, plugins, middleware and so on</li>
</ol>
<p>I am more firmly in the SPA camp nowadays and love the productivity of a Vue application + standard styling libraries. But hey, Express and server-side templating keeps things real simple.</p>
<h2 id="get-started-setup">Get Started: Setup</h2>
<p>Install <a href="https://nodejs.org/en/download/">Node</a> and <a href="https://code.visualstudio.com/download">VSCode</a> if you don&rsquo;t already have them.</p>
<p>Create a new folder in some corner of your computer, name it <code>bloggie</code>, and open VSCode in that folder.</p>
<p>Open a terminal (in Windows, Mac or in VSCode - I don&rsquo;t judge), ensure that you are in the project folder, and key in the command to initiate the project.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm init -y
</span></span></code></pre></div><p><img loading="lazy" src="/2020/express-blog-app-start.jpg" type="" alt="express-blog-app-start"  /></p>
<p>It&rsquo;s time for that pat on your back - 25% of the work is already done.</p>
<p>Install a few packages that will be used in the project. We will see their purpose in a bit.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save express ejs pg knex dotenv
</span></span></code></pre></div><p>Here&rsquo;s how the packages will be used..</p>
<ul>
<li><code>express</code>: App server</li>
<li><code>ejs</code>: Templating language that allows us to specify variables in standard HTML</li>
<li><code>pg</code>: Connect and run queries on postgres DB</li>
<li><code>dotenv</code>: Get variables from an environment file</li>
</ul>
<p>Install dev dependencies, which are packages used to get stuff done during development, but are not needed in production.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save-dev nodemon knex
</span></span></code></pre></div><p>Here we have -</p>
<ul>
<li><code>nodemon</code>: automatically restarts server when files are changes</li>
<li><code>knex</code>: Query builder that makes writing dynamic queries a wee bit easier</li>
</ul>
<p>You can install <code>knex</code> globally with <code>npm i -g knex</code> if you are going to use knex commands every now and then. The advantage of using global knex is that you don&rsquo;t need to explicitly reference knex within <code>node_modules</code>. Either ways, it is a good idea to include knex as an explicit dependency to also let others know of its gracious presence.</p>
<p>Create a folder in the project root folder and call it <code>public</code>. This folder will host all the assets exposed to the internet - like css, images, etc.</p>
<p>Next, install Postgres database server. The easiest way to do it is to download <a href="https://laragon.org/download/index.html">Laragon</a>, and click on a few buttons to install Postgres database.</p>
<p>We now have everything to get started.</p>
<h2 id="getting-started-first-steps">Getting Started: First Steps</h2>
<p>Create a new file in the project folder called <code>app.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// setup
</span></span></span><span class="line"><span class="cl"><span class="nx">require</span><span class="p">(</span><span class="s2">&#34;dotenv&#34;</span><span class="p">).</span><span class="nx">config</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s2">&#34;view engine&#34;</span><span class="p">,</span> <span class="s2">&#34;ejs&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="kr">static</span><span class="p">(</span><span class="s2">&#34;public&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">urlencoded</span><span class="p">({</span> <span class="nx">extended</span><span class="o">:</span> <span class="kc">false</span> <span class="p">}));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">9000</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;App listening on port 9000.&#34;</span><span class="p">));</span>
</span></span></code></pre></div><p>With a few lines of code we created an Express server.</p>
<ul>
<li><code>require(&quot;dotenv&quot;).config()</code> allows us to define and use environment variables</li>
<li><code>app.set(&quot;view engine&quot;, &quot;ejs&quot;)</code> lets use <code>ejs</code> templating engine, which is a way to introduce variables within HTML</li>
<li><code>app.use(express.static(&quot;public&quot;));</code> enables us to store static assets in <code>public</code> folder and use that in our app</li>
<li><code>app.use(express.urlencoded({ extended: false }))</code> will allow us to use parameters in the URL - we will see more of this</li>
</ul>
<p>Include a command in your <code>package.json</code> to run your app.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;bloggie&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;1.0.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;main&#34;</span><span class="p">:</span> <span class="s2">&#34;app.js&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;scripts&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;dev&#34;</span><span class="p">:</span> <span class="s2">&#34;nodemon app.js&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// other lines
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>You can now start your express app with the command -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm run dev
</span></span></code></pre></div><p>See the line <code>App listening on port 9000.</code> and rejoice. Try making any changes to a file and see the server automatically restart - ah, the joy of modern programming.</p>
<h2 id="create-database">Create Database</h2>
<p>Any modern web app has several layers to it. We typically -</p>
<ul>
<li>design &ldquo;top-down&rdquo;: think about how your app flows, how screens are used and drill-down to specifics - where the business logic is implemented and data gets stored</li>
<li>develop &ldquo;bottom-up&rdquo;: start assembling blocks from the bottom layer and build out</li>
</ul>
<p>So, let&rsquo;s start creating them tables. <code>knex</code> makes it a breeze.</p>
<p>Get started by creating the knex init file - <code>knexfile.js</code>. You can do that by entering the below command..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npx knex init
</span></span></code></pre></div><p>.. or reference knex using the full path relative to your project root folder.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">node_modules/.bin/knex init
</span></span></code></pre></div><p>If you have installed <code>knex</code> globally, you could simply use <code>knex</code> like any other DOS command in the terminal.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">knex init
</span></span></code></pre></div><p>Change <code>knexfile.js</code> file to specify our database and connection settings -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// Update with your config settings.
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">development</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">client</span><span class="o">:</span> <span class="s2">&#34;postgresql&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">connection</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">database</span><span class="o">:</span> <span class="s2">&#34;bloggie&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">user</span><span class="o">:</span> <span class="s2">&#34;postgres&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">password</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">pool</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">min</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">max</span><span class="o">:</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">migrations</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">tableName</span><span class="o">:</span> <span class="s2">&#34;knex_migrations&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">directory</span><span class="o">:</span> <span class="s2">&#34;data/migrations&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>The configuration is fairly straight forward -</p>
<ol>
<li>Specify a database and user id/ password to connect</li>
<li>Specify a pool. A pool persists connections even after a transaction is completed and allows the next transaction to reuse connection. This saves execution time</li>
<li>We also specify the name of the table that stores the migration history - <code>knex_migrations</code>, and the directory where table definitions and seed data is stored - <code>data/migrations</code></li>
</ol>
<p>Create <code>data</code> and <code>migrations</code> directories.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">mkdir</span> data
</span></span><span class="line"><span class="cl"><span class="k">mkdir</span> data/migrations
</span></span></code></pre></div><p>Create your first migration file called <code>&lt;wierd_number&gt;_init.js</code>. A migration file allows you to simplify creating tables and also version controlling table changes made at different times.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">knex migrate:make init
</span></span></code></pre></div><p>Change the file to include table definitions. We will create a table to store blog posts and call it <code>posts</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">exports</span><span class="p">.</span><span class="nx">up</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">knex</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">knex</span><span class="p">.</span><span class="nx">schema</span><span class="p">.</span><span class="nx">createTable</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">table</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">increments</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">timestamp</span><span class="p">(</span><span class="s2">&#34;created_at&#34;</span><span class="p">).</span><span class="nx">defaultTo</span><span class="p">(</span><span class="nx">knex</span><span class="p">.</span><span class="nx">fn</span><span class="p">.</span><span class="nx">now</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">timestamp</span><span class="p">(</span><span class="s2">&#34;updated_at&#34;</span><span class="p">).</span><span class="nx">defaultTo</span><span class="p">(</span><span class="nx">knex</span><span class="p">.</span><span class="nx">fn</span><span class="p">.</span><span class="nx">now</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">string</span><span class="p">(</span><span class="s2">&#34;title&#34;</span><span class="p">).</span><span class="nx">notNullable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">text</span><span class="p">(</span><span class="s2">&#34;content&#34;</span><span class="p">).</span><span class="nx">notNullable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">string</span><span class="p">(</span><span class="s2">&#34;slug&#34;</span><span class="p">,</span> <span class="mi">100</span><span class="p">).</span><span class="nx">unique</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nx">table</span><span class="p">.</span><span class="nx">string</span><span class="p">(</span><span class="s2">&#34;tags&#34;</span><span class="p">,</span> <span class="mi">100</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">exports</span><span class="p">.</span><span class="nx">down</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">knex</span><span class="p">,</span> <span class="nb">Promise</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">knex</span><span class="p">.</span><span class="nx">schema</span><span class="p">.</span><span class="nx">dropTable</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Next, let us apply this migration to the database.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">knex migrate:up
</span></span></code></pre></div><p>If everything goes well we will see table <code>posts</code> created in the database. You can verify it by connecting to your Postgres DB using database client programs like pgadmin4 (typically installed with Postgres in dev environment) or <a href="https://www.heidisql.com/">HeidiSQL</a>.</p>
<p>Before we go any further, create a file to facilitate easy import of knex libraries in our project - <code>data/db.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">environment</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_ENV</span> <span class="o">||</span> <span class="s2">&#34;development&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">config</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;../knexfile.js&#34;</span><span class="p">)[</span><span class="nx">environment</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;knex&#34;</span><span class="p">)(</span><span class="nx">config</span><span class="p">);</span>
</span></span></code></pre></div><p>You can test the connection by adding following lines in <code>app.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">db</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;./data/db&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;posts: &#34;</span><span class="p">,</span> <span class="nx">posts</span><span class="p">);</span>
</span></span></code></pre></div><p>This should output an empty array since the table does not have any rows yet. You can delete the above lines once testing is complete - we don&rsquo;t quite need them.</p>
<h2 id="routes-in-express">Routes in Express</h2>
<p>Remember that Express server is running on port 9000? Go to a browser and enter <code>http://localhost:9000</code> to see a blank page. Real-world web applications do magic with these URLs - you could have -</p>
<ul>
<li><code>http://localhost:9000/blog</code>: to show posts from your blog</li>
<li><code>http://localhost:9000/users</code>: to display all users of your app</li>
</ul>
<p>Of course you have to build functionality in your server to provide information back to user when she enters the URL. These URLs are what are called routes for your app. ExpressJS can identify routes and you can enter your own functions to call for specific routes.</p>
<p>Just add following lines to <code>app.js</code> to create a new route -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/hello&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s2">&#34;hello world&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Save the file and go to <code>http://localhost:9000/hello</code> in your browser to see <code>hello world</code> message.</p>
<p>An app can have many routes and it is going to make our <code>app.js</code> look bad. Let&rsquo;s put these routes in a different file. Create a new folder called <code>routes</code> in project root and create a file therein called <code>index.js</code>. Fill this file with the same code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/hello&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s2">&#34;hello world&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>Import this file in <code>app.js</code>..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// setup
</span></span></span><span class="line"><span class="cl"><span class="nx">require</span><span class="p">(</span><span class="s2">&#34;dotenv&#34;</span><span class="p">).</span><span class="nx">config</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="kr">static</span><span class="p">(</span><span class="s2">&#34;public&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">urlencoded</span><span class="p">({</span> <span class="nx">extended</span><span class="o">:</span> <span class="kc">false</span> <span class="p">}));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;./routes/index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="nx">router</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">9000</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;App listening on port 9000.&#34;</span><span class="p">));</span>
</span></span></code></pre></div><p>While rest of the lines remain the same as earlier, <code>app.use(&quot;/&quot;, router);</code> will signify that the new route will be available at <code>/</code>. If you had typed <code>/blog</code> instead, we could have specified routes only applicable to a blog. For e.g. <code>/blog/post-1</code>, <code>/blog</code>, <code>/blog/post-2</code>, etc.</p>
<p>Routes by themselves can execute some code and send the response back to the caller. But, that&rsquo;s no joy - we need to display information in a structured manner on a page. Enter <code>views</code>.</p>
<h2 id="views-in-express">Views in Express</h2>
<p>Views can be simple HTML pages that display any information. In our example we use a templating language (<code>ejs</code>) to create HTML and include variables in the HTML. These variables are substituted at runtime by values from database, disk or from external API calls.</p>
<p>To use <code>ejs</code> we need to tell Express that. Change <code>app.js</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// setup
</span></span></span><span class="line"><span class="cl"><span class="nx">require</span><span class="p">(</span><span class="s2">&#34;dotenv&#34;</span><span class="p">).</span><span class="nx">config</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="s2">&#34;view engine&#34;</span><span class="p">,</span> <span class="s2">&#34;ejs&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="kr">static</span><span class="p">(</span><span class="s2">&#34;public&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">urlencoded</span><span class="p">({</span> <span class="nx">extended</span><span class="o">:</span> <span class="kc">false</span> <span class="p">}));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;./routes/index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="nx">router</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">9000</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;App listening on port 9000.&#34;</span><span class="p">));</span>
</span></span></code></pre></div><p>Create a new view <code>hello.ejs</code> in <code>&lt;project_root&gt;/views/</code> folder. Add below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>hello world<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Change the <code>hello</code> route in <code>routes/index.js</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/hello&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;hello&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>Visit <code>http://localhost:9000/hello</code> to see the <code>hello world</code> message.</p>
<p>So far you have seen how routes work, how to interact with database, and how to create views and display information. These are the only building blocks we need - let&rsquo;s put them together for our blog.</p>
<h2 id="understand-routes-for-a-blog">Understand routes for a Blog</h2>
<p>What exactly can you do with a blog?</p>
<ul>
<li>Display posts</li>
<li>View a specific post</li>
<li>Write a post</li>
<li>Update a post</li>
<li>Delete a post</li>
</ul>
<p>Each of these actions will have a specific route in Express. Let&rsquo;s start with displaying a list of posts.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">db</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;../data/db&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">slugify</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;slugify&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">marked</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;marked&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">domPurify</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;dompurify&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">JSDOM</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;jsdom&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">purify</span> <span class="o">=</span> <span class="nx">domPurify</span><span class="p">(</span><span class="k">new</span> <span class="nx">JSDOM</span><span class="p">().</span><span class="nb">window</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// const results = await db.query(&#34;select * from posts&#34;);
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// res.send({ rows: results.rows });
</span></span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">orderBy</span><span class="p">(</span><span class="s2">&#34;created_at&#34;</span><span class="p">,</span> <span class="s2">&#34;desc&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/index&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">posts</span><span class="o">:</span> <span class="nx">posts</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><p>We are pointing two routes <code>/</code> (<code>http://localhost:9000</code>) and <code>/blog</code> (<code>http://localhost:9000/blog</code>) to two views <code>index</code> and <code>blog/index</code> respectively.</p>
<p>Let us add the two views.</p>
<p>Create a new view <code>views/index.ejs</code>, which will serve as the home page for the app.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    Head section this is
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span><span class="p">&gt;</span>Link 1<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span><span class="p">&gt;</span>Link 2<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-weight:800&#34;</span><span class="p">&gt;</span>Welcome to Bloggie<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-meta&#34;</span><span class="p">&gt;</span>&#39;tis where magic happens.<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span><span class="p">&gt;&lt;</span><span class="nt">button</span><span class="p">&gt;</span>Go to Blog!<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span>(c) Bloggie Blog.<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create a new view <code>views/blog/index.ejs</code> to display a list of posts.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    Head section this is
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span><span class="p">&gt;</span>Link 1<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span><span class="p">&gt;</span>Link 2<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-weight:800&#34;</span><span class="p">&gt;</span>List of Posts<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 1<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 2<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 3<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span>(c) Bloggie Blog.<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>You can now visit the URLs <code>/</code> and <code>/blog</code> to see these views. You may have observed that we have repeated information in sections like <code>head</code>, <code>footer</code> etc. <code>ejs</code> provides a good way to reuse sections by creating them in one place and including them in any other views as required.</p>
<p>We can easily do that for our views. First create a reusable &ldquo;partial file&rdquo; called <code>views/partials/head.ejs</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;UTF-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width, initial-scale=1.0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>My Super Blog<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create a second partial for navigation <code>views/partials/nav.ejs</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">header</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;text-align: center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;site-title&#34;</span><span class="p">&gt;</span>My Super Blog<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/&#34;</span><span class="p">&gt;</span>Home<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span> | <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span><span class="p">&gt;</span>Blog<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span> |
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://github.com/prashanth1k/bloggie&#34;</span><span class="p">&gt;</span>GitHub<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Create another partial for footer <code>views/partials/footer.ejs</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">hr</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">p</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;text-align:center; color:grey; font-size: small;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  © 2020-Infinity My Super Blog
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>We now include these partials in our views.</p>
<p>Our <code>index.ejs</code> will change to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;./partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;./partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-weight:800&#34;</span><span class="p">&gt;</span>Welcome to Bloggie<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-meta&#34;</span><span class="p">&gt;</span>&#39;tis where magic happens.<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span><span class="p">&gt;&lt;</span><span class="nt">button</span><span class="p">&gt;</span>Go to Blog!<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;./partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The <code>&lt;%- %&gt;</code> tags allow you to include variables, values and functions. Here we use <code>include</code> statement to include another <code>ejs</code> file &ldquo;as is&rdquo; - meaning, the target <code>ejs</code> file will be copied/pasted in the parent &ldquo;in full&rdquo; at runtime.</p>
<p>The blog list page <code>blog/index.ejs</code> will change to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;./partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;./partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;font-weight:800&#34;</span><span class="p">&gt;</span>List of Posts<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 1<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 2<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span>Post 3<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;./partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The end result will be the same as earlier.</p>
<p>Since we are on the topic of views and views are about displaying information in a beautiful way - let us also include some styles.</p>
<p>Change <code>views/partials/head.ejs</code> to -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;UTF-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;viewport&#34;</span> <span class="na">content</span><span class="o">=</span><span class="s">&#34;width=device-width, initial-scale=1.0&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span>
</span></span><span class="line"><span class="cl">  <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text/css&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/css/styles.css&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;preconnect&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://fonts.gstatic.com&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span>
</span></span><span class="line"><span class="cl">  <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;800&amp;display=swap&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>My Super Blog<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span></code></pre></div><p><code>milligram.css</code> is a nice, classless styling library. It allows you to style your apps without adding any (or many) styling classes and has sensible defaults for standard HTML elements. We will include additional styling for our app in a new file called <code>/css/styles.css</code>. Check out the <a href="https://github.com/prashanth1k/bloggie">Github repo</a> for contents of <code>styles.css</code> - we will not be discussing any details here.</p>
<p>Pull in Open Sans Google fonts just because you can. You can use any font that you like.</p>
<h2 id="routes-for-your-blog-app">Routes for your Blog App</h2>
<p>Now that we have grasped the basics of routes and views, let us start adding routing logic for all possible transactions by changing <code>routes/index.js</code>.</p>
<h3 id="base-structure-of-routes">Base structure of routes</h3>
<p>The basic structure of routes remains as-is. We will add a DB reference to enable us to query or update database for specific route transactions.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;express&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">router</span> <span class="o">=</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Router</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">db</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;../data/db&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;index&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">router</span><span class="p">;</span>
</span></span></code></pre></div><h3 id="display-a-list-of-posts">Display a list of posts</h3>
<p>Add route to show posts -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">posts</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">orderBy</span><span class="p">(</span><span class="s2">&#34;created_at&#34;</span><span class="p">,</span> <span class="s2">&#34;desc&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/index&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">posts</span><span class="o">:</span> <span class="nx">posts</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>All we are doing here is to -</p>
<ul>
<li>get content from <code>posts</code> table in database <code>db.from(&quot;posts&quot;)</code> ordered by created date</li>
<li>render the view <code>blog/index</code>. Pass data from database to the view</li>
</ul>
<p>We have already seen how to use variable values in the view - we will see actual code in the next section.</p>
<h3 id="display-a-specific-post">Display a specific post</h3>
<p>Create a route/method to &ldquo;show&rdquo; a specific blog post.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog/:id&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">post</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">id</span><span class="p">).</span><span class="nx">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/show&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">post</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>See the string <code>:id</code> in route url? This implies that <code>id</code> is a variable. For e.g. the URL can be <code>http://localhost:9000/blog/1</code> (id = 1), <code>http://localhost:9000/blog/42</code> (id = 42), and so on.</p>
<p>We query database for the specific id passed in the URL and, as was earlier, provide the data to the view.</p>
<p>While using <code>id</code> simply works, URLs with ids are not really user-friendly. Let us change it to include a URL-friendly version of our post title (called <code>slug</code>). Slug is a distinct column we created for the purpose, and we will use that column instead of <code>id</code>. For e.g. a post with title &ldquo;Hello World!&rdquo; can have the slug <code>hello-world</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog/:slug&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">post</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;slug&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">slug</span><span class="p">).</span><span class="nx">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/show&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">post</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>Let&rsquo;s do one more thing while we are on this topic. Let us allow user to type content in markdown. This is not a problem while saving the record since we save the entries as-is, but we should render markdown as formatted HTML when showing the blog post. We can do that using a library called <code>marked</code> and combining that with a package or two to sanitize the HTML (<code>purify</code> / <code>jsdom</code>).</p>
<p>Install package -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save marked dompurify marked jsdom
</span></span></code></pre></div><p>Include the libraries in our route code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">marked</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;marked&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">domPurify</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;dompurify&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="p">{</span> <span class="nx">JSDOM</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&#34;jsdom&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">purify</span> <span class="o">=</span> <span class="nx">domPurify</span><span class="p">(</span><span class="k">new</span> <span class="nx">JSDOM</span><span class="p">().</span><span class="nb">window</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog/:slug&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">post</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;slug&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">slug</span><span class="p">).</span><span class="nx">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">post</span><span class="p">.</span><span class="nx">content</span> <span class="o">=</span> <span class="nx">post</span><span class="p">.</span><span class="nx">content</span> <span class="o">?</span> <span class="nx">purify</span><span class="p">.</span><span class="nx">sanitize</span><span class="p">(</span><span class="nx">marked</span><span class="p">(</span><span class="nx">post</span><span class="p">.</span><span class="nx">content</span><span class="p">))</span> <span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/show&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">post</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h3 id="create-a-new-post">Create a new post</h3>
<p>We will create a route/view to display fields of a post and allow user to create new post.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog/new&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/new&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="p">{}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p><code>post: {}</code> passes an empty object called <code>post</code> to the view. We will tie the fields in the view to attributes of this object. We use an empty object here rather than not passing anything at all since we may want to change this in the future to default the values of few fields on the view. You can safely ignore this for now.</p>
<h3 id="save-a-post">Save a post</h3>
<p>Create a route to save a new post by using a <code>POST</code> transaction.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">insert</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">})</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="sb">`/blog/</span><span class="si">${</span><span class="nx">id</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>The function used in this route will perform below tasks -</p>
<ul>
<li>gets data passed in <code>req</code>. In our case a view passes this data along after the user enters data and submits the form</li>
<li>inserts a record in <code>posts</code> table and populates values</li>
<li>redirects to the URL <code>/blog/&lt;some_id&gt;</code>. We have created the route for this previously - that route will fetch record with this <code>id</code> and call the &ldquo;show&rdquo; view to display post details</li>
</ul>
<p>Again, using id just works. But this is not quite what we want. Let us bring in <code>slug</code> here - but we want to solve the problem of converting title automatically to a slug. We do that using a package called <code>slugify</code>.</p>
<p>First, install <code>slugify</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save slugify
</span></span></code></pre></div><p>Change the above logic -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">slug</span> <span class="o">=</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span> <span class="p">{</span> <span class="nx">lower</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">strict</span><span class="o">:</span> <span class="kc">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">insert</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">})</span>
</span></span><span class="line"><span class="cl">      <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="sb">`/blog/</span><span class="si">${</span><span class="nx">id</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>The logic here is simple and straight forward. But, what happens if you are saving an updated record? We would then need to define another route and specify a different service. To keep things simple, let us combine save function for both new and updated records -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">postId</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">slug</span> <span class="o">=</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span> <span class="p">{</span> <span class="nx">lower</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">strict</span><span class="o">:</span> <span class="kc">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">insert</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">update</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">,</span> <span class="nb">parseInt</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">id</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="sb">`/blog/</span><span class="si">${</span><span class="nx">slug</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/new&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h3 id="edit-a-post">Edit a post</h3>
<p>Editing a post includes two transactions-</p>
<ol>
<li>Query for a specific post (and hand it over to view)</li>
<li>(Once user is done and clicks <code>Save</code>) Collect details updated by user and hand it over to a route / service to save the changes</li>
</ol>
<p>We will achieve the first part through the URL <code>http://localhost:9000/blog/edit/&lt;post_slug&gt;</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">&#34;/blog/edit/:slug&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">post</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">from</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">).</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;slug&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">slug</span><span class="p">).</span><span class="nx">first</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/new&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">post</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>While we could use different routes/logic to save new posts and to save updated posts, here we keep things simple. We will reuse <code>router.post(&quot;/blog&quot;, async (req, res) =&gt; {}</code> function as described in the previous section to save updates.</p>
<h2 id="more-views-for-blog-app">More Views for Blog App</h2>
<p>We are done with most of the routes. Let us create views to go along with them. Create a folder <code>views/blog</code> to store all <code>blog</code> related views in one place. Let&rsquo;s start with the views.</p>
<h3 id="display-a-list-of-posts-1">Display a list of posts</h3>
<p>Create a new view <code>views/blog/index.ejs</code> to show list of posts.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;postlist-nav&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog/new&#34;</span><span class="p">&gt;&lt;</span><span class="nt">button</span><span class="p">&gt;</span>New Post<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="err">&lt;</span>% posts.forEach(post =&gt; { %&gt;
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">aside</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">h3</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;postlist-title&#34;</span><span class="p">&gt;</span><span class="err">&lt;</span>%= post.title %&gt;<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-meta&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            📅 <span class="err">&lt;</span>%= post.created_at.toISOString().substring(0,10) %&gt; | 📁<span class="err">&lt;</span>%=
</span></span><span class="line"><span class="cl">            post.tags %&gt;
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span><span class="err">&lt;</span>%= post.content.substring(0,200) + &#39;...&#39; %&gt;<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">aside</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog/&lt;%= post.slug %&gt;&#34;</span><span class="p">&gt;</span>Read More<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="err">&lt;</span>% }); %&gt;
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;../partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>We receive posts from the route file and display records here. A few more interesting observations -</p>
<ul>
<li>We can use expressions in our EJS templates. e.g. <code>&lt;%= post.content.substring(0,200) + '...' %&gt;</code></li>
<li>We can use loops to display repeated sections - <code>&lt;% posts.forEach(post =&gt; { %&gt;</code>. <code>&lt;%</code> will just perform calculations, while <code>&lt;%=</code> will print out the result</li>
<li>You can use expressions in HTML tags or attributes</li>
<li>Note that we pass arguments to the route with the link <code>&lt;a href=&quot;/blog/&lt;%= post.slug %&gt;&quot;&gt;Read More&lt;/a&gt;</code></li>
</ul>
<p>Navigate to <code>https://localhost:9000/blog/</code> to see this view.</p>
<h3 id="display-a-specific-post-1">Display a specific post</h3>
<p>Create a new view <code>views/blog/show.ejs</code> and include below code.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;text-align: end;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;/blog/edit/&lt;%= post.slug %&gt;&#34;</span><span class="p">&gt;&lt;</span><span class="nt">button</span><span class="p">&gt;</span>Edit<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">h2</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-title&#34;</span><span class="p">&gt;</span><span class="err">&lt;</span>%= post.title %&gt;<span class="p">&lt;/</span><span class="nt">h2</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;post-meta&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          📅 <span class="err">&lt;</span>%= post.created_at.toISOString().substring(0,10) %&gt; | 📁<span class="err">&lt;</span>%=
</span></span><span class="line"><span class="cl">          post.tags %&gt;
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span><span class="err">&lt;</span>%- post.content %&gt;<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;../partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>This is very similar to what wee had earlier, but we just show one post rather than a bunch of posts.</p>
<p>The only additional thing to note is the redirection to <code>edit</code> view when user clicks on the edit post button.</p>
<h3 id="create-a-new-post-1">Create a new post</h3>
<p>Create new view <code>views/blog/new.ejs</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;POST&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="err">&lt;</span>%- include(&#34;_form_default&#34;) %&gt;
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;../partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>We have included a <code>_form_default.ejs</code> here instead of directly filling in the form fields for creating a new post. This is to encourage reuse of the form for both <code>new</code> and <code>edit</code> post functions.</p>
<p>Also take note of <code>&lt;form action=&quot;/blog&quot; method=&quot;POST&quot;&gt;</code> which redirects user to a route <code>/blog</code> with a method <code>POST</code> on submission of the form. The form is submitted at the click of <code>Save</code> button.</p>
<p>Create a new partial view <code>views/blog/_form_default.ejs</code> to house all controls of the form -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;form-group&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>Title<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;postlist-header&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;title&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;title&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#39;text&#39;</span> <span class="na">label</span><span class="o">=</span><span class="s">&#34;tags&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;&lt;%= post.title %&gt;&#34;</span>  <span class="na">required</span><span class="p">&gt;&lt;/</span><span class="nt">input</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;title&#34;</span><span class="p">&gt;</span>Tags 📁<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;tags&#34;</span> <span class="na">name </span><span class="o">=</span> <span class="s">&#34;tags&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;text&#34;</span> <span class="na">label</span><span class="o">=</span><span class="s">&#34;tags&#34;</span> <span class="na">required</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;&lt;%= post.tags %&gt;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;content&#34;</span><span class="p">&gt;</span>Content<span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">textarea</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;content&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;content&#34;</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;30&#34;</span> <span class="na">rows</span><span class="o">=</span><span class="s">&#34;20&#34;</span> <span class="na">required</span><span class="p">&gt;</span><span class="err">&lt;</span>%= post.content %&gt;<span class="p">&lt;/</span><span class="nt">textarea</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;id&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;id&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;hidden&#34;</span> <span class="na">value</span><span class="o">=</span><span class="s">&#34;&lt;%= post.id %&gt;&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;form-group&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">button</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;submit&#34;</span><span class="p">&gt;</span>Save<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>The form is a standard HTML form except the values of the fields - they are derived from the query and passed across to EJS as a parameter.</p>
<h3 id="save-a-post-1">Save a post</h3>
<p>Take action when the data is posted to <code>/blog</code> route. We do all the required operations in the route file itself to keep things simple. In real world you may want to just keep routing logic here and hive everything else to separate JS files (&amp; call them &ldquo;services&rdquo;).</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s2">&#34;/blog&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">let</span> <span class="nx">postId</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">slug</span> <span class="o">=</span> <span class="nx">slugify</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span> <span class="p">{</span> <span class="nx">lower</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nx">strict</span><span class="o">:</span> <span class="kc">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">insert</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">postId</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">db</span><span class="p">(</span><span class="s2">&#34;posts&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">update</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">          <span class="nx">title</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">content</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">tags</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">slug</span><span class="o">:</span> <span class="nx">slug</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">})</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">,</span> <span class="nb">parseInt</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">id</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="nx">returning</span><span class="p">(</span><span class="s2">&#34;id&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">redirect</span><span class="p">(</span><span class="sb">`/blog/</span><span class="si">${</span><span class="nx">slug</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">res</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="s2">&#34;blog/new&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">post</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>The actual DB save is self-explanatory and simple - thanks to <code>knex</code>. We perform an insert or update operation depending on whether <code>id</code> value already exists in the <code>post</code> object.</p>
<p>Once the record is saved, we show the saved post with <code>res.redirect(</code>/blog/${slug}<code>);</code></p>
<h3 id="editing-a-post">Editing a post</h3>
<p>We used a route <code>/blog/edit/:id</code> to trigger edit logic. The route queries the DB and passes the specific post details along.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/head&#39;); %&gt;
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="err">&lt;</span>%- include(&#39;../partials/nav&#39;); %&gt;
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">&#34;/blog&#34;</span> <span class="na">method</span><span class="o">=</span><span class="s">&#34;POST&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="err">&lt;</span>%- include(&#34;_form_default&#34;) %&gt;
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">footer</span><span class="p">&gt;</span><span class="err">&lt;</span>%- include(&#39;../partials/footer&#39;); %&gt;<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>We will reuse the route <code>/blog</code> with method <code>POST</code> to save record - you will see this in the submit action <code>&lt;form action=&quot;/blog&quot; method=&quot;POST&quot;&gt;</code>.</p>
<h2 id="finis">Finis</h2>
<p>So, there you have it - a beautiful looking blog app of your own! You can create new posts, display a list of posts, view single post and even edit it :). Want more? Comment and let me know!</p>
<p>See the complete code on the <a href="https://github.com/prashanth1k/bloggie">Github repo</a>.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Build a Simple Timesheet App using Vue &amp; Vuetify</title>
      <link>https://techformist.com/build-simple-timesheet-app-vue-vuetify/</link>
      <pubDate>Wed, 28 Oct 2020 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/build-simple-timesheet-app-vue-vuetify/</guid>
      <description>&lt;p&gt;In this post we will see how to create a simple timesheet app using Vue and Vuetify. This is not quite a comprehensive tutorial on Vue or Vuetify, rather a demo of front-end features, see how easy it is to build an usable app, and in general, how modern app development makes the whole process enjoyable.&lt;/p&gt;
&lt;h2 id=&#34;what-are-we-building&#34;&gt;What are we building?&lt;/h2&gt;
&lt;p&gt;A simple timesheet app that will -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;enable to enter time on a day&lt;/li&gt;
&lt;li&gt;enable export of time data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will store everything in browser storage and there will be no standard persistence layer. This app may or may not plugin to backend (Firebase? ExpressJS / Fastify? Hasura? Other?) in the future - comment and let me know if you&amp;rsquo;re interested in seeing that!&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In this post we will see how to create a simple timesheet app using Vue and Vuetify. This is not quite a comprehensive tutorial on Vue or Vuetify, rather a demo of front-end features, see how easy it is to build an usable app, and in general, how modern app development makes the whole process enjoyable.</p>
<h2 id="what-are-we-building">What are we building?</h2>
<p>A simple timesheet app that will -</p>
<ul>
<li>enable to enter time on a day</li>
<li>enable export of time data</li>
</ul>
<p>We will store everything in browser storage and there will be no standard persistence layer. This app may or may not plugin to backend (Firebase? ExpressJS / Fastify? Hasura? Other?) in the future - comment and let me know if you&rsquo;re interested in seeing that!</p>
<p>Technically, we will focus on -</p>
<ol>
<li>Use Vuex and router (latter is not quite needed, you will see more of this)</li>
<li>Form validations</li>
<li>Make application a joy to use with keyboard shortcuts</li>
</ol>
<p>This is how it looks..</p>
<p><img loading="lazy" src="/2020/simple-timesheet-app-daily-demo.gif" type="" alt="simple-timesheet-app-daily-demo"  /></p>
<p>Go to <a href="https://simple-timesheet.techformist.com">https://simple-timesheet.techformist.com</a> to see how the application works.</p>
<h2 id="get-started-with-vue">Get started with Vue</h2>
<p>If you don&rsquo;t have Vue CLI, this is a good time to go ahead and install it. Vue CLI is the starting point for all great Vue projects.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm install -g @vue/cli
</span></span></code></pre></div><p>Create the project -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">vue create simple-timesheet
</span></span></code></pre></div><p>Select the Vue version 2 for the sake of this project and instruct wizard that you will <strong>Manually select features</strong>. Also, select the below features/options -</p>
<ul>
<li>Options: Babel, PWA Support (optional), Router, Vuex, Linter / Formatter</li>
<li><code>Use history mode</code> to &lsquo;Y&rsquo; (default)</li>
<li>A sensible option for ESLint - I recommend <code>ESLint + Prettier</code></li>
<li>Store configuration in dedicated configuration files</li>
</ul>
<p>Sit back while Vue CLI downloads packages and creates the project.</p>
<p>Once done, add Vuetify to the project.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl"><span class="k">cd</span> simple-timesheet
</span></span><span class="line"><span class="cl">vue add vuetify
</span></span></code></pre></div><p>Choose the default Vuetify configuration.</p>
<p>Add packages to our app - we will see their role in subsequent sections.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm i --save vuex-persist vue-shortkey
</span></span></code></pre></div><p>Your project is ready to roll. Open the project folder in VS Code, the greatest editor of our times to get started.</p>
<h2 id="wire-everything-up">Wire Everything Up</h2>
<p>Vue comes packaged with all the things you need - so, there&rsquo;s no complex wiring involved. Let us focus on getting everything to a baseline version to start creating magic.</p>
<p>Change the default <code>App.vue</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">v-app</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-app-bar</span> <span class="na">app</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;primary darken-2&#34;</span> <span class="na">dark</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">h3</span><span class="p">&gt;</span>Simple Timesheet<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-spacer</span><span class="p">&gt;&lt;/</span><span class="nt">v-spacer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-btn</span> <span class="na">text</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/daily&#34;</span><span class="p">&gt;</span>Daily<span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-btn</span> <span class="na">text</span> <span class="na">to</span><span class="o">=</span><span class="s">&#34;/about&#34;</span><span class="p">&gt;</span>About<span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">v-app-bar</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-card</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;grey lighten-5&#34;</span> <span class="na">height</span><span class="o">=</span><span class="s">&#34;100%&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-container</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">router-view</span><span class="p">&gt;&lt;/</span><span class="nt">router-view</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">v-container</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">v-card</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">v-main</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">v-app</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;App&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">components</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">data</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="c1">//
</span></span></span><span class="line"><span class="cl">    <span class="p">}),</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>All we have done here is to change the toolbar, denote where our router will render views (<code>router-view</code> - no surprise there), and wrap the entire thing in a <code>v-container</code> to provide some nice spacing on all sides.</p>
<p>Follow up with a few more changes at the project level -</p>
<ol>
<li>Delete <code>component/HelloWorld.vue</code> component - we will create our own components. Remove <code>HelloWorld</code> references from <code>App.vue</code> and <code>Home.vue</code> view.</li>
<li>Delete <code>views/Home.vue</code> and remove references to <code>Home</code> from <code>router/index.js</code>.</li>
<li>Change <code>About.vue</code> page - include whatever content you want.</li>
<li>Create a new view called <code>views/Daily.vue</code> - let them be blank for now</li>
<li>Change <code>router/index.js</code> to add references to the new view. Let us redirect &ldquo;/&rdquo; to &ldquo;/daily&rdquo; and &ldquo;/daily&rdquo; will point to the &ldquo;Daily&rdquo; view.
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="c1">// ... other code
</span></span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">routes</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/daily&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Daily&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../views/Daily.vue&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/weekly&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Weekly&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../views/Weekly.vue&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">path</span><span class="o">:</span> <span class="s2">&#34;/about&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;About&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">component</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="kr">import</span><span class="p">(</span><span class="cm">/* webpackChunkName: &#34;about&#34; */</span> <span class="s2">&#34;../views/About.vue&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="c1">// ... other code
</span></span></span></code></pre></div></li>
</ol>
<p>Next, configure any additional packages.</p>
<h3 id="package-1-vuex-persist">Package 1: vuex-persist</h3>
<p><code>vuex-persist</code> enables storing of vuex values to browser local storage. This is quite handy since we don&rsquo;t want to lose values entered by the user whenever the page is refreshed, or when the website is closed.</p>
<p>Make below changes in <code>store/index.js</code> -</p>
<ol>
<li>
<p>Pull <code>vuex-persist</code> module</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">VuexPersistence</span> <span class="nx">from</span> <span class="s2">&#34;vuex-persist&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">vuexLocal</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">VuexPersistence</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">storage</span><span class="o">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">localStorage</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div></li>
<li>
<p>Include as a plugin</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="k">new</span> <span class="nx">Vuex</span><span class="p">.</span><span class="nx">Store</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">state</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">mutations</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">actions</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">modules</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span><span class="nx">vuexLocal</span><span class="p">.</span><span class="nx">plugin</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div></li>
</ol>
<h3 id="package-2-vue-shortkey">Package 2: vue-shortkey</h3>
<p>Change <code>main.js</code>. Just after the line <code>Vue.config.productionTip = false;</code> add another line..</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">Vue</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">require</span><span class="p">(</span><span class="s2">&#34;vue-shortkey&#34;</span><span class="p">));</span>
</span></span></code></pre></div><p>This will reference the package we added earlier <code>vue-shortkey</code>, which will enable us to tie keyboard shortcuts to specific actions (e.g. create new record can be tied to <code>Ctrl + N</code>).</p>
<h3 id="additional-configuration">Additional Configuration</h3>
<p>Add a single line to <code>public/index.html</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/microtip/microtip.css&#34;</span> <span class="p">/&gt;</span>
</span></span></code></pre></div><p>This will enable us to use a small, light-weight package called <code>microtip</code> to show tooltips on any UI element. See <a href="/simple-tooltip-vue">creating simple tooltips in Vue</a> for more details.</p>
<h3 id="start-your-project">Start your project</h3>
<p>It&rsquo;s time to start up stuff and see if everything&rsquo;s working.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmd" data-lang="cmd"><span class="line"><span class="cl">npm run serve
</span></span></code></pre></div><p>You should see your Vue application start up, and automatically open the browser with your application at <code>http://localhost:8080</code>.</p>
<p>Note that -</p>
<ul>
<li>We have not added any functionality yet - will get to that in the next section</li>
<li>UI elements like icons, iamges and fonts were not changed</li>
<li>We did not quite need a router. We could have as well used a tab component in Vuetify and be no wiser. While that keeps things simpler, router is invaluable if you start adding other views and need navigation elements for those views</li>
<li>It&rsquo;s possible to configure vuex-persist to your heart&rsquo;s content, but we are sticking to keeping things simple</li>
</ul>
<h2 id="create-supporting-components">Create Supporting Components</h2>
<p>Let&rsquo;s go ahead and create a couple of reusable components that will be used by other components.</p>
<h3 id="date-pick-component">Date Pick Component</h3>
<p>Vuetify makes creating a field with a date pick quite easy. We can create a text box and enable a date picker using <code>v-date-picker</code>.</p>
<p><img loading="lazy" src="/misc/date-picker-input-box-vuetify.gif" type="" alt="date-picker-input-box-vuetify"  /></p>
<p>But, we don&rsquo;t want to use boilerplate code each time we need to create a date field. Let us create a <code>DatePick</code> component that can be used by other components or views for any date fields.</p>
<p>Create a new file <code>components/DatePick.vue</code>. Add following code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c">&lt;!-- Todo: This needs cleaning up - either incl. date format or remove them --&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">v-menu</span>
</span></span><span class="line"><span class="cl">    <span class="na">ref</span><span class="o">=</span><span class="s">&#34;menu&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;menu&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">:close-on-content-click</span><span class="o">=</span><span class="s">&#34;false&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">transition</span><span class="o">=</span><span class="s">&#34;scale-transition&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">offset-y</span>
</span></span><span class="line"><span class="cl">    <span class="na">:nudge-right</span><span class="o">=</span><span class="s">&#34;40&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">scrollable</span>
</span></span><span class="line"><span class="cl">    <span class="na">max-width</span><span class="o">=</span><span class="s">&#34;290px&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">min-width</span><span class="o">=</span><span class="s">&#34;290px&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">template</span> <span class="na">v-slot:activator</span><span class="o">=</span><span class="s">&#34;{ on }&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-text-field</span>
</span></span><span class="line"><span class="cl">        <span class="na">:value</span><span class="o">=</span><span class="s">&#34;dateDisplay&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">outlined</span>
</span></span><span class="line"><span class="cl">        <span class="na">:label</span><span class="o">=</span><span class="s">&#34;label&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">append-icon</span><span class="o">=</span><span class="s">&#34;mdi-calendar&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">readonly</span>
</span></span><span class="line"><span class="cl">        <span class="na">:dense</span><span class="o">=</span><span class="s">&#34;dense&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">:hide-details</span><span class="o">=</span><span class="s">&#34;hideDetails&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">:disabled</span><span class="o">=</span><span class="s">&#34;disabled&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="err">@</span><span class="na">click:append</span><span class="o">=</span><span class="s">&#34;menu = true&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-on</span><span class="o">=</span><span class="s">&#34;on&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&gt;&lt;/</span><span class="nt">v-text-field</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-date-picker</span>
</span></span><span class="line"><span class="cl">      <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;dateValue&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">no-title</span>
</span></span><span class="line"><span class="cl">      <span class="na">scrollable</span>
</span></span><span class="line"><span class="cl">      <span class="na">:min</span><span class="o">=</span><span class="s">&#34;min&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">:max</span><span class="o">=</span><span class="s">&#34;max&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="err">@</span><span class="na">input</span><span class="o">=</span><span class="s">&#34;menu = false&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&gt;&lt;/</span><span class="nt">v-date-picker</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">v-menu</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">props</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">label</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">appendIcon</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;mdi-calendar&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">field</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="s2">&#34;&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">dense</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">Boolean</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="kc">false</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">hideDetails</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">Boolean</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="kc">false</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">disabled</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">Boolean</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="kc">false</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">min</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="k">default</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="kr">const</span> <span class="nx">dt</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">          <span class="nx">dt</span><span class="p">.</span><span class="nx">setDate</span><span class="p">(</span><span class="nx">dt</span><span class="p">.</span><span class="nx">getDate</span><span class="p">()</span> <span class="o">-</span> <span class="mi">30</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="k">return</span> <span class="nx">dt</span><span class="p">.</span><span class="nx">toISOString</span><span class="p">().</span><span class="nx">substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">max</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="k">default</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="kr">const</span> <span class="nx">dt</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">          <span class="nx">dt</span><span class="p">.</span><span class="nx">setDate</span><span class="p">(</span><span class="nx">dt</span><span class="p">.</span><span class="nx">getDate</span><span class="p">()</span> <span class="o">+</span> <span class="mi">365</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">          <span class="k">return</span> <span class="nx">dt</span><span class="p">.</span><span class="nx">toISOString</span><span class="p">().</span><span class="nx">substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">data</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">menu</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">modal</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">menu2</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">localField</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">dateValue</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">computed</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">dateDisplay</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">dateValue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">set</span><span class="p">(</span><span class="nx">val</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">$emit</span><span class="p">(</span><span class="s2">&#34;update:field&#34;</span><span class="p">,</span> <span class="nx">val</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">localFieldFmt</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">get</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">formatDate</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">localField</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">set</span><span class="p">(</span><span class="nx">val</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">$emit</span><span class="p">(</span><span class="s2">&#34;update:field&#34;</span><span class="p">,</span> <span class="nx">val</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">watch</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">localFieldFmt</span><span class="p">(</span><span class="nx">val</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">$emit</span><span class="p">(</span><span class="s2">&#34;update:field&#34;</span><span class="p">,</span> <span class="nx">val</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">dateValue</span><span class="p">(</span><span class="nx">val</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">$emit</span><span class="p">(</span><span class="s2">&#34;update:field&#34;</span><span class="p">,</span> <span class="nx">val</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">mounted</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">dateValue</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">field</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// this.localField = this.parseDate(this.field);
</span></span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">methods</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">test</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;wow&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">formatDate</span><span class="p">(</span><span class="nx">date</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">date</span><span class="p">)</span> <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="p">[</span><span class="nx">year</span><span class="p">,</span> <span class="nx">month</span><span class="p">,</span> <span class="nx">day</span><span class="p">]</span> <span class="o">=</span> <span class="nx">date</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s2">&#34;-&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">//   return `${day}/${month}/${year}`;
</span></span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="sb">`</span><span class="si">${</span><span class="nx">year</span><span class="si">}</span><span class="sb">-</span><span class="si">${</span><span class="nx">month</span><span class="si">}</span><span class="sb">-</span><span class="si">${</span><span class="nx">day</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="nx">parseDate</span><span class="p">(</span><span class="nx">date</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">date</span><span class="p">)</span> <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="p">[</span><span class="nx">day</span><span class="p">,</span> <span class="nx">month</span><span class="p">,</span> <span class="nx">year</span><span class="p">]</span> <span class="o">=</span> <span class="nx">date</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s2">&#34;-&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="sb">`</span><span class="si">${</span><span class="nx">year</span><span class="si">}</span><span class="sb">-</span><span class="si">${</span><span class="nx">month</span><span class="p">.</span><span class="nx">padStart</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s2">&#34;0&#34;</span><span class="p">)</span><span class="si">}</span><span class="sb">-</span><span class="si">${</span><span class="nx">day</span><span class="p">.</span><span class="nx">padStart</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s2">&#34;0&#34;</span><span class="p">)</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="nx">setLocalFieldFmt</span><span class="p">(</span><span class="nx">val</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">localFieldFmt</span> <span class="o">=</span> <span class="nx">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">localField</span> <span class="o">=</span> <span class="nx">val</span> <span class="o">?</span> <span class="k">this</span><span class="p">.</span><span class="nx">parseDate</span><span class="p">(</span><span class="nx">val</span><span class="p">)</span> <span class="o">:</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Don&rsquo;t quite worry if you don&rsquo;t get what&rsquo;s going on here. We are doing a couple of things -</p>
<ol>
<li>Create a text field input box that can take in user inputs</li>
<li>Enable date control using <code>v-date-picker</code></li>
<li>Raise an event whenever the date is set so that the calling component can set a value based on user input</li>
<li>We can also parse date values to handle international dates, but we will not quite use that here</li>
</ol>
<p>We can now use this component in any other view or component like so -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">DatePick</span>
</span></span><span class="line"><span class="cl">  <span class="na">name</span><span class="o">=</span><span class="s">&#34;todayDate&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">:field</span><span class="o">=</span><span class="s">&#34;dayDate&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="err">@</span><span class="na">update:field</span><span class="o">=</span><span class="s">&#34;setDayDate($event)&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">:dense</span><span class="o">=</span><span class="s">&#34;true&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">&gt;&lt;/</span><span class="nt">DatePick</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Here -</p>
<ul>
<li><code>dayDate</code> is a field (can be from Vuex or at the component level - we will see how this is used shortly)</li>
<li>On <code>update:field</code> event (which corresponds to the date input by user) we call a method called <code>setDayDate</code></li>
</ul>
<p>See <a href="/vuetify-input-field-date-picker/">reusable date picker field for Vuetify</a> for more details about the date picker field.</p>
<h3 id="confirm-component">Confirm component</h3>
<p>It is a common UI experience to ask for confirmation before allowing specific user actions - especially if they are irreversible. Vuetify has a <code>v-dialog</code> component to show a popup to that purpose, but it would need some boilerplate code to enable it each time to ask a question. Let&rsquo;s create a <code>Confirm</code> component to make it easier.</p>
<p>Create a new file <code>components/Confirm.vue</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">v-dialog</span>
</span></span><span class="line"><span class="cl">    <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;dialog&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">:max-width</span><span class="o">=</span><span class="s">&#34;options.width&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">:style</span><span class="o">=</span><span class="s">&#34;{ zIndex: options.zIndex }&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="err">@</span><span class="na">keydown</span><span class="err">.</span><span class="na">esc</span><span class="o">=</span><span class="s">&#34;cancel&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-card</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-toolbar</span> <span class="na">dark</span> <span class="na">:color</span><span class="o">=</span><span class="s">&#34;options.color&#34;</span> <span class="na">dense</span> <span class="na">flat</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-toolbar-title</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-body-2 font-weight-bold grey--text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          {{ title }}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">v-toolbar-title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">v-toolbar</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-card-text</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-show</span><span class="o">=</span><span class="s">&#34;!!message&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">class</span><span class="o">=</span><span class="s">&#34;pa-4 black--text&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-html</span><span class="o">=</span><span class="s">&#34;message&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&gt;&lt;/</span><span class="nt">v-card-text</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-card-actions</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;pt-3&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-spacer</span><span class="p">&gt;&lt;/</span><span class="nt">v-spacer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">          <span class="na">v-if</span><span class="o">=</span><span class="s">&#34;!options.noconfirm&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">color</span><span class="o">=</span><span class="s">&#34;grey&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">text</span>
</span></span><span class="line"><span class="cl">          <span class="na">class</span><span class="o">=</span><span class="s">&#34;body-2 font-weight-bold&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="err">@</span><span class="na">click</span><span class="err">.</span><span class="na">native</span><span class="o">=</span><span class="s">&#34;cancel&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&gt;</span>Cancel<span class="p">&lt;/</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">        <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">          <span class="na">color</span><span class="o">=</span><span class="s">&#34;primary&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">class</span><span class="o">=</span><span class="s">&#34;body-2 font-weight-bold&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">outlined</span>
</span></span><span class="line"><span class="cl">          <span class="err">@</span><span class="na">click</span><span class="err">.</span><span class="na">native</span><span class="o">=</span><span class="s">&#34;agree&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&gt;</span>OK<span class="p">&lt;/</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">        <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">v-card-actions</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">v-card</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">v-dialog</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Confirm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">data</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">dialog</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">resolve</span><span class="o">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">reject</span><span class="o">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">message</span><span class="o">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">title</span><span class="o">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">options</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">color</span><span class="o">:</span> <span class="s2">&#34;grey lighten-3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">width</span><span class="o">:</span> <span class="mi">400</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">zIndex</span><span class="o">:</span> <span class="mi">200</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">noconfirm</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">methods</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">open</span><span class="p">(</span><span class="nx">title</span><span class="p">,</span> <span class="nx">message</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">dialog</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">title</span> <span class="o">=</span> <span class="nx">title</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">message</span> <span class="o">=</span> <span class="nx">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">options</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">assign</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">((</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">resolve</span> <span class="o">=</span> <span class="nx">resolve</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">reject</span> <span class="o">=</span> <span class="nx">reject</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">});</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">agree</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">dialog</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">cancel</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">dialog</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>In the above code -</p>
<ul>
<li>we show a message popup using <code>v-dialog</code>. The message is passed to the component using props</li>
<li>we pass along the user action (<code>yes</code> or <code>no</code> for example) so that the caller can take action based on the answer</li>
</ul>
<p>We use the <code>Confirm</code> component in two parts.</p>
<ol>
<li>
<p>First, create a reference to <code>Confirm</code> in <code>&lt;template&gt;</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c">&lt;!-- other code --&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">confirm</span> <span class="na">ref</span><span class="o">=</span><span class="s">&#34;confirm&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c">&lt;!-- other code --&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Import the component.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// other code
</span></span></span><span class="line"><span class="cl">  <span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">components</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">Confirm</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../components/Confirm&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// other code
</span></span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>Call the confirm dialog whenever needed</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// other code
</span></span></span><span class="line"><span class="cl">  <span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">methods</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">async</span> <span class="nx">deleteRecordWithConfirm</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="kr">await</span> <span class="k">this</span><span class="p">.</span><span class="nx">$refs</span><span class="p">.</span><span class="nx">confirm</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Confirm Delete&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Are you sure you want to delete this record?&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">deleteRecord</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// other code
</span></span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div></li>
</ol>
<p>Again, don&rsquo;t worry too much into how confirm works - you will get time to see much more later.</p>
<p>Now that everything&rsquo;s wired up and we created baseline infrastructure, it is time to write our core functionality.</p>
<h2 id="create-daily-component">Create Daily Component</h2>
<p>We already created a view called <code>Daily.vue</code>. We will add a simple form and some code to enable users to create/edit/view timesheet entries.</p>
<p>Add the below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;center&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-card</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;white&#34;</span> <span class="na">width</span><span class="o">=</span><span class="s">&#34;70%&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-toolbar</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;grey lighten-3&#34;</span> <span class="na">flat</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;font-weight-black h6&#34;</span><span class="p">&gt;</span>Daily Timesheet<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-spacer</span><span class="p">&gt;&lt;/</span><span class="nt">v-spacer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">          <span class="na">small</span>
</span></span><span class="line"><span class="cl">          <span class="na">class</span><span class="o">=</span><span class="s">&#34;mr-2&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;resetAfterConfirm&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">aria-label</span><span class="o">=</span><span class="s">&#34;Reset timesheet. Delete all entries below.&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">data-microtip-position</span><span class="o">=</span><span class="s">&#34;bottom&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">role</span><span class="o">=</span><span class="s">&#34;tooltip&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">v-icon</span> <span class="na">small</span> <span class="na">dark</span><span class="p">&gt;</span>mdi-delete-sweep<span class="p">&lt;/</span><span class="nt">v-icon</span><span class="p">&gt;</span> Reset
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-menu</span> <span class="na">offset-y</span> <span class="na">close-on-content-click</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">template</span> <span class="na">v-slot:activator</span><span class="o">=</span><span class="s">&#34;{ on, attrs }&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">              <span class="na">small</span>
</span></span><span class="line"><span class="cl">              <span class="na">class</span><span class="o">=</span><span class="s">&#34;mr-2&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">aria-label</span><span class="o">=</span><span class="s">&#34;Download timesheet.&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">data-microtip-position</span><span class="o">=</span><span class="s">&#34;bottom&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">role</span><span class="o">=</span><span class="s">&#34;tooltip&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">v-bind</span><span class="o">=</span><span class="s">&#34;attrs&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">v-on</span><span class="o">=</span><span class="s">&#34;on&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&lt;</span><span class="nt">v-icon</span> <span class="na">small</span> <span class="na">dark</span><span class="p">&gt;</span>mdi-download<span class="p">&lt;/</span><span class="nt">v-icon</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              Export
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">v-list</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">v-list-item</span>
</span></span><span class="line"><span class="cl">              <span class="na">v-for</span><span class="o">=</span><span class="s">&#34;(item, index) in downloadItems&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="na">:key</span><span class="o">=</span><span class="s">&#34;index&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;invokeAction(item.action)&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&lt;</span><span class="nt">v-list-item-title</span><span class="p">&gt;</span>{{ item.title }}<span class="p">&lt;/</span><span class="nt">v-list-item-title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">v-list-item</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">v-list</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">v-menu</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">          <span class="na">color</span><span class="o">=</span><span class="s">&#34;primary&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">small</span>
</span></span><span class="line"><span class="cl">          <span class="na">class</span><span class="o">=</span><span class="s">&#34;mr-2&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;newDayTime&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">v-shortkey</span><span class="o">=</span><span class="s">&#34;[&#39;alt&#39;, &#39;shift&#39;, &#39;n&#39;]&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="err">@</span><span class="na">shortkey</span><span class="o">=</span><span class="s">&#34;newDayTime()&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">aria-label</span><span class="o">=</span><span class="s">&#34;Create new time. [alt+shift+n]&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">data-microtip-position</span><span class="o">=</span><span class="s">&#34;bottom&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">role</span><span class="o">=</span><span class="s">&#34;tooltip&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">v-icon</span> <span class="na">small</span> <span class="na">dark</span><span class="p">&gt;</span>mdi-plus<span class="p">&lt;/</span><span class="nt">v-icon</span><span class="p">&gt;</span>Add
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">v-toolbar</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-container</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;left&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;pl-3 pr-3&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">&#34;todayDate&#34;</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;font-weight-bold grey--text&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            Date
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">label</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">DatePick</span>
</span></span><span class="line"><span class="cl">            <span class="na">name</span><span class="o">=</span><span class="s">&#34;todayDate&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">:field</span><span class="o">=</span><span class="s">&#34;dayDate&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="err">@</span><span class="na">update:field</span><span class="o">=</span><span class="s">&#34;setDayDate($event)&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="na">:dense</span><span class="o">=</span><span class="s">&#34;true&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&gt;&lt;/</span><span class="nt">DatePick</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-h6&#34;</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;left&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            Total Hours:
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;font-weight-bold&#34;</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;primary&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              {{ totalTime }}
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-card</span>
</span></span><span class="line"><span class="cl">          <span class="na">flat</span>
</span></span><span class="line"><span class="cl">          <span class="na">color</span><span class="o">=</span><span class="s">&#34;transparent&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">height</span><span class="o">=</span><span class="s">&#34;400px&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">class</span><span class="o">=</span><span class="s">&#34;pl-3&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="na">style</span><span class="o">=</span><span class="s">&#34;overflow-y:auto; overflow-x:hidden&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">v-form</span> <span class="err">@</span><span class="na">submit</span><span class="err">.</span><span class="na">prevent</span><span class="o">=</span><span class="s">&#34;addEntry&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">v-row</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;center&#34;</span> <span class="na">dense</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;12&#34;</span> <span class="na">sm</span><span class="o">=</span><span class="s">&#34;10&#34;</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;left&#34;</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&lt;</span><span class="nt">v-col</span>
</span></span><span class="line"><span class="cl">                <span class="na">cols</span><span class="o">=</span><span class="s">&#34;12&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="na">v-for</span><span class="o">=</span><span class="s">&#34;(dayTime, index) in dayTimes&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="na">:key</span><span class="o">=</span><span class="s">&#34;index&#34;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">v-row</span> <span class="na">dense</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;12&#34;</span> <span class="na">sm</span><span class="o">=</span><span class="s">&#34;8&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">v-text-field</span>
</span></span><span class="line"><span class="cl">                      <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;What work is this for?&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;dayTime[&#39;desc&#39;]&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">dense</span>
</span></span><span class="line"><span class="cl">                      <span class="na">outlined</span>
</span></span><span class="line"><span class="cl">                      <span class="na">autofocus</span>
</span></span><span class="line"><span class="cl">                      <span class="err">@</span><span class="na">focus</span><span class="o">=</span><span class="s">&#34;activeIndex = index&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">hide-details</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&gt;&lt;/</span><span class="nt">v-text-field</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;10&#34;</span> <span class="na">sm</span><span class="o">=</span><span class="s">&#34;2&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">v-text-field</span>
</span></span><span class="line"><span class="cl">                      <span class="na">dense</span>
</span></span><span class="line"><span class="cl">                      <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;Hours&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;dayTime[&#39;time&#39;]&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">outlined</span>
</span></span><span class="line"><span class="cl">                      <span class="na">type</span><span class="o">=</span><span class="s">&#34;number&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">reverse</span>
</span></span><span class="line"><span class="cl">                      <span class="err">@</span><span class="na">focus</span><span class="o">=</span><span class="s">&#34;activeIndex = index&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">hide-details</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&gt;&lt;/</span><span class="nt">v-text-field</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;2&#34;</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;left&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">                      <span class="na">fab</span>
</span></span><span class="line"><span class="cl">                      <span class="na">icon</span>
</span></span><span class="line"><span class="cl">                      <span class="na">small</span>
</span></span><span class="line"><span class="cl">                      <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;delDayTimeByIndex(activeIndex)&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">v-shortkey</span><span class="o">=</span><span class="s">&#34;[&#39;alt&#39;, &#39;shift&#39;, &#39;del&#39;]&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="err">@</span><span class="na">shortkey</span><span class="o">=</span><span class="s">&#34;delDayTimeByIndex(activeIndex)&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">aria-label</span><span class="o">=</span><span class="s">&#34;Delete this entry. [alt+shift+del]&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">data-microtip-position</span><span class="o">=</span><span class="s">&#34;bottom&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">data-microtip-size</span><span class="o">=</span><span class="s">&#34;medium&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="na">role</span><span class="o">=</span><span class="s">&#34;tooltip&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                      <span class="p">&lt;</span><span class="nt">v-icon</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;grey&#34;</span><span class="p">&gt;</span>mdi-delete<span class="p">&lt;/</span><span class="nt">v-icon</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">v-row</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">              <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">v-row</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">v-form</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">v-card</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">v-container</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">v-card</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">confirm</span> <span class="na">ref</span><span class="o">=</span><span class="s">&#34;confirm&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">import</span> <span class="p">{</span> <span class="nx">mapState</span><span class="p">,</span> <span class="nx">mapMutations</span> <span class="p">}</span> <span class="nx">from</span> <span class="s2">&#34;vuex&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Daily&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">components</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">DatePick</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../components/DatePick&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="nx">Confirm</span><span class="o">:</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="kr">import</span><span class="p">(</span><span class="s2">&#34;../components/Confirm&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">data</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">activeIndex</span><span class="o">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">downloadItems</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span> <span class="nx">title</span><span class="o">:</span> <span class="s2">&#34;CSV&#34;</span><span class="p">,</span> <span class="nx">action</span><span class="o">:</span> <span class="s2">&#34;generateDownloadCsv&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span> <span class="nx">title</span><span class="o">:</span> <span class="s2">&#34;TXT&#34;</span><span class="p">,</span> <span class="nx">action</span><span class="o">:</span> <span class="s2">&#34;generateDownloadTxt&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">computed</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="p">...</span><span class="nx">mapState</span><span class="p">(</span><span class="s2">&#34;daystr&#34;</span><span class="p">,</span> <span class="p">[</span><span class="s2">&#34;dayTimes&#34;</span><span class="p">,</span> <span class="s2">&#34;dayDate&#34;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="nx">totalTime</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">dayTimes</span><span class="p">.</span><span class="nx">reduce</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nx">sum</span><span class="p">,</span> <span class="nx">element</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">sum</span> <span class="o">+</span> <span class="p">(</span><span class="nb">Number</span><span class="p">(</span><span class="nx">element</span><span class="p">[</span><span class="s2">&#34;time&#34;</span><span class="p">])</span> <span class="o">||</span> <span class="mi">0</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">          <span class="mi">0</span>
</span></span><span class="line"><span class="cl">        <span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">mounted</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">dayTimes</span><span class="p">.</span><span class="nx">length</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">resetDay</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">methods</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="p">...</span><span class="nx">mapMutations</span><span class="p">(</span><span class="s2">&#34;daystr&#34;</span><span class="p">,</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;newDayTime&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;setActiveDayTime&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;setDayDate&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;resetDay&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;delDayTimeByIndex&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">]),</span>
</span></span><span class="line"><span class="cl">      <span class="kr">async</span> <span class="nx">resetAfterConfirm</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="kr">await</span> <span class="k">this</span><span class="p">.</span><span class="nx">$refs</span><span class="p">.</span><span class="nx">confirm</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Confirm Reset&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;Are you sure you want to reset timesheet? You will lose all data on this page.&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="k">this</span><span class="p">.</span><span class="nx">resetDay</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">invokeAction</span><span class="p">(</span><span class="nx">action</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">[</span><span class="nx">action</span><span class="p">]();</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">generateDownloadCsv</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">generateExportAndDownload</span><span class="p">(</span><span class="s2">&#34;data:text/csv&#34;</span><span class="p">,</span> <span class="s2">&#34;csv&#34;</span><span class="p">,</span> <span class="s2">&#34;,&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">generateDownloadTxt</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">this</span><span class="p">.</span><span class="nx">generateExportAndDownload</span><span class="p">(</span><span class="s2">&#34;data:text/txt&#34;</span><span class="p">,</span> <span class="s2">&#34;txt&#34;</span><span class="p">,</span> <span class="s2">&#34; - &#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">generateExportAndDownload</span><span class="p">(</span><span class="nx">filetype</span><span class="p">,</span> <span class="nx">extn</span><span class="p">,</span> <span class="nx">separator</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nx">strDayTimes</span> <span class="o">=</span> <span class="sb">`</span><span class="si">${</span><span class="nx">filetype</span><span class="si">}</span><span class="sb">;charset=utf-8,Timesheet for Date: </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">dayDate</span><span class="si">}</span><span class="sb"> \n\rTotal Time: </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">totalTime</span><span class="si">}</span><span class="sb"> hours \n\rTime Records\n===============================\n`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">strDayTimes</span> <span class="o">+=</span> <span class="sb">`Description</span><span class="si">${</span><span class="nx">separator</span><span class="si">}</span><span class="sb">Time (Hours)\n===============================\n`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">strDayTimes</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">dayTimes</span>
</span></span><span class="line"><span class="cl">          <span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">element</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="sb">`</span><span class="si">${</span><span class="nx">element</span><span class="p">[</span><span class="s2">&#34;desc&#34;</span><span class="p">]</span><span class="si">}${</span><span class="nx">separator</span><span class="si">}${</span><span class="nx">element</span><span class="p">[</span><span class="s2">&#34;time&#34;</span><span class="p">]</span><span class="si">}</span><span class="sb">`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s2">&#34;\n&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/(^\[)|(\]$)/gm</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">fileData</span> <span class="o">=</span> <span class="nb">encodeURI</span><span class="p">(</span><span class="nx">strDayTimes</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">link</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">&#34;a&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">link</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s2">&#34;href&#34;</span><span class="p">,</span> <span class="nx">fileData</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">link</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s2">&#34;download&#34;</span><span class="p">,</span> <span class="sb">`timesheet.</span><span class="si">${</span><span class="nx">extn</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nx">link</span><span class="p">.</span><span class="nx">click</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>There are quite a few things going on here. Let us dissect them in detail.</p>
<h3 id="start-up">Start up</h3>
<p><code>mounted()</code> method in a Vue component helps us to &ldquo;hook&rdquo; into the component start up and run some code each time the component gets displayed.</p>
<p>We are including the following code in <code>mounted</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">dayTimes</span><span class="p">.</span><span class="nx">length</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">resetDay</span><span class="p">();</span>
</span></span></code></pre></div><p>This will call a method <code>resetDay</code> only if <code>dayTimes</code> array does not have any elements. <code>resetDay</code> is outlined in the Vuex store. It will -</p>
<ol>
<li>Reset the date to today&rsquo;s date</li>
<li>Delete all entries in the timesheet</li>
</ol>
<h3 id="ui-elements">UI Elements</h3>
<p>Everything within <code>&lt;template&gt;</code> tags form our UI. Here we use Vuetify grid, ready-made components from Vuetify like button, text input box, and more to create our timesheet.</p>
<h4 id="toolbar">Toolbar</h4>
<p>Toolbar consists of a couple of buttons and a menu item to show export options.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">v-toolbar</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;grey lighten-3&#34;</span> <span class="na">flat</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;font-weight-black h6&#34;</span><span class="p">&gt;</span>Daily Timesheet<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">v-spacer</span><span class="p">&gt;&lt;/</span><span class="nt">v-spacer</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">    <span class="na">small</span>
</span></span><span class="line"><span class="cl">    <span class="na">class</span><span class="o">=</span><span class="s">&#34;mr-2&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;resetAfterConfirm&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">aria-label</span><span class="o">=</span><span class="s">&#34;Reset timesheet. Delete all entries below.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">data-microtip-position</span><span class="o">=</span><span class="s">&#34;bottom&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">role</span><span class="o">=</span><span class="s">&#34;tooltip&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-icon</span> <span class="na">small</span> <span class="na">dark</span><span class="p">&gt;</span>mdi-delete-sweep<span class="p">&lt;/</span><span class="nt">v-icon</span><span class="p">&gt;</span> Reset
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">v-menu</span> <span class="na">offset-y</span> <span class="na">close-on-content-click</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">template</span> <span class="na">v-slot:activator</span><span class="o">=</span><span class="s">&#34;{ on, attrs }&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">        <span class="na">small</span>
</span></span><span class="line"><span class="cl">        <span class="na">class</span><span class="o">=</span><span class="s">&#34;mr-2&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">aria-label</span><span class="o">=</span><span class="s">&#34;Download timesheet.&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">data-microtip-position</span><span class="o">=</span><span class="s">&#34;bottom&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">role</span><span class="o">=</span><span class="s">&#34;tooltip&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-bind</span><span class="o">=</span><span class="s">&#34;attrs&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-on</span><span class="o">=</span><span class="s">&#34;on&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-icon</span> <span class="na">small</span> <span class="na">dark</span><span class="p">&gt;</span>mdi-download<span class="p">&lt;/</span><span class="nt">v-icon</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        Export
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-list</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-list-item</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-for</span><span class="o">=</span><span class="s">&#34;(item, index) in downloadItems&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">:key</span><span class="o">=</span><span class="s">&#34;index&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;invokeAction(item.action)&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-list-item-title</span><span class="p">&gt;</span>{{ item.title }}<span class="p">&lt;/</span><span class="nt">v-list-item-title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">v-list-item</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">v-list</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">v-menu</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">    <span class="na">color</span><span class="o">=</span><span class="s">&#34;primary&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">small</span>
</span></span><span class="line"><span class="cl">    <span class="na">class</span><span class="o">=</span><span class="s">&#34;mr-2&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;newDayTime&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">v-shortkey</span><span class="o">=</span><span class="s">&#34;[&#39;alt&#39;, &#39;shift&#39;, &#39;n&#39;]&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="err">@</span><span class="na">shortkey</span><span class="o">=</span><span class="s">&#34;newDayTime()&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">aria-label</span><span class="o">=</span><span class="s">&#34;Create new time. [alt+shift+n]&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">data-microtip-position</span><span class="o">=</span><span class="s">&#34;bottom&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="na">role</span><span class="o">=</span><span class="s">&#34;tooltip&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-icon</span> <span class="na">small</span> <span class="na">dark</span><span class="p">&gt;</span>mdi-plus<span class="p">&lt;/</span><span class="nt">v-icon</span><span class="p">&gt;</span>Add
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">v-toolbar</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>You may note that -</p>
<ul>
<li><code>v-menu</code> pulls in the list of menu items using a <code>&lt;v-list&gt;</code> from a variable called <code>downloadItems</code>. This variable is specific to this Vue component and is defined in <code>data</code> section</li>
<li>we used <code>microtip</code> required parameters like <code>aria-label</code>, <code>data-microtip-position</code> and <code>role</code> to create tooltips on button</li>
<li>we called methods defined in the <code>script</code> section using the magical <code>@click</code> event from buttons (<code>v-btn</code>)</li>
<li>buttons use <code>v-shortkey</code> to denote the shortcut key combination to simulate button click and <code>@shotcutkey</code> to denote which method should be called on click</li>
</ul>
<h4 id="header">Header</h4>
<p>Create -</p>
<ul>
<li>a date field that the user can update. Use the <code>DatePick</code> component created earlier</li>
<li>a field that shows the total time entered. Use <code>totalTime</code> computed variable - details on the computed variable in the <code>computed</code> section</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">DatePick</span>
</span></span><span class="line"><span class="cl">  <span class="na">name</span><span class="o">=</span><span class="s">&#34;todayDate&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">:field</span><span class="o">=</span><span class="s">&#34;dayDate&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="err">@</span><span class="na">update:field</span><span class="o">=</span><span class="s">&#34;setDayDate($event)&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="na">:dense</span><span class="o">=</span><span class="s">&#34;true&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">&gt;&lt;/</span><span class="nt">DatePick</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;text-h6&#34;</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;left&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  Total Hours:
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;font-weight-bold&#34;</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;primary&#34;</span><span class="p">&gt;</span> {{ totalTime }} <span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span></code></pre></div><h4 id="timesheet-entries">Timesheet entries</h4>
<p>Show the list of timesheet entries recorded in <code>dayTimes</code> array with the below code block -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;12&#34;</span> <span class="na">v-for</span><span class="o">=</span><span class="s">&#34;(dayTime, index) in dayTimes&#34;</span> <span class="na">:key</span><span class="o">=</span><span class="s">&#34;index&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">v-row</span> <span class="na">dense</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;12&#34;</span> <span class="na">sm</span><span class="o">=</span><span class="s">&#34;8&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-text-field</span>
</span></span><span class="line"><span class="cl">        <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;What work is this for?&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;dayTime[&#39;desc&#39;]&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">dense</span>
</span></span><span class="line"><span class="cl">        <span class="na">outlined</span>
</span></span><span class="line"><span class="cl">        <span class="na">autofocus</span>
</span></span><span class="line"><span class="cl">        <span class="err">@</span><span class="na">focus</span><span class="o">=</span><span class="s">&#34;activeIndex = index&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">hide-details</span>
</span></span><span class="line"><span class="cl">      <span class="p">&gt;&lt;/</span><span class="nt">v-text-field</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;10&#34;</span> <span class="na">sm</span><span class="o">=</span><span class="s">&#34;2&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-text-field</span>
</span></span><span class="line"><span class="cl">        <span class="na">dense</span>
</span></span><span class="line"><span class="cl">        <span class="na">placeholder</span><span class="o">=</span><span class="s">&#34;Hours&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-model</span><span class="o">=</span><span class="s">&#34;dayTime[&#39;time&#39;]&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">outlined</span>
</span></span><span class="line"><span class="cl">        <span class="na">type</span><span class="o">=</span><span class="s">&#34;number&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">reverse</span>
</span></span><span class="line"><span class="cl">        <span class="err">@</span><span class="na">focus</span><span class="o">=</span><span class="s">&#34;activeIndex = index&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">hide-details</span>
</span></span><span class="line"><span class="cl">      <span class="p">&gt;&lt;/</span><span class="nt">v-text-field</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">v-col</span> <span class="na">cols</span><span class="o">=</span><span class="s">&#34;2&#34;</span> <span class="na">align</span><span class="o">=</span><span class="s">&#34;left&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">v-btn</span>
</span></span><span class="line"><span class="cl">        <span class="na">fab</span>
</span></span><span class="line"><span class="cl">        <span class="na">icon</span>
</span></span><span class="line"><span class="cl">        <span class="na">small</span>
</span></span><span class="line"><span class="cl">        <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;delDayTimeByIndex(activeIndex)&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">v-shortkey</span><span class="o">=</span><span class="s">&#34;[&#39;alt&#39;, &#39;shift&#39;, &#39;del&#39;]&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="err">@</span><span class="na">shortkey</span><span class="o">=</span><span class="s">&#34;delDayTimeByIndex(activeIndex)&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">aria-label</span><span class="o">=</span><span class="s">&#34;Delete this entry. [alt+shift+del]&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">data-microtip-position</span><span class="o">=</span><span class="s">&#34;bottom&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">data-microtip-size</span><span class="o">=</span><span class="s">&#34;medium&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="na">role</span><span class="o">=</span><span class="s">&#34;tooltip&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">v-icon</span> <span class="na">color</span><span class="o">=</span><span class="s">&#34;grey&#34;</span><span class="p">&gt;</span>mdi-delete<span class="p">&lt;/</span><span class="nt">v-icon</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">v-btn</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">v-row</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">v-col</span><span class="p">&gt;</span>
</span></span></code></pre></div><h3 id="computed-variables">Computed variables</h3>
<p>Computed variables allow us to use calculated values, values that dymamically change at different stages of the component based on component state, data variables, external data, user actions and so on.</p>
<p>We created two different types of variables here -</p>
<ol>
<li>Pull in the Vuex state variables from <code>daystr</code> module with <code>...mapState(&quot;daystr&quot;, [&quot;dayTimes&quot;, &quot;dayDate&quot;])</code></li>
<li>Create a <code>totalTime</code> value that will add up all time entries and provide the total time entered on the timesheet. There are multiple ways of doing this including a simple <code>for</code> statement to loop through the <code>dayTimes</code> array, but we have used some shortcut methods to keep the code clean 😜</li>
</ol>
<p>The overall <code>computed</code> code block is below -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">computed</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="p">...</span><span class="nx">mapState</span><span class="p">(</span><span class="s2">&#34;daystr&#34;</span><span class="p">,</span> <span class="p">[</span><span class="s2">&#34;dayTimes&#34;</span><span class="p">,</span> <span class="s2">&#34;dayDate&#34;</span><span class="p">]),</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">totalTime</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">dayTimes</span><span class="p">.</span><span class="nx">reduce</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nx">sum</span><span class="p">,</span> <span class="nx">element</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">sum</span> <span class="o">+</span> <span class="p">(</span><span class="nb">Number</span><span class="p">(</span><span class="nx">element</span><span class="p">[</span><span class="s2">&#34;time&#34;</span><span class="p">])</span> <span class="o">||</span> <span class="mi">0</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span>
</span></span></code></pre></div><h3 id="methods">Methods</h3>
<p>Most of the methods are mutations defined in the Vuex module <code>dailystr</code>. These are referenced in our component with the following line -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">methods</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span><span class="nx">mapMutations</span><span class="p">(</span><span class="s2">&#34;daystr&#34;</span><span class="p">,</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;newDayTime&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;setActiveDayTime&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;setDayDate&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;resetDay&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;delDayTimeByIndex&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">]),</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Beyond Vuex, we have a few more methods -</p>
<h4 id="method-1-invokeaction">Method 1: InvokeAction</h4>
<p>This method simply calls another method. It is used in a list so that we can call methods dynamically while we are defining the list.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">invokeAction</span><span class="p">(</span><span class="nx">action</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">[</span><span class="nx">action</span><span class="p">]();</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span>
</span></span></code></pre></div><h4 id="method-2-confirm-and-reset-timesheet">Method 2: Confirm and reset timesheet</h4>
<p>This method gets invoked when user clicks on &ldquo;Reset&rdquo; button. Ask user to confirm reset and call a Vuex mutation that will reset the <code>dayTimes</code> array and reset date to today&rsquo;s date.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">async</span> <span class="nx">resetAfterConfirm</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="kr">await</span> <span class="k">this</span><span class="p">.</span><span class="nx">$refs</span><span class="p">.</span><span class="nx">confirm</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;Confirm Reset&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;Are you sure you want to reset timesheet? You will lose all data on this page.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">resetDay</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span>
</span></span></code></pre></div><h4 id="methods-3--4-generatedownload-methods">Methods 3 &amp; 4: generateDownLoad methods</h4>
<p>We invoke two distinct methods when user clicks on export button - one of them facilitates export to CSV file format, while the other option enables a text export.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">generateDownloadCsv</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">this</span><span class="p">.</span><span class="nx">generateExportAndDownload</span><span class="p">(</span><span class="s2">&#34;data:text/csv&#34;</span><span class="p">,</span> <span class="s2">&#34;csv&#34;</span><span class="p">,</span> <span class="s2">&#34;,&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="nx">generateDownloadTxt</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">this</span><span class="p">.</span><span class="nx">generateExportAndDownload</span><span class="p">(</span><span class="s2">&#34;data:text/txt&#34;</span><span class="p">,</span> <span class="s2">&#34;txt&#34;</span><span class="p">,</span> <span class="s2">&#34; - &#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span>
</span></span></code></pre></div><p>Both these methods call <code>generateExportAndDownload</code>, which will export the timesheet entries to a file based on input arguments. We could have called <code>generateExportAndDownload</code> method directly from the <code>template</code> HTML with arguments, but we used different methods for any future scalability. (yes, this is sarcasm)</p>
<h4 id="method-5-generateexportanddownload-method">Method 5: generateExportAndDownload method</h4>
<p><code>generateExportAndDownload</code> will -</p>
<ul>
<li>take three arguments for the export file type, the extension to be used for the export file and the separator to be used between the timesheet description and number of hours</li>
<li>fetch the entries from the Vuex store variables (the &ldquo;state&rdquo; values) <code>dayDate</code> and <code>dayTimes</code></li>
<li>create a string for export by joining some informational statements and the <code>dayTimes</code> array</li>
<li>create an <code>a</code> tag with the content as newly created string</li>
<li>simulate a click on the <code>a</code> link to download content to a file</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="nx">generateExportAndDownload</span><span class="p">(</span><span class="nx">filetype</span><span class="p">,</span> <span class="nx">extn</span><span class="p">,</span> <span class="nx">separator</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">let</span> <span class="nx">strDayTimes</span> <span class="o">=</span> <span class="sb">`</span><span class="si">${</span><span class="nx">filetype</span><span class="si">}</span><span class="sb">;charset=utf-8,Timesheet for Date: </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">dayDate</span><span class="si">}</span><span class="sb"> \n\rTotal Time: </span><span class="si">${</span><span class="k">this</span><span class="p">.</span><span class="nx">totalTime</span><span class="si">}</span><span class="sb"> hours \n\rTime Records\n===============================\n`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">strDayTimes</span> <span class="o">+=</span> <span class="sb">`Description</span><span class="si">${</span><span class="nx">separator</span><span class="si">}</span><span class="sb">Time (Hours)\n===============================\n`</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">strDayTimes</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">dayTimes</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">element</span> <span class="p">=&gt;</span> <span class="sb">`</span><span class="si">${</span><span class="nx">element</span><span class="p">[</span><span class="s2">&#34;desc&#34;</span><span class="p">]</span><span class="si">}${</span><span class="nx">separator</span><span class="si">}${</span><span class="nx">element</span><span class="p">[</span><span class="s2">&#34;time&#34;</span><span class="p">]</span><span class="si">}</span><span class="sb">`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s2">&#34;\n&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/(^\[)|(\]$)/gm</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">fileData</span> <span class="o">=</span> <span class="nb">encodeURI</span><span class="p">(</span><span class="nx">strDayTimes</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">link</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">&#34;a&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">link</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s2">&#34;href&#34;</span><span class="p">,</span> <span class="nx">fileData</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">link</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s2">&#34;download&#34;</span><span class="p">,</span> <span class="sb">`timesheet.</span><span class="si">${</span><span class="nx">extn</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">link</span><span class="p">.</span><span class="nx">click</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">},</span>
</span></span></code></pre></div><h2 id="modify-vuex-store">Modify Vuex store</h2>
<p>The <code>Daily</code> timesheet component references Vuex store and specifically a module called <code>dailystr</code>. Let us include that.</p>
<p>Create a new file called <code>store/dailystr.js</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">namespaced</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;daystr&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">state</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">dayDate</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">dayTimes</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="nx">activeDayTime</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">mutations</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">newDayTime</span><span class="p">(</span><span class="nx">state</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">state</span><span class="p">.</span><span class="nx">dayTimes</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span> <span class="nx">desc</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="nx">time</span><span class="o">:</span> <span class="mi">1</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">setActiveDayTime</span><span class="p">(</span><span class="nx">state</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">state</span><span class="p">.</span><span class="nx">activeDayTime</span> <span class="o">=</span> <span class="nx">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">delDayTimeByIndex</span><span class="p">(</span><span class="nx">state</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">state</span><span class="p">.</span><span class="nx">dayTimes</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">index</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">setDayDate</span><span class="p">(</span><span class="nx">state</span><span class="p">,</span> <span class="nx">val</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">state</span><span class="p">.</span><span class="nx">dayDate</span> <span class="o">=</span> <span class="nx">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">resetDay</span><span class="p">(</span><span class="nx">state</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">state</span><span class="p">.</span><span class="nx">dayDate</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">toISOString</span><span class="p">().</span><span class="nx">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="nx">state</span><span class="p">.</span><span class="nx">dayTimes</span> <span class="o">=</span> <span class="p">[{</span> <span class="nx">desc</span><span class="o">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="nx">time</span><span class="o">:</span> <span class="mi">1</span> <span class="p">}];</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>We create a bunch of variables to store time entries in a day, and also created <code>mutations</code> that allow us to change those variable values.</p>
<p>Change <code>store/index.js</code> to include the newly created module. The complete code is outlined below.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Vue</span> <span class="nx">from</span> <span class="s2">&#34;vue&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">Vuex</span> <span class="nx">from</span> <span class="s2">&#34;vuex&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">VuexPersistence</span> <span class="nx">from</span> <span class="s2">&#34;vuex-persist&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">daystr</span> <span class="nx">from</span> <span class="s2">&#34;./daystr&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Vue</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">Vuex</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">vuexLocal</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">VuexPersistence</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">storage</span><span class="o">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">localStorage</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="k">default</span> <span class="k">new</span> <span class="nx">Vuex</span><span class="p">.</span><span class="nx">Store</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">state</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">mutations</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">actions</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">modules</span><span class="o">:</span> <span class="p">{</span> <span class="nx">daystr</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span><span class="nx">vuexLocal</span><span class="p">.</span><span class="nx">plugin</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>We had made the <code>vuex-persist</code> related changes at the beginning of this post.</p>
<h2 id="enable-pwa">Enable PWA</h2>
<p>If you had selected the <code>PWA</code> option while creating the project using Vue CLI, your app is automatically available as a progressive web app. You cannot test this unless you are connected using <code>https</code>. Since we don&rsquo;t really do any changes here, you can see the PWA in action after deploying the application.</p>
<h2 id="deploy">Deploy</h2>
<p>Deploying a client-application is really easy - thanks to build/deploy/host application services available today.</p>
<p>As an example, we will use <a href="https://vercel.com">vercel.com</a>.</p>
<p>Go to vercel.com, create an account if you don&rsquo;t have one, or login to your existing account.</p>
<p>On dashboard, click on <code>Import Project</code> button. Vercel will ask you for the Git repository to import and may also ask you for additional permissions to access repository.</p>
<p><img loading="lazy" src="/2020/deploy-vue-app-vercel.jpg" type="" alt="deploy-vue-app-vercel"  /></p>
<p>Once the repo is imported, Vercel should automatically identify the project as a Vue app and set build configuration. Review the configuration and click on <code>Deploy</code> to deploy your app and make it available to the world. Vercel will provide the URL that you can use to access your app.</p>
<p>The URL for your app will be available over https (e.g. <a href="https://simple-timesheet.vercel.app">simple-timesheet.vercel.app</a>). You will be able to install this app to your desktop or mobile using the functionality enabled by PWA.</p>
<h2 id="finis">Finis</h2>
<p>That&rsquo;s it - you have created and deployed a totally real-world timesheet application usign Vue, Vuetify and friends.</p>
<p>The repository with full code is at <a href="https://github.com/prashanth1k/simple-timesheet">https://github.com/prashanth1k/simple-timesheet</a>.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
