Today we’ll build an application using VueJS, but we can’t just do a todo app as is customary (that’s already been done anyway). We needed something a bit more complicated, so we’ll build an application that shows a paginated list of items (tutorials in this case, but it can easily be retrofitted with other data types) that can be filtered by a search bar or some radio options. This tutorial assumes you know Vue, or know how to traverse the docs, so it’s more of an example of what it can do than it is tutorial in how to use Vue.

What you see in this tutorial is only the first step, though. In future iterations, you will see how Vuex, Vue-Router and connecting to an API server should look. Until then, we’ll just be using Vue (and Boostrap… don’t judge, we just needed something that would help me do this quickly).

Getting Set Up

Before we get started, note that there is a repo on Github for this project. The ‘tutorial-1’ branch refers to the iteration that we’re building today.

The first thing we need to do is get the project set up. The easiest way to do this is with vue-cli because it will scaffold out a base application for us with a nice build system and development workflow. So let’s install it via npm and use it right away:

npm install -g vue-cli

vue init webpack tutorial-search

cd tutorial-search

npm install

We’ll be using the ‘webpack’ template because it has all the tools we need, including Babel so we can use ES6/ES2015, and we need to choose something. When running init you’ll need to fill in some information about the project: enter in whatever Project Name, Description, and author information you think is appropriate, choose “Runtime-only” since we’ll be using single file components and won’t need to compile templates at runtime. You can answer “no” (technically “n”) to the rest of the questions because there won’t be enough time/space in this article to go over using those technologies, but you’re free to use them if you wish. Then, after running the rest of the commands, everything should be set up for us. Run npm run dev to see if it works for you. You can keep that running if you’d like, but it’ll probably end up showing a lot of errors until we’re done.

Now we need to install Bootstrap and strip out the bits that we don’t want from the tiny app that already exists. npm install -S bootstrap@3 gets us Bootstrap. Then we’ll delete /src/components/Hello.vue , move /src/App.vue into the /src/components/ folder because it is a Vue component, so why shouldn’t it be in there with the rest of them. Then, finally we need to edit our /src/main.js :

Change the line that imports App to import from ./components/App because we moved the file

to import from because we moved the file Add an import for Bootstrap with import 'bootstrap/dist/css/bootstrap.css' .

. While you’re in here, you might as well delete that ESLint comment, since we’re not using ESLint.

The Application Foundation

Now we need to move on to App.vue . First we’ll create some of the basic static elements of the application:

Tutorial Finder Use the search box and technology selector to find a tutorial you’re looking for.

Displaying Tutorials

Now we have a foundation, but we also need some data to show before we try to build any components that display/filter that data. So let’s create /src/data.js and fill it with the code you see on GitHub. It’s relatively large (167 lines), so it’s probably not a great idea to just plop it in here. It has two bits of data:

technologies contains the keys, display name, and color for each technology that we’ll be filtering by. We’ll use that later on, but right now we’re going to focus on the other data.

contains the keys, display name, and color for each technology that we’ll be filtering by. We’ll use that later on, but right now we’re going to focus on the other data. tutorials contains a list of all of the tutorials and that’s what we’ll need right now.

Now that we have that, let’s add it to the App component:

So here, we’re importing the data and on creation of the component we’re “filtering” the tutorials. Currently there isn’t any actual filtering; we’re just assigning all of the tutorialData to our tutorials property. Now we should display those tutorials, so let’s create /src/components/TutorialList.vue and fill it with the following:

The styles are just for creating a simple flexbox grid instead of relying on Boostrap’s rows and columns (easier to work with programmatically). Otherwise it’s just a simple container and looping to create child “ components, so let’s create /src/components/Tutorial.vue and fill that in next :

{{ item.description }}

let parser = document.createElement('a')

export default { name: 'tutorial', props: ['item'], components: { TechLabel }, methods: { domainOf: url => ((parser.href = url), parser.hostname.replace(/^www\./, '')) } }

This component just displays a lot of the data about the tutorial in a nice readable fashion. We use a simple trick to parse the URLs and to display just the domain rather than using a parsing library, and we throw some labels at the end to display what technologies are covered in the tutorial, which brings us to the next component, which will be in /src/components/TechLabel.vue :

{{ text }}

Here, we finally use the technologies data to find the display text and color for the labels. So let’s add this TutorialList to the App . We’ll need to add TutorialList into the template, import it, and list it in the components property. The comments below show you what changes need to be made:

... ...

If you’ve been able to follow along well up to this point, you can run npm run dev and see something like this:

Pagination

Right now we’re displaying all 22 results in one big list. It’s not that big of a deal, but if we had more data, it’d be pretty messy, so let’s throw some pagination in there. We’ll do this by creating a Pagination component ( /src/components/Pagination.vue ). If you think about it, a pagination component is really just a kind of input (similar to a list of radio buttons or a select box, but using links as the underlying mechanism rather than a built-in input) with the pages you can choose from and the value equals the selected page, so we’re going to set up our Pagination component to be able to accept a v-model so we’ll be updated with the selected page every time one is clicked. This is based on vue-pagination-2, but “chunking” was stripped out and it was converted into an input using v-model instead of using a global store/bus. Here’s the code:

return parts[i].replace('{count}', this.items).replace('{from}', from).replace('{to}', to) } }, methods: { setPage: function(page) { if (this.allowedPage(page)) { this.page = page this.$emit('page-change', page) } }, next: function() { return this.setPage(this.page + 1) }, prev: function() { return this.setPage(this.page - 1) }, allowedPage: function(page) { return page >= 1 && page

It's a little complicated. We pass in the number of items there are in the list ( items ) and the number of items should show on each page ( perPage , defaults at 10), and it'll calculate how many pages you need. You can pass in the currentPage to set which page you're on. When the page changes, it'll emit a 'page-change' event to alert you to the new value, or, thanks to the model property, we can just use v-model so it'll automatically update us to the new value.

Before we add the pagination to App , though, we'll need a way to only display the portion of the tutorials that belong on the selected page, so we'll create a utility function in /src/utilities/get-array-section.js :

export default function(arr, sectionNumber, sectionSize) { let totalSections = Math.ceil(arr.length / sectionSize) sectionNumber = Math.min(sectionNumber, totalSections) let from = (sectionNumber - 1) * sectionSize let to = Math.min(from + sectionSize, arr.length) return arr.slice(from, to) }

This function takes the full array, a page/section number and how many items should be in each section, and then returns the bit of the array that fits in that section. Now let's add pagination to the App component. The comments below show you what changes need to be made:

... ...

Cool. Now our list is paginated. You'll notice that when you change the page, though, that the pages are changed quite suddenly.

Transitions

Let's throw a transition in there to make things look smoother. To do this, we'll work inside the TutorialList component and add the changes noted in the comments below:

...

It should look like this now:

Isn't that gorgeous? Okay, maybe not gorgeous, but very nice, especially considering how little we had to do to achieve it.

Search Filter

But now we need some filtering! We'll start by filtering by keywords with a search box. So let's create /src/components/SearchBox.vue :

We honestly didn't need a custom component for this, but it helps clean up App a bit and allows us to use this same component elsewhere in the future with the same wrapper elements and styles with very little effort. Anyway, let's add filtering by this search box into the App , following the instructions in the comments:

...

...

...

That should all be working fine and you can search for keywords to your heart's content! Note that the transition happens when you're searching too. That's pretty cool, huh?

Tech Selector Filter

Now let's move on to our final filter: the radio buttons that allow you to select only tutorials that talk about that technology. To do this, we'll create /src/components/RadioGroup.vue :

All

Here we're adding a radio button for each technology, labeling them with the same TechLabel s we used previously. We also add a default "All" option so we can continue to see all of the tutorials if we would like to. And RadioGroup acts like a single custom input, just like SearchBox did, so we can use it in a very similar manner in App , so let's get that in there:

...

...

...

And that's it. You should have a fully working tutorial searching application to play with. npm run dev to see it in action or npm run build to build it and you can run it on a separate server.

Conclusion

Whew! That was a lot of code in a short amount of time. If you have any questions about design decisions or how something works, feel free to ask via an issue on the repo. You'll likely find a quicker reply on there versus using the comments section here (though feel free to leave comments here if you're not looking for quick replies). Thanks for reading!

Explore JavaScript Courses