Nikola Brežnjak blog - Tackling software development with a dose of humor
  • Home
  • Daily Thoughts
  • Ionic
  • Stack Overflow
  • Books
  • About me
Home
Daily Thoughts
Ionic
Stack Overflow
Books
About me
  • Home
  • Daily Thoughts
  • Ionic
  • Stack Overflow
  • Books
  • About me
Nikola Brežnjak blog - Tackling software development with a dose of humor
JavaScript, Vue.js

Getting started with Vue.js 3 by building a Pokemon search application

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 🙂, so here’s a new and updated post.

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.

So, in this post, you’ll learn how to use create-vue (official Vue project scaffolding tool) to build a Vue.js 3 application for searching Pokemon by using Poke API.

Introduction – The Battle is Over Indeed

A few years ago, this was a popular meme. It was funny because it was true 🙂

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 😉) frameworks established themselves:

  • Angular (93k)
  • React (218k)
  • Svelte (75k)
  • Vue.js (206k v2, 43k v3)

I added the number of Github *s (at the time of this writing), but I don’t want you to read into that too much 🤗

Analysis paralysis will, well, paralyze you!

You could argue that there are other options like Ember, Mithril, or good ‘ol jQuery even! However, this tweet says it all:

Developers are fighting over which frontend framework is better.. it’s not like users know or care. They mostly care about the User Experience. UX should be our focus on the frontend.

Personally, I stuck to the Angular bandwagon since version 1.0, but that started losing its ooomph after versions 2, 3, 4, … sorry, lost count.

I believe that Vue.js (due to its progressive and flexible nature) is a perfect fit for teams that have to rewrite old codebases one step at a time. However, you can also use it as a full-blown framework if you wish.

Personally, React’s JSX just seems wrong, and some people, smarter than me, swear by that being TheRightWay™, and I guess we’re not here to discuss tastes…

Recently I checked out Svelte and kinda like it, so will be doing a post like this for it; stay tuned.

General ‘framework war’ kind of questions I tend to answer in the following way:

Please just stop with the analysis paralysis already.

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.

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.

Besides, nowadays speed will not be a deciding factor among the top JS frameworks.

With all this out of the way, fasten your seatbelts, take a venti (or trenta) sized cup of coffee, and let’s go do something practical! 💪

The Demo App

As said in the intro, we’ll build an application for searching (and showing) Pokemon by using Poke API.

You can fork the complete source code on Github.

I’m using Vue.js 3, and I’ll be referring to it as just Vue in the rest of this post.

Prerequisites

Make sure that you have the following tools installed:

  • Node.js – here’s a free but outdated step by step guide/book for both Windows and Mac. Or, really, just go to the main website and download the executable for your machine
  • Git – here’s a fun getting started tutorial in case you’re new to it

Start a new app with create-vue

To start the project, run the following command (in your Terminal): npm create vue@latest

This command, as their docs say, will install and execute create-vue, the official Vue project scaffolding tool. You will be presented with prompts for several optional features such as TypeScript and testing support (I named the project PokemonSearch_Vue3):

✔ Project name: … PokemonSearch_Vue3
✔ Package name: … pokemonsearch-vue3
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit Testing? … No / Yes
✔ Add an End-to-End Testing Solution? › No
✔ Add ESLint for code quality? … No / Yes

Scaffolding project in /Users/Nikola.Breznjak/Development/Web/Vue/PokemonSearch_Vue3...

Done. Now run:

cd PokemonSearch_Vue3
npm install
npm run dev

In the previous blog post, we used Vue CLI. That has been deprecated and create-vue is now the default. The reasons that they quote are:

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.
Unlike 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.

You can learn more about ‘why’ Vite here.

Running our scaffolded project

Let’s run the commands (in terminal) noted in the previous output:

cd PokemonSearch_Vue3
npm install
npm run dev

You should get this output:

 VITE v5.0.12  ready in 175 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help

You should see the following page in your browser if you open http://localhost:5173.

Folder structure

Now, let’s open this project in the editor of your choice (I’m using Visual Studio Code + Volar extension), and you should see something like this:

This is an introduction tutorial, to get you running fast, so I won’t be going into any specific details and will be only focusing on the src folder.

Add content

OK, so let’s add something to our app.

But, where to start? 🤔

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.

So, if you search for the string You did it!, you’ll see the string is within the App.vue file. This file contains the following code:

<script setup>
import HelloWorld from './components/HelloWorld.vue'
import TheWelcome from './components/TheWelcome.vue'
</script>

<template>
  <header>
    <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />

    <div class="wrapper">
      <HelloWorld msg="You did it!" />
    </div>
  </header>

  <main>
    <TheWelcome />
  </main>
</template>

<style scoped>
header {
  line-height: 1.5;
}

.logo {
  display: block;
  margin: 0 auto 2rem;
}

@media (min-width: 1024px) {
  header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }

  .logo {
    margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }
}
</style>

Without knowing much about Vue.js, you can see where you would change the You did it! text. So, let’s change that to Welcome to Pokemon Search. Save that, and voila!, you’ll see the change reflected immediately in your browser.

Add some style

I borrowed the image (hope they don’t mind) from Wikipedia and saved it in the assets folder as logo.webp, added a search input, and styled it a bit to match it with the Pokemon style. In case you’re wondering, I asked ChatGPT to help with coming up with the style 🙂

Here’s the final code that I came up with in App.vue:

<template>
  <header>
    <img alt="Vue logo" class="logo" src="./assets/logo.webp" />
  </header>

  <main>
    <div class="search-container">
      <input class="search-box" type="text" placeholder="Search..." v-model="searchTerm">
    </div>
  </main>
</template>

<style scoped>
header {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.logo {
  margin: 0 2rem 0 0;
}

.search-container {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  gap: 10px;
}

.search-box {
  width: 30%;
  height: 50px;
  font-size: 1.5em;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
  margin: 40px 0;
  text-align: center;
}

Also, I did a few other smaller things:

  • added background: linear-gradient(to right, #FDDF3C, #3B4CCA); in the base.css file in the body tag
  • removed the main.css file altogether
  • imported base.css in the main.js file instead of main.css
  • removed the whole components folder

The way this looks now is as follows:

If you get stuck in any of the above steps, please reach out in the comments, and I’ll be happy to help.

Pokemon API

Finally, we come to the cool part 🥶, and that is to fetch some data from the PokeAPI and show it in our app.

How do we get this API? Well, if you do a simple Google search for pokemon api and open the first link, you’ll also get to the documentation for their API.

By looking at the docs, you can find that the API endpoint that lists all the available Pokemon is this: https://pokeapi.co/api/v2/pokemon. There’s a total of 1302 records.

Now, fetching all this data every time you load your app would be a bad idea from the performance standpoint, but also from their fair use policy.

So, what we will do is open this link which will fetch all 1320 Pokemon endpoints. The output looks something like this:

Now, save this output (just Command + S or Ctrl + s if you’re on Windows) to a local file that we’ll name pokemonapi.json and place this file in the src/assets folder.

⚠️ I just want to give proper props to PokeAPI for their awesome service 👏

For our demo purposes, this will be fine, but if you’d like to deploy this somewhere where you’d get a lot of traffic (or, if the main list of Pokemon changes), you’d have to cache the responses. We’ll tackle this in another blog post, but just something to keep in mind.

Show the data

Now we’ll want to list all the Pokemon that we have in the saved pokemonapi.json file. To do that, we’ll write some Javascript code in the top of the App.vue file that looks like this:

<script>
import pokemonData from './assets/pokemonapi.json';

export default {
  data() {
    return {
      pokemonList: pokemonData.results,
      searchTerm: '',
      selectedPokemon: null
    }
  },
  computed: {
    filteredPokemonList() {
      return this.pokemonList.filter(pokemon => pokemon.name.includes(this.searchTerm));
    }
  }
}
</script>

filteredPokemonList function returns the list of pokemon that we loaded from the pokemonapi.json file and filters them by what we enter in the input box.

And we’ll add this portion of HTML just below the search box:

<ul>
  <li v-for="pokemon in filteredPokemonList" :key="pokemon.id" class="pokemon-item">
    {{ pokemon.name }}
  </li>
</ul>

And, we’ll add a bit of CSS:

.pokemon-item {
  float: left;
  margin: 10px;
}
.pokemon-item a {
  color: #000;
  text-decoration: none;
  font-size: 16px;
  transition: color 0.3s ease;
  text-transform: capitalize;
}

.pokemon-item a:hover {
  color: #3B4CCA;
}

ul {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 5px;
  list-style: none;
}

Doing this, you should have your app look something like this:

Get additional details about each Pokemon

If you open any of the URLs that you see in the pokemonapi.json file, you will get something like this:

To show some additional information about a certain Pokemon (once clicked on its name in the list), we’ll update the li item by adding the a link to it like this:

<li v-for="pokemon in filteredPokemonList" :key="pokemon.id" class="pokemon-item">
  <a href="#" @click="showPokemon(pokemon.url)">{{ pokemon.name }}</a>
  </li>

On the click event we attached the showPokemon function (by using @click) and passed it the URL that we get in the main API call (loaded from the JSON file).

Now we should define this function in the methods object like this (I’m showing the contents of the whole script tag):

import pokemonData from './assets/pokemonapi.json';

export default {
  data() {
    return {
      pokemonList: pokemonData.results,
      searchTerm: '',
      selectedPokemon: null
    }
  },
  computed: {
    filteredPokemonList() {
      return this.pokemonList.filter(pokemon => pokemon.name.includes(this.searchTerm));
    }
  },
  methods: {
    async showPokemon(url) {
      const response = await fetch(url);
      if (!response.ok) {
        console.error(`Error fetching Pokemon: ${response.statusText}`);
        return;
      }

      this.selectedPokemon = await response.json();
      console.log(this.selectedPokemon);
    }
  }
}

To show the selected Pokemon, we’ll add a bit of HTML:

<div class="pokemon-details" v-if="selectedPokemon">
  <h2>{{ selectedPokemon.name }}</h2>
  <img :src="selectedPokemon.sprites.front_default" alt="selectedPokemon.name">
  <p>Height: {{ selectedPokemon.height }}</p>
  <p>Weight: {{ selectedPokemon.weight }}</p>

  <div v-for="(stat, index) in selectedPokemon.stats" :key="index">
    <p>{{ stat.stat.name }}: {{ stat.base_stat }}</p>
  </div>
</div>

We’re using v-if="selectedPokemon" so that the line {{ selectedPokemon.name }} doesn’t throw an error for trying to access a property that doesn’t exist on the object selectedPokemon (which is initialized as null in the beginnning).

We’re using v-for to loop through all the elements of the stats array and output the name and base_stat properties.

To make it look nicer, we’ll use a bit of CSS:

.pokemon-details {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 30%;
  margin: 20px auto;
  padding: 20px;
  border: 1px solid #000;
  border-radius: 10px;
  color: #000;
  text-transform: capitalize;
}

.pokemon-details img {
  width: 100px;
  height: 100px;
}

For reference, for those following the tutorial to the dot, here’s the full listing of HelloWorld.vue file:

<script>
import pokemonData from './assets/pokemonapi.json';

export default {
  data() {
    return {
      pokemonList: pokemonData.results,
      searchTerm: '',
      selectedPokemon: null
    }
  },
  computed: {
    filteredPokemonList() {
      return this.pokemonList.filter(pokemon => pokemon.name.includes(this.searchTerm));
    }
  },
  methods: {
    async showPokemon(url) {
      const response = await fetch(url);
      if (!response.ok) {
        console.error(`Error fetching Pokemon: ${response.statusText}`);
        return;
      }

      this.selectedPokemon = await response.json();
      console.log(this.selectedPokemon);
    }
  }
}
</script>

<template>
  <header>
    <img alt="Vue logo" class="logo" src="./assets/logo.webp" />
  </header>

  <main>
    <div class="search-container">
      <input class="search-box" type="text" placeholder="Search..." v-model="searchTerm">
    </div>

    <div class="pokemon-details" v-if="selectedPokemon">
      <h2>{{ selectedPokemon.name }}</h2>
      <img :src="selectedPokemon.sprites.front_default" alt="selectedPokemon.name">
      <p>Height: {{ selectedPokemon.height }}</p>
      <p>Weight: {{ selectedPokemon.weight }}</p>

      <div v-for="(stat, index) in selectedPokemon.stats" :key="index">
        <p>{{ stat.stat.name }}: {{ stat.base_stat }}</p>
      </div>
    </div>

    <ul>
      <li v-for="pokemon in filteredPokemonList" :key="pokemon.id" class="pokemon-item">
        <a href="#" @click="showPokemon(pokemon.url)">{{ pokemon.name }}</a>
      </li>
    </ul>
  </main>
</template>

<style scoped>
header {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.logo {
  margin: 0 2rem 0 0;
}

.search-container {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  /* Change the direction to row */
  gap: 10px;
}

.search-box {
  width: 30%;
  height: 50px;
  font-size: 1.5em;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
  margin: 40px 0;
  text-align: center;
}

.pokemon-item {
  float: left;
  margin: 10px;
}
.pokemon-item a {
  color: #000;
  text-decoration: none;
  font-size: 16px;
  transition: color 0.3s ease;
  text-transform: capitalize;
}

.pokemon-item a:hover {
  color: #3B4CCA;
}

ul {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 5px;
  list-style: none;
}

.pokemon-details {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 30%;
  margin: 20px auto;
  padding: 20px;
  border: 1px solid #000;
  border-radius: 10px;
  color: #000;
  text-transform: capitalize;
}

.pokemon-details img {
  width: 100px;
  height: 100px;
}
</style>

B e a utiful

At this point, we can search for some Pokemon (my son’s favorite is, ofc, Pikachu), and if we click on it, we’ll get something like this:

Deployment

If you’d like to host this on your web server, then first run npm run build and you’ll get an output similar to this:

Now all you have to do is take the contents of the dist folder and ‘paste’ it on your static web server.

If you don’t have a server of your own, then Vite has an extensive description for deploying your static pages (if you don’t have the ) to many popular services like Github Pages, Netlify, Vercel, Surge, etc.

You can deploy to Github Pages in under 2 minutes by following their documentation.

Just for brevity sake the steps are as follows:

  • create a new public Github repository and name it username.github.io, where username is your username on GitHub.
  • clone the repo with git clone https://github.com/username/username.github.io
  • inside the folder copy the contents of the dist folder
  • commit and push the changes:
git add --all 
git commit -m "Initial commit"
git push -u origin main

Now your site will be visible online at https://username.github.io (again, where username is your Github username)

You can check my deployment here.

Conclusion

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.

Please leave any comments and feedback in the discussion section below, and thank you for reading!

JavaScript, Vue.js

Getting started with Vue.js 3 by building a Giphy search application

TL;DR

In this post, you’ll learn how to use Vue CLI to build a Vue.js 3 application for searching Giphy’s GIFs by using their API.

Introduction – The War is Over

Let’s be honest; even those of us that actually don’t hate the JavaScript ecosystem can understand the frustration with the fact that new JS frameworks are popping up all the time.

This was especially true some 2-3 years ago. 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 😉) frameworks established themselves:

  • Angular (71k)
  • React (165k)
  • Svelte (45k)
  • Vue.js (181k)

I added the number of Github `*’s (at the time of this writing), but I don’t want you to read into that too much 🤗

Analysis paralysis will, well, paralyze you!

You could argue that there are other options like Ember, Mithril, or good ‘ol jQuery even! However, this tweet says it all:

Developers are fighting over which frontend framework is better.. it’s not like users know or care. They mostly care about the User Experience. UX should be our focus on the frontend.

Personally, I stuck to the Angular bandwagon ever since version 1.0, but that started losing it’s ooomph after version 2.

I believe that Vue.js (due to its progressive and flexible nature) is a perfect fit for the teams that have to rewrite old codebases one step at a time. However, you can also use it as a full-blown framework if you wish.

Personally, React’s JSX just seems wrong, and some people, smarter than me, swear by that being TheRightWay™, and I guess we’re not here to discuss tastes…

General’ framework war’ kind of questions I tend to answer in the following way:

Please just stop with the analysis paralysis already.

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.

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.

Besides, nowadays the speed will not be a deciding factor among the top JS frameworks.

With all this out of the way, fasten your seatbelts, take a venti (or trenta) sized cup of coffee, and let’s go do something practical! 💪

If you care about the hardcore metrics ⏱️ and want to check out some detailed comparisons between popular frontend frameworks, here are a few blog posts.

The Demo App

As said in the intro, we’ll build an application for searching (and showing) Giphy GIFs by using their API.

You can fork the complete source code on Github.

I’m using Vue.js 3, and I’ll be referring to it as just Vue.js in the rest of this post.

Prerequisites

Make sure that you have the following tools installed:

  • Node.js – here’s a free but outdated step by step guide/book for both Windows and Mac. Or, really, just go to the main website and download the executable for your machine
  • Git – here’s a fun getting started tutorial in case you’re new to it

Vue CLI

As their docs say:

Vue CLI aims to be the standard tooling baseline for the Vue ecosystem. It ensures the various build tools work smoothly together with sensible defaults so you can focus on writing your app instead of spending days wrangling with configurations. At the same time, it still offers the flexibility to tweak the config of each tool without the need for ejecting.

To install Vue CLI, run the following command (in your Terminal):

npm install -g @vue/cli

You can confirm that the installation went well if you run vue and get an output with usage information.

⚠️ Just for reference (in case you follow this tutorial at a later stage and something is not the same as I output it here), my version (get the output by running vue --version in your Terminal) as of this writing is @vue/cli 4.5.12.

Start a new app with Vue CLI

We’ll call our app, originally 🙈, giphy-search. So, to start a new app using Vue CLI, run:

vue create giphy-search

Make sure you select the option ❯ Default (Vue 3 Preview) ([Vue 3] babel, eslint) and press ENTER.

You should get an output similar to this:

Vue CLI v4.5.12
✨  Creating project in /Users/nikola/DEV/BLOG/giphy-search.
🗃  Initializing git repository...
⚙️  Installing CLI plugins. This might take a while...
🚀  Invoking generators...
📦  Installing additional dependencies...
📄  Generating README.md...
🎉  Successfully created project giphy-search.

After this command finishes, let’s cd into the project and run it:

cd giphy-search
npm run serve

You should get this output:

DONE  Compiled successfully in 3178ms

App running at:
  - Local:   http://localhost:8080/
  - Network: http://192.168.8.189:8080/

Note that the development build is not optimized.
To create a production build, run npm run build.

You should see the following page in your browser if you open http://localhost:8080.

Folder structure

Now, let’s open this project in the editor of your choice (I’m using Visual Studio Code), and you should see something like this:

This is an introduction tutorial, to get you running fast, so I won’t be going into any specific details and will be only focusing on the src folder.

Add content

OK, so let’s add something to our app.

But, where to start? 🤔

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.

So, if you search for the string Welcome to Your Vue.js App, you’ll see the string is within the App.vue file. This file contains the following code:

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <HelloWorld msg="Welcome to Your Vue.js App"/>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

Without knowing much about Vue.js, you can see where you would change the Welcome to Your Vue.js App text. So, let’s change that to Welcome to GiphySearch. While you do that, also remove the contents of the style tag.

In the App.vue file, we have a template tag that contains a standard HTML img tag and an HelloWorld tag, which is a so-called component. Here’s the link to the documentation where you can learn more about components.

Add an input and a button

Our basic application should have one input field and one button.

To do this, adjust the template in the HelloWorld.vue file to contain only this:

<div class="hello">
    <h1>{{ msg }}</h1>

    <input name="search" />
    <button>Search</button>
</div>

Actions

Having a simple search input field and a button doesn’t do much. We want to click the button, and we want to output something to the console just to verify it’s working correctly.

So, this is how you define a function that will handle a button click in Vue.js:

<button @click="performSearch">Search</button>

But, if you open your DevTools now and click the Search button, you’ll get an error like:

runtime-core.esm-bundler.js?5c40:38 [Vue warn]: Unhandled error during execution of native event handler
  at <HelloWorld msg="Welcome to GiphySearch" >
  at <App>
warn @ runtime-core.esm-bundler.js?5c40:38
logError @ runtime-core.esm-bundler.js?5c40:211
handleError @ runtime-core.esm-bundler.js?5c40:203
callWithErrorHandling @ runtime-core.esm-bundler.js?5c40:157
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js?5c40:163
invoker @ runtime-dom.esm-bundler.js?830f:327
runtime-core.esm-bundler.js?5c40:217 Uncaught TypeError: _ctx.performSearch is not a function
    at Object.onClick._cache.<computed>._cache.<computed> (HelloWorld.vue?fdab:6)
    at callWithErrorHandling (runtime-core.esm-bundler.js?5c40:154)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?5c40:163)
    at HTMLButtonElement.invoker (runtime-dom.esm-bundler.js?830f:327)

That’s because we haven’t defined the performSearch function anywhere.

Let’s do that now. In the HelloWorld.vue file, add the following function definition inside the script tag, methods object property:

<script>
export default {
    name: 'HelloWorld',
    props: {
        msg: String
    },
    methods: {
        performSearch() {
            console.log('clicked');
        }
    }
};
</script>

We defined the performSearch function, which doesn’t accept any parameters and it doesn’t return anything. It just outputs clicked in the console.

Gather input

What if we would like to output (to the console) the string that someone typed in the input field?

Well, first we need to add a new attribute to the input field:

<input name="title" v-model="searchTerm">

The v-model is a directive that instructs Vue.js to bind the input to the new searchTerm variable.

Finally, change the performSearch function to this:

performSearch: function() {
    console.log(this.searchTerm);
}

Technically, you could write this a bit differently, passing the searchTerm variable into the performSearch function as a parameter:

performSearch: function(searchTerm) {
   console.log(searchTerm);
}

<button @click="performSearch(searchTerm)">Search</button>

I'd love to hear from you in the comments which approach is better in your opinion.

Giphy search API

Finally, we come to the cool part 🥶, and that is to fetch some data from the Giphy API and show it in our app.

How do we get this API? Well, if you do a simple Google search for giphy api and open the first link, you’ll get the documentation for their API.

You need to follow these instructions to create an account (and an app) to get an API key. You don’t need an SDK solution at this point (you may want to go that route if you’re going to make a mobile app that shows these images).

After you obtain your API key through their dashboard, you’re going to be able to make search (they offer a bunch more) API requests through their API explorer.

An API URL (obviously, with the fake API key) may look like this: https://api.giphy.com/v1/gifs/search?api_key=AbC&q=cats&limit=10&offset=0&rating=g&lang=en

Great, now we see what kind of a request we need to create to search Giphy’s GIF database for a certain term.

If you open this link in the browser, you’ll see that the service returns something like:

In the next section, we’ll cover retrieving this data within our app.

⚠️ Since Giphy’s rules now require you to add attribution, make sure you add it. I added the image in the footer with a link to their docs.

Vue.js HTTP requests

We have several options for making HTTP requests in Vue.js, and some may see this flexibility as a pro, and some may see it as a con. Either way, for more options, check out this post.

I chose to go with Axios, as it’s a very popular JavaScript library for making HTTP requests. It’s an HTTP client that makes use of the modern Promises API by default (instead of the not so nice JavaScript callbacks 🙂) and runs on both the client and the server (i.e., Node.js).

In your Terminal enter the following command to install Axios via npm:

npm install axios --save

Import Axios in the HelloWorld.vue file just after the script tag:

import axios from "axios";

The performSearch function should now look like this:

let API_KEY = 'getYourOwn';
let link = `https://api.giphy.com/v1/gifs/search?api_key=${API_KEY}&limit=25&offset=0&rating=g&lang=en&q=`;
let apiLink = link + this.searchTerm;

axios
    .get(apiLink)
    .then((response) => {
        console.log(response);
    })
    .catch((error) => {
        console.log(error);
    });

Just for reference, to put it all in one listing, the contents of the HelloWorld.vue file should be:

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>

        <input name="search" v-model="searchTerm" />
        <button @click="performSearch()">Search</button>
    </div>
    <a href="https://developers.giphy.com/docs/api#quick-start-guide">
        <img src="giphy.png" alt="" class="giphyAttribution" />
    </a>
</template>






If you run the app and enter something in the input box, and then click the search button, you’ll see something like this in your console log:

You can see that we’re getting an object that in its data property has another data property (so meta 😎) that’s an array with 25 objects, which holds the information about the images we’ll show in our app.

Well, after a tongue twister in the previous sentence, this is all great, but we don’t want to be logging our objects to the console; we want to show them in our app! 🙂

To show the GIF, you can choose any of the properties under the images object, and use the url property. I used fixed_height_small in my example.

We don’t want to just show one image but all of the images. We can use the v-for directive for that:

<img v-for="g in giphies" :key="g.id" :src="g.images.fixed_height_small.url" />

For reference, here’s the full listing of HelloWorld.vue file:

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>

        <input name="search" v-model="searchTerm" />
        <button @click="performSearch()">Search</button>

        <img v-for="g in giphies" :key="g.id" :src="g.images.fixed_height_small.url" />
    </div>
    <a href="https://developers.giphy.com/docs/api#quick-start-guide">
        <img src="giphy.png" alt="" class="giphyAttribution" />
    </a>
</template>






B e a utiful

At this point, if we take a look at the app and search, for example, for ‘cat coding’ we’ll get this:

Although the result doesn’t look sleek (ha!, far from it 😳), our code does exactly what it’s supposed to do. If you want it to look nicer, feel free to add more CSS.

Bulma is a cool framework that I used in the JWT authentication in an Angular application with a Go backend post in case you’re interested in taking a look.

Conclusion

In this tutorial, you learned how to get started with using Vue.js 3 by building an application for searching Giphy’s GIFs by using their API.

Please leave any comments and feedback in the discussion section below, and thank you for reading!

Recent posts

  • Discipline is also a talent
  • Play for the fun of it
  • The importance of failing
  • A fresh start
  • Perseverance

Categories

  • Android (3)
  • Books (114)
    • Programming (22)
  • CodeProject (35)
  • Daily Thoughts (77)
  • Go (3)
  • iOS (5)
  • JavaScript (127)
    • Angular (4)
    • Angular 2 (3)
    • Ionic (61)
    • Ionic2 (2)
    • Ionic3 (8)
    • MEAN (3)
    • NodeJS (27)
    • Phaser (1)
    • React (1)
    • Three.js (1)
    • Vue.js (2)
  • Leadership (1)
  • Meetups (8)
  • Miscellaneou$ (77)
    • Breaking News (8)
    • CodeSchool (2)
    • Hacker Games (3)
    • Pluralsight (7)
    • Projects (2)
    • Sublime Text (2)
  • PHP (6)
  • Quick tips (40)
  • Servers (8)
    • Heroku (1)
    • Linux (3)
  • Stack Overflow (81)
  • Unity3D (9)
  • Windows (8)
    • C# (2)
    • WPF (3)
  • Wordpress (2)

"There's no short-term solution for a long-term result." ~ Greg Plitt

"Everything around you that you call life was made up by people that were no smarter than you." ~ S. Jobs

"Hard work beats talent when talent doesn't work hard." ~ Tim Notke

© since 2016 - Nikola Brežnjak