{"id":4661,"date":"2024-02-01T16:16:56","date_gmt":"2024-02-01T16:16:56","guid":{"rendered":"https:\/\/nikola-breznjak.com\/blog\/?p=4661"},"modified":"2024-02-07T22:27:07","modified_gmt":"2024-02-07T22:27:07","slug":"getting-started-with-vue-js-3-by-building-a-pokemon-search-application","status":"publish","type":"post","link":"https:\/\/nikola-breznjak.com\/blog\/javascript\/getting-started-with-vue-js-3-by-building-a-pokemon-search-application\/","title":{"rendered":"Getting started with Vue.js 3 by building a Pokemon search application"},"content":{"rendered":"<h2>TL;DR<\/h2>\n<p>In the previous tutorial I showed you how to <a href=\"https:\/\/www.nikola-breznjak.com\/blog\/javascript\/getting-started-vue-js-3-building-giphy-search-application\/\">get started with Vue.js 3 by building a Giphy search application<\/a>. That was a long while ago \ud83d\ude42, so here&#8217;s a new and updated post.<\/p>\n<p>But, to not just update the post, I decided to do something different. Since my kids are into Pokemon, what better use of my coding skills than to make them an app where they can search for their favorite Pokemon and check their stats.<\/p>\n<p>So, in this post, you&#8217;ll learn how to use <a href=\"https:\/\/github.com\/vuejs\/vue-cli\">create-vue<\/a> (official Vue project scaffolding tool) to build a <strong>Vue.js 3<\/strong> application for searching Pokemon by using <a href=\"https:\/\/pokeapi.co\/docs\/v2#pokemon\">Poke API<\/a>.<\/p>\n<h2>Introduction &#8211; The Battle is Over Indeed<\/h2>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/CseGOCb.png\" alt=\"\" \/><\/p>\n<p>A few years ago, this was a popular meme. It was funny because it was true \ud83d\ude42<\/p>\n<p>However, it seems that the craziness has settled down a bit and that the war is seemingly over. For now. These top four (top 5 lists are overrated \ud83d\ude09) frameworks established themselves:<\/p>\n<ul>\n<li><a href=\"https:\/\/angular.io\/\">Angular<\/a> (93k)<\/li>\n<li><a href=\"https:\/\/reactjs.org\/\">React<\/a> (218k)<\/li>\n<li><a href=\"https:\/\/svelte.dev\/\">Svelte<\/a> (75k)<\/li>\n<li><a href=\"https:\/\/vuejs.org\/\">Vue.js<\/a> (206k <a href=\"https:\/\/github.com\/vuejs\/vue\">v2<\/a>, 43k <a href=\"https:\/\/github.com\/vuejs\/core\">v3<\/a>)<\/li>\n<\/ul>\n<p>I added the number of Github <code>*<\/code>s (at the time of this writing), but I don&#8217;t want you to read into that too much \ud83e\udd17<\/p>\n<h2>Analysis paralysis will, well, paralyze you!<\/h2>\n<p>You could argue that there are other options like Ember, Mithril, or good &#8216;ol jQuery even! However, <a href=\"https:\/\/twitter.com\/JoubranJad\/status\/1136030060975017984\">this tweet<\/a> says it all:<\/p>\n<blockquote>\n<p>Developers are fighting over which frontend framework is better.. it&#8217;s not like users know or care. They mostly care about the User Experience. UX should be our focus on the frontend.<\/p>\n<\/blockquote>\n<p>Personally, I stuck to the Angular bandwagon since version 1.0, but that started losing its <em>ooomph<\/em> after versions 2, 3, 4, &#8230; sorry, lost count.<\/p>\n<p>I believe that Vue.js (due to its progressive and flexible nature) is a perfect fit for teams that have to rewrite old codebases <strong>one step at a time<\/strong>. However, you can also use it as a full-blown framework if you wish.<\/p>\n<p>Personally, React&#8217;s JSX just <em>seems wrong<\/em>, and some people, smarter than me, swear by that being TheRightWay\u2122, and I guess we&#8217;re not here to discuss tastes&#8230;<\/p>\n<p>Recently I checked out Svelte and kinda like it, so will be doing a post like this for it; stay tuned.<\/p>\n<p>General &#8216;framework war&#8217; kind of questions I tend to answer in the following way:<\/p>\n<blockquote>\n<p>Please just stop with the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Analysis_paralysis\">analysis paralysis<\/a> already.<\/p>\n<p>Do your research, pick a framework (any framework for that matter) that the community is using, use it, and see how far it gets you.<\/p>\n<p>All these talks about X being slow or Y being better just make no sense until you try it yourself for your use case and preference.<\/p>\n<p>Besides, nowadays speed will not be a deciding factor among the top JS frameworks.<\/p>\n<\/blockquote>\n<p>With all this out of the way, fasten your seatbelts, take a venti (or trenta) sized cup of coffee, and let&#8217;s go do something practical! \ud83d\udcaa<\/p>\n<h2>The Demo App<\/h2>\n<p>As said in the intro, we&#8217;ll build an application for searching (and showing) Pokemon by using <a href=\"https:\/\/pokeapi.co\/docs\/v2#pokemon\">Poke API<\/a>.<\/p>\n<p>You can fork the complete source code on <a href=\"https:\/\/github.com\/Hitman666\/PokemonSearch_Vue3\">Github<\/a>.<\/p>\n<blockquote>\n<p>I&#8217;m using Vue.js 3, and I&#8217;ll be referring to it as just Vue in the rest of this post.<\/p>\n<\/blockquote>\n<h2>Prerequisites<\/h2>\n<p>Make sure that you have the following tools installed:<\/p>\n<ul>\n<li>Node.js &#8211; here&#8217;s a free but outdated <a href=\"https:\/\/leanpub.com\/meantodo\">step by step guide\/book<\/a> for both Windows and Mac. Or, really, just go to the <a href=\"https:\/\/nodejs.org\/\">main website<\/a> and download the executable for your machine<\/li>\n<li>Git &#8211; here&#8217;s a fun <a href=\"https:\/\/nikola-breznjak.com\/blog\/miscellaneou\/learn-git-fast-job-depends\/\">getting started<\/a> tutorial in case you&#8217;re new to it<\/li>\n<\/ul>\n<h2>Start a new app with create-vue<\/h2>\n<p>To start the project, run the following command (in your Terminal): <code>npm create vue@latest<\/code><\/p>\n<p>This command, as their <a href=\"https:\/\/github.com\/vuejs\/create-vue\">docs say<\/a>, will install and execute <code>create-vue<\/code>, the official Vue project scaffolding tool. You will be presented with prompts for several optional features such as TypeScript and testing support (<em>I named the project PokemonSearch_Vue3<\/em>):<\/p>\n<pre><code>\u2714 Project name: \u2026 PokemonSearch_Vue3\n\u2714 Package name: \u2026 pokemonsearch-vue3\n\u2714 Add TypeScript? \u2026 No \/ Yes\n\u2714 Add JSX Support? \u2026 No \/ Yes\n\u2714 Add Vue Router for Single Page Application development? \u2026 No \/ Yes\n\u2714 Add Pinia for state management? \u2026 No \/ Yes\n\u2714 Add Vitest for Unit Testing? \u2026 No \/ Yes\n\u2714 Add an End-to-End Testing Solution? \u203a No\n\u2714 Add ESLint for code quality? \u2026 No \/ Yes\n\nScaffolding project in \/Users\/Nikola.Breznjak\/Development\/Web\/Vue\/PokemonSearch_Vue3...\n\nDone. Now run:\n\ncd PokemonSearch_Vue3\nnpm install\nnpm run dev<\/code><\/pre>\n<p>In the previous blog post, we used Vue CLI. That has been deprecated and <code>create-vue<\/code> is now the default. The reasons that they quote are:<\/p>\n<blockquote>\n<p>Vue CLI is based on webpack, while create-vue is based on Vite. Vite supports most of the configured conventions found in Vue CLI projects out of the box, and provides a significantly better development experience due to its extremely fast startup and hot-module replacement speed. Learn more about why we recommend Vite over webpack here.<br \/>\nUnlike Vue CLI, create-vue itself is just a scaffolding tool: it creates a pre-configured project based on the features you choose, and delegates the rest to Vite. Projects scaffolded this way can directly leverage the Vite plugin ecosystem which is Rollup-compatible.<\/p>\n<\/blockquote>\n<p>You can learn more about &#8216;why&#8217; Vite <a href=\"https:\/\/vitejs.dev\/guide\/why.html\">here<\/a>.<\/p>\n<h2>Running our scaffolded project<\/h2>\n<p>Let&#8217;s run the commands (in terminal) noted in the previous output:<\/p>\n<pre><code>cd PokemonSearch_Vue3\nnpm install\nnpm run dev<\/code><\/pre>\n<p>You should get this output:<\/p>\n<pre><code> VITE v5.0.12  ready in 175 ms\n\n  \u279c  Local:   http:\/\/localhost:5173\/\n  \u279c  Network: use --host to expose\n  \u279c  press h + enter to show help<\/code><\/pre>\n<p>You should see the following page in your browser if you open <a href=\"http:\/\/localhost:5173\">http:\/\/localhost:5173<\/a>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/T9SICEF.png\" alt=\"\" \/><\/p>\n<h2>Folder structure<\/h2>\n<p>Now, let&#8217;s open this project in the editor of your choice (I&#8217;m using <a href=\"https:\/\/code.visualstudio.com\/\">Visual Studio Code<\/a> + <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=Vue.volar\">Volar<\/a> extension), and you should see something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/6WHFJn4.png\" alt=\"\" \/><\/p>\n<p>This is an introduction tutorial, to get you running fast, so I won&#8217;t be going into any specific details and will be only focusing on the <code>src<\/code> folder.<\/p>\n<h2>Add content<\/h2>\n<p>OK, so let&#8217;s add something to our app.<\/p>\n<p>But, where to start? \ud83e\udd14<\/p>\n<p>Well, one of the first things I do when I come to a project for the first time is to look at the generated output. Then I try to find the strings corresponding to that output within the source code.<\/p>\n<p>So, if you search for the string <code>You did it!<\/code>, you&#8217;ll see the string is within the <code>App.vue<\/code> file. This file contains the following code:<\/p>\n<pre><code>&lt;script setup&gt;\nimport HelloWorld from &#039;.\/components\/HelloWorld.vue&#039;\nimport TheWelcome from &#039;.\/components\/TheWelcome.vue&#039;\n&lt;\/script&gt;\n\n&lt;template&gt;\n  &lt;header&gt;\n    &lt;img alt=&quot;Vue logo&quot; class=&quot;logo&quot; src=&quot;.\/assets\/logo.svg&quot; width=&quot;125&quot; height=&quot;125&quot; \/&gt;\n\n    &lt;div class=&quot;wrapper&quot;&gt;\n      &lt;HelloWorld msg=&quot;You did it!&quot; \/&gt;\n    &lt;\/div&gt;\n  &lt;\/header&gt;\n\n  &lt;main&gt;\n    &lt;TheWelcome \/&gt;\n  &lt;\/main&gt;\n&lt;\/template&gt;\n\n&lt;style scoped&gt;\nheader {\n  line-height: 1.5;\n}\n\n.logo {\n  display: block;\n  margin: 0 auto 2rem;\n}\n\n@media (min-width: 1024px) {\n  header {\n    display: flex;\n    place-items: center;\n    padding-right: calc(var(--section-gap) \/ 2);\n  }\n\n  .logo {\n    margin: 0 2rem 0 0;\n  }\n\n  header .wrapper {\n    display: flex;\n    place-items: flex-start;\n    flex-wrap: wrap;\n  }\n}\n&lt;\/style&gt;<\/code><\/pre>\n<p>Without knowing much about Vue.js, you can see where you would change the <code>You did it!<\/code> text. So, let&#8217;s change that to <code>Welcome to Pokemon Search<\/code>. Save that, and voila!, you&#8217;ll see the change reflected immediately in your browser.<\/p>\n<h2>Add some style<\/h2>\n<p>I borrowed the image (hope they don&#8217;t mind) from <a href=\"https:\/\/en.wikipedia.org\/wiki\/Pok%C3%A9mon\">Wikipedia<\/a> and saved it in the <code>assets<\/code> folder as <code>logo.webp<\/code>, added a search input, and styled it a bit to match it with the Pokemon style. <em>In case you&#8217;re wondering, I asked ChatGPT to help with coming up with the style<\/em> \ud83d\ude42<\/p>\n<p>Here&#8217;s the final code that I came up with in <code>App.vue<\/code>:<\/p>\n<pre><code>&lt;template&gt;\n  &lt;header&gt;\n    &lt;img alt=&quot;Vue logo&quot; class=&quot;logo&quot; src=&quot;.\/assets\/logo.webp&quot; \/&gt;\n  &lt;\/header&gt;\n\n  &lt;main&gt;\n    &lt;div class=&quot;search-container&quot;&gt;\n      &lt;input class=&quot;search-box&quot; type=&quot;text&quot; placeholder=&quot;Search...&quot; v-model=&quot;searchTerm&quot;&gt;\n    &lt;\/div&gt;\n  &lt;\/main&gt;\n&lt;\/template&gt;\n\n&lt;style scoped&gt;\nheader {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n}\n\n.logo {\n  margin: 0 2rem 0 0;\n}\n\n.search-container {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n  gap: 10px;\n}\n\n.search-box {\n  width: 30%;\n  height: 50px;\n  font-size: 1.5em;\n  padding: 10px;\n  border: 1px solid #ccc;\n  border-radius: 5px;\n  margin: 40px 0;\n  text-align: center;\n}<\/code><\/pre>\n<p>Also, I did a few other smaller things:<\/p>\n<ul>\n<li>added <code>background: linear-gradient(to right, #FDDF3C, #3B4CCA);<\/code> in the <code>base.css<\/code> file in the <code>body<\/code> tag<\/li>\n<li>removed the <code>main.css<\/code> file altogether<\/li>\n<li>imported <code>base.css<\/code> in the <code>main.js<\/code> file instead of <code>main.css<\/code><\/li>\n<li>removed the whole <code>components<\/code> folder<\/li>\n<\/ul>\n<p>The way this looks now is as follows: <img decoding=\"async\" src=\"https:\/\/i.imgur.com\/hrX5ZR6.png\" alt=\"\" \/><\/p>\n<p><em>If you get stuck in any of the above steps, please reach out in the comments, and I&#8217;ll be happy to help.<\/em><\/p>\n<h2>Pokemon API<\/h2>\n<p>Finally, we come to the cool part \ud83e\udd76, and that is to fetch some data from the PokeAPI and show it in our app.<\/p>\n<p>How do we get this API? Well, if you do a simple Google search for <code>pokemon api<\/code> and open the <a href=\"https:\/\/pokeapi.co\/\">first link<\/a>, you&#8217;ll also get to the <a href=\"https:\/\/pokeapi.co\/docs\/v2\">documentation<\/a> for their API.<\/p>\n<p>By looking at the docs, you can find that the API endpoint that lists all the available Pokemon is this: <a href=\"https:\/\/pokeapi.co\/api\/v2\/pokemon\">https:\/\/pokeapi.co\/api\/v2\/pokemon<\/a>. There&#8217;s a total of 1302 records.<\/p>\n<p>Now, fetching all this data every time you load your app would be a bad idea from the performance standpoint, but also from their <a href=\"https:\/\/pokeapi.co\/docs\/v2#fairuse\">fair use<\/a> policy.<\/p>\n<p>So, what we will do is open <a href=\"https:\/\/pokeapi.co\/api\/v2\/pokemon?limit=1320\">this link<\/a> which will fetch all 1320 Pokemon endpoints. The output looks something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/BlKuxTW.png\" alt=\"\" \/><\/p>\n<p>Now, save this output (just Command + S or Ctrl + s if you&#8217;re on Windows) to a local file that we&#8217;ll name <code>pokemonapi.json<\/code> and place this file in the <code>src\/assets<\/code> folder.<\/p>\n<blockquote>\n<p>\u26a0\ufe0f I just want to give proper props to <a href=\"https:\/\/pokeapi.co\/\">PokeAPI<\/a> for their awesome service \ud83d\udc4f<\/p>\n<\/blockquote>\n<p><em>For our demo purposes, this will be fine, but if you&#8217;d like to deploy this somewhere where you&#8217;d get a lot of traffic (or, if the main list of Pokemon changes), you&#8217;d have to cache the responses. We&#8217;ll tackle this in another blog post, but just something to keep in mind.<\/em><\/p>\n<h2>Show the data<\/h2>\n<p>Now we&#8217;ll want to list all the Pokemon that we have in the saved <code>pokemonapi.json<\/code> file. To do that, we&#8217;ll write some Javascript code in the top of the <code>App.vue<\/code> file that looks like this:<\/p>\n<pre><code>&lt;script&gt;\nimport pokemonData from &#039;.\/assets\/pokemonapi.json&#039;;\n\nexport default {\n  data() {\n    return {\n      pokemonList: pokemonData.results,\n      searchTerm: &#039;&#039;,\n      selectedPokemon: null\n    }\n  },\n  computed: {\n    filteredPokemonList() {\n      return this.pokemonList.filter(pokemon =&gt; pokemon.name.includes(this.searchTerm));\n    }\n  }\n}\n&lt;\/script&gt;<\/code><\/pre>\n<p><code>filteredPokemonList<\/code> function returns the list of pokemon that we loaded from the <code>pokemonapi.json<\/code> file and filters them by what we enter in the input box.<\/p>\n<p>And we&#8217;ll add this portion of HTML just below the search box:<\/p>\n<pre><code>&lt;ul&gt;\n  &lt;li v-for=&quot;pokemon in filteredPokemonList&quot; :key=&quot;pokemon.id&quot; class=&quot;pokemon-item&quot;&gt;\n    {{ pokemon.name }}\n  &lt;\/li&gt;\n&lt;\/ul&gt;<\/code><\/pre>\n<p>And, we&#8217;ll add a bit of CSS:<\/p>\n<pre><code>.pokemon-item {\n  float: left;\n  margin: 10px;\n}\n.pokemon-item a {\n  color: #000;\n  text-decoration: none;\n  font-size: 16px;\n  transition: color 0.3s ease;\n  text-transform: capitalize;\n}\n\n.pokemon-item a:hover {\n  color: #3B4CCA;\n}\n\nul {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n  gap: 5px;\n  list-style: none;\n}<\/code><\/pre>\n<p>Doing this, you should have your app look something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/9CtWoYV.png\" alt=\"\" \/><\/p>\n<h2>Get additional details about each Pokemon<\/h2>\n<p>If you open any of the URLs that you see in the <code>pokemonapi.json<\/code> file, you will get something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/0e52ATX.png\" alt=\"\" \/><\/p>\n<p>To show some additional information about a certain Pokemon (once clicked on its name in the list), we&#8217;ll update the <code>li<\/code> item by adding the <code>a<\/code> link to it like this:<\/p>\n<pre><code>&lt;li v-for=&quot;pokemon in filteredPokemonList&quot; :key=&quot;pokemon.id&quot; class=&quot;pokemon-item&quot;&gt;\n  &lt;a href=&quot;#&quot; @click=&quot;showPokemon(pokemon.url)&quot;&gt;{{ pokemon.name }}&lt;\/a&gt;\n  &lt;\/li&gt;<\/code><\/pre>\n<p>On the click event we attached the <code>showPokemon<\/code> function (by using <code>@click<\/code>) and passed it the URL that we get in the main API call (loaded from the JSON file).<\/p>\n<p>Now we should define this function in the <code>methods<\/code> object like this (I&#8217;m showing the contents of the whole script tag):<\/p>\n<pre><code>import pokemonData from &#039;.\/assets\/pokemonapi.json&#039;;\n\nexport default {\n  data() {\n    return {\n      pokemonList: pokemonData.results,\n      searchTerm: &#039;&#039;,\n      selectedPokemon: null\n    }\n  },\n  computed: {\n    filteredPokemonList() {\n      return this.pokemonList.filter(pokemon =&gt; pokemon.name.includes(this.searchTerm));\n    }\n  },\n  methods: {\n    async showPokemon(url) {\n      const response = await fetch(url);\n      if (!response.ok) {\n        console.error(`Error fetching Pokemon: ${response.statusText}`);\n        return;\n      }\n\n      this.selectedPokemon = await response.json();\n      console.log(this.selectedPokemon);\n    }\n  }\n}<\/code><\/pre>\n<p>To show the selected Pokemon, we&#8217;ll add a bit of HTML:<\/p>\n<pre><code>&lt;div class=&quot;pokemon-details&quot; v-if=&quot;selectedPokemon&quot;&gt;\n  &lt;h2&gt;{{ selectedPokemon.name }}&lt;\/h2&gt;\n  &lt;img :src=&quot;selectedPokemon.sprites.front_default&quot; alt=&quot;selectedPokemon.name&quot;&gt;\n  &lt;p&gt;Height: {{ selectedPokemon.height }}&lt;\/p&gt;\n  &lt;p&gt;Weight: {{ selectedPokemon.weight }}&lt;\/p&gt;\n\n  &lt;div v-for=&quot;(stat, index) in selectedPokemon.stats&quot; :key=&quot;index&quot;&gt;\n    &lt;p&gt;{{ stat.stat.name }}: {{ stat.base_stat }}&lt;\/p&gt;\n  &lt;\/div&gt;\n&lt;\/div&gt;<\/code><\/pre>\n<p>We&#8217;re using <code>v-if=&quot;selectedPokemon&quot;<\/code> so that the line <code>{{ selectedPokemon.name }}<\/code> doesn&#8217;t throw an error for trying to access a property that doesn&#8217;t exist on the object <code>selectedPokemon<\/code> (which is initialized as <code>null<\/code> in the beginnning).<\/p>\n<p>We&#8217;re using <code>v-for<\/code> to loop through all the elements of the <code>stats<\/code> array and output the <code>name<\/code> and <code>base_stat<\/code> properties.<\/p>\n<p>To make it look nicer, we&#8217;ll use a bit of CSS:<\/p>\n<pre><code>.pokemon-details {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  width: 30%;\n  margin: 20px auto;\n  padding: 20px;\n  border: 1px solid #000;\n  border-radius: 10px;\n  color: #000;\n  text-transform: capitalize;\n}\n\n.pokemon-details img {\n  width: 100px;\n  height: 100px;\n}<\/code><\/pre>\n<p>For reference, for those following the tutorial to the dot, here&#8217;s the full listing of <code>HelloWorld.vue<\/code> file:<\/p>\n<pre><code>&lt;script&gt;\nimport pokemonData from &#039;.\/assets\/pokemonapi.json&#039;;\n\nexport default {\n  data() {\n    return {\n      pokemonList: pokemonData.results,\n      searchTerm: &#039;&#039;,\n      selectedPokemon: null\n    }\n  },\n  computed: {\n    filteredPokemonList() {\n      return this.pokemonList.filter(pokemon =&gt; pokemon.name.includes(this.searchTerm));\n    }\n  },\n  methods: {\n    async showPokemon(url) {\n      const response = await fetch(url);\n      if (!response.ok) {\n        console.error(`Error fetching Pokemon: ${response.statusText}`);\n        return;\n      }\n\n      this.selectedPokemon = await response.json();\n      console.log(this.selectedPokemon);\n    }\n  }\n}\n&lt;\/script&gt;\n\n&lt;template&gt;\n  &lt;header&gt;\n    &lt;img alt=&quot;Vue logo&quot; class=&quot;logo&quot; src=&quot;.\/assets\/logo.webp&quot; \/&gt;\n  &lt;\/header&gt;\n\n  &lt;main&gt;\n    &lt;div class=&quot;search-container&quot;&gt;\n      &lt;input class=&quot;search-box&quot; type=&quot;text&quot; placeholder=&quot;Search...&quot; v-model=&quot;searchTerm&quot;&gt;\n    &lt;\/div&gt;\n\n    &lt;div class=&quot;pokemon-details&quot; v-if=&quot;selectedPokemon&quot;&gt;\n      &lt;h2&gt;{{ selectedPokemon.name }}&lt;\/h2&gt;\n      &lt;img :src=&quot;selectedPokemon.sprites.front_default&quot; alt=&quot;selectedPokemon.name&quot;&gt;\n      &lt;p&gt;Height: {{ selectedPokemon.height }}&lt;\/p&gt;\n      &lt;p&gt;Weight: {{ selectedPokemon.weight }}&lt;\/p&gt;\n\n      &lt;div v-for=&quot;(stat, index) in selectedPokemon.stats&quot; :key=&quot;index&quot;&gt;\n        &lt;p&gt;{{ stat.stat.name }}: {{ stat.base_stat }}&lt;\/p&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n\n    &lt;ul&gt;\n      &lt;li v-for=&quot;pokemon in filteredPokemonList&quot; :key=&quot;pokemon.id&quot; class=&quot;pokemon-item&quot;&gt;\n        &lt;a href=&quot;#&quot; @click=&quot;showPokemon(pokemon.url)&quot;&gt;{{ pokemon.name }}&lt;\/a&gt;\n      &lt;\/li&gt;\n    &lt;\/ul&gt;\n  &lt;\/main&gt;\n&lt;\/template&gt;\n\n&lt;style scoped&gt;\nheader {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n}\n\n.logo {\n  margin: 0 2rem 0 0;\n}\n\n.search-container {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n  \/* Change the direction to row *\/\n  gap: 10px;\n}\n\n.search-box {\n  width: 30%;\n  height: 50px;\n  font-size: 1.5em;\n  padding: 10px;\n  border: 1px solid #ccc;\n  border-radius: 5px;\n  margin: 40px 0;\n  text-align: center;\n}\n\n.pokemon-item {\n  float: left;\n  margin: 10px;\n}\n.pokemon-item a {\n  color: #000;\n  text-decoration: none;\n  font-size: 16px;\n  transition: color 0.3s ease;\n  text-transform: capitalize;\n}\n\n.pokemon-item a:hover {\n  color: #3B4CCA;\n}\n\nul {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n  gap: 5px;\n  list-style: none;\n}\n\n.pokemon-details {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  width: 30%;\n  margin: 20px auto;\n  padding: 20px;\n  border: 1px solid #000;\n  border-radius: 10px;\n  color: #000;\n  text-transform: capitalize;\n}\n\n.pokemon-details img {\n  width: 100px;\n  height: 100px;\n}\n&lt;\/style&gt;<\/code><\/pre>\n<h2>B e a utiful<\/h2>\n<p>At this point, we can search for some Pokemon (my son&#8217;s favorite is, ofc, Pikachu), and if we click on it, we&#8217;ll get something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/DEWVNg7.png\" alt=\"\" \/><\/p>\n<h2>Deployment<\/h2>\n<p>If you&#8217;d like to host this on your web server, then first run <code>npm run build<\/code> and you&#8217;ll get an output similar to this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/YHNDNYB.png\" alt=\"\" \/><\/p>\n<p>Now all you have to do is take the contents of the <code>dist<\/code> folder and &#8216;paste&#8217; it on your static web server.<\/p>\n<p>If you don&#8217;t have a server of your own, then Vite has an extensive <a href=\"https:\/\/vitejs.dev\/guide\/static-deploy\">description<\/a> for deploying your static pages (if you don&#8217;t have the ) to many popular services like Github Pages, Netlify, Vercel, Surge, etc.<\/p>\n<p>You can deploy to Github Pages in under 2 minutes by following their <a href=\"https:\/\/pages.github.com\/\">documentation<\/a>.<\/p>\n<p>Just for brevity sake the steps are as follows:<\/p>\n<ul>\n<li>create a new public Github repository and name it <code>username.github.io<\/code>, where <code>username<\/code> is your <code>username<\/code> on GitHub.<\/li>\n<li>clone the repo with <code>git clone https:\/\/github.com\/username\/username.github.io<\/code><\/li>\n<li>inside the folder copy the contents of the <code>dist<\/code> folder<\/li>\n<li>commit and push the changes:<\/li>\n<\/ul>\n<pre><code>git add --all \ngit commit -m &quot;Initial commit&quot;\ngit push -u origin main<\/code><\/pre>\n<p>Now your site will be visible online at <a href=\"https:\/\/username.github.io\">https:\/\/username.github.io<\/a> (again, where <code>username<\/code> is your Github username)<\/p>\n<p>You can check my deployment <a href=\"https:\/\/hitman666.github.io\/\">here<\/a>.<\/p>\n<h2>Conclusion<\/h2>\n<p>In this tutorial, you learned how to get started with using Vue.js 3 by building an application for searching Pokemon by using PokeAPI and making it publically accessible via Github Pages.<\/p>\n<p>Please leave any comments and feedback in the discussion section below, and thank you for reading!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR In the previous tutorial I showed you how to get started with Vue.js 3 by building a Giphy search application. That was a long while ago \ud83d\ude42,&hellip;<\/p>\n","protected":false},"author":1,"featured_media":4662,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,58],"tags":[],"class_list":["post-4661","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","category-vue-js"],"_links":{"self":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/4661","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/comments?post=4661"}],"version-history":[{"count":0,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/4661\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media\/4662"}],"wp:attachment":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media?parent=4661"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/categories?post=4661"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/tags?post=4661"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}