Vue.js ❤️ Craft CMS - Single Page App: Searching or Filtering Entries by Title

Turns out writing a series is time consuming!

For those of you that are still with me, apologies. I've been cranking out a lot of work on a new Laravel side project that is going to act as a vehicle for another Laravel side project I have in the works so those, along side my day job, have been taking up all of my time.

That said, I'm producing this content for free and we never agreed a timeframe 😉

I'm currently (time of writing at least) on a flight from London to NYC for Laracon this week so I've got time (yay for disconnection in flight AKA as being too cheap to pay for wifi).

So, back to Vue and Craft and recap where we are.

  1. I've bootstrapped the app
  2. I've got routes
  3. I've got my content API from Craft

Next I want to search over the entry titles. I've called this searching/filtering as they're essentially the same thing and it might help the Google machine.

Now, I have debated (with myself) as to how I demonstrate this. The first time, I built things out, I had all of my logic in a single Vue component, it worked fine but it's a lot of code for a single component.

As I looked for ways to refactor, splitting my code into multiple Vue components made the most sense but then I was wondering why my existing logic didn't work. Turns out, for Vue components to communicate with one another you need an event bus or Vuex. The event bus method is straight forward enough but I think if you're at this point, you may as well just go for Vuex.

Vuex is Vue's first party State Management plugin. I can say that in the Vue apps I've built since, I generally opt to use Vuex because it's just easier to run with regardless of the size of your app.

However, I feel like covering Vuex would be too ambitious for this series of posts. If you're really keen, I'll share what I've got working in Vuex in another repo. So, to demonstrate the concept of search across a single entry attribute (the title) we'll just add the search logic to our existing component.

With all that said, let's get back into some code, specifically JobList.vue and I'm going to add

into the <template> after its first HTML element.

Hopefully the markup speaks for itself as to what it'll do but it will search entries (in my case jobs) based on their title.

The key part to this in the markup is the v-model="keyword" that will tie into the keyword that I'm just about to add into the data function within the script section of my component. All this is going to do is set our keyword model value to be empty when we first load the app.

With that set, I need a function that will actually perform the search. I'll add this outside of the rest of my export default

Now this is just pure JavaScript, nothing Vue about it at this point, apart from sharing some names of variables and parameters.

If you're not familiar with what's going on here, the function is getJobByKeyword and I'm passing 2 params into the function, jobs and keyword. Then I'm creating a new constant called search that will be the keyword, trimmed to lowercase.

If there's no value to search, then I want all jobs/entries else return my jobs filtered by the name of the item.

Now I need to hook this up to my Vue instance and for that, I'll need a computed property on my Vue instance and I'm going to call it filteredByKeyword.

Again, this computed property is just a pure JS function returning another JS function and passing in my jobs and the value of my keyword as parameters to that function.

Next, I need to change out my v-for loop. It'll become v-for="jobs in filteredByKeyword" and for good measure, I'll add an <h1> directly above that with <h1>Showing {{ filteredByKeyword.length }} entries</h1> so that I can see the number of entries I have initially and then should see that count decrease as I filter them.

So JobList.vue should now look like

If I save all of that, kill any previous npm tasks I was running, restart npm run hot and start searching, my entries should start to filter by their title and my count should change as well 🙌🏻

That will do for this post.

As you'll see below, I've included a new subscription option to get notified of new posts on Vue with Craft. There's no Mailchimp here my friend, just a simple contact form that will help me send posts relevant to this one because Twitter isn't always the best way to get content updates.

There's also those pesky share buttons to make it super-simple to share with your peers.

As always, if there's something I've implemented you think is dumb or just plain wrong - call me out on it and @me