Creating the search component and using Vue slots

In order to let the users of LyricsFinder easily look for artists and songs, we will now create a search component.

Our specifications for this component are quite simple:

The search component will be a dumb component: it will emit events but will not know or care about what happens next. Actually, the home view will be responsible for listening and reacting to those events; as such, that view will be a smarter component.

Let's get started! Go ahead and create a Search.vue file in src/components.

To begin with, use the following skeleton for the component:

<template> 
  <el-container class="lf-search"> 
    TODO 
  </el-container> 
</template> 
 
<script lang="ts"> 
  import {Component, Vue} from 'vue-property-decorator'; 
 
  @Component({}) 
  export default class Search extends Vue { 
  } 
</script> 
 
<style scoped> 
 
</style> 
Notice that we've used an el-container again to wrap our content. Our component also uses a custom lf-search CSS class.

Let's work on the template.

Replace the TODO line in the el-container with the following code:

<el-input clearable placeholder="Artist or song to search for" prefix-
icon="el-icon-search"> <el-button slot="append" type="primary" icon="el-icon-
search">Search</el-button> </el-input>

We have now added the input field and the search button.

There are some interesting things in this code:

Another interesting detail is that the button is nested in el-input and has a slot property set to append. You might wonder what this all means.

Slots are a feature of Vue components enabling content projection. They're actually one more of those ideas borrowed from Angular. The concept of slots is that components can define places where elements can be inserted by its users.

Check out the references if you want to learn more about slots. If you're curious about the equivalent feature in Angular, then take a look at this article: https://blog.angular-university.io/angular-ng-content.

In this case, we have used the slot named append of the el-input component, which adds content after the input field. This approach is described here in detail: https://element.eleme.io/#/en-US/component/input.

Now, adapt the style tag as follows:

<style scoped> 
  .lf-search { 
    width: 100%; 
  } 
</style> 

This will increase the width of the container.

Now let's bind the input to the component's class. To do so, first add the following field to the class:

private searchText = '';

Then, in order to define the binding, follow these steps:

  1. Add v-model="searchText" to the el-input tag. To finish up, we need to implement the event handling as described in our specifications. Adapt the template again to handle the keyup, clear and click events.
  1. Add @keyup.enter.native="searchHandler()" to the el-input tag.
  2. Add @click="searchHandler()" to the el-button tag.

Thanks to those event handlers, LyricsFinder will now react to the Enter key press and to the button click.

Instead of the keyup event, you could also hook your event handler to the change event in order to react to more interactions (for example, copy/paste).

Next, import the Emit decorator at the top of the component's class:

import {Emit} from 'vue-property-decorator';

Finally, add the following methods to the same class:

public searchHandler(): void { 
  if ('' !== this.searchText) { 
    this.emitSearchEvent(); 
  } else { 
    this.emitSearchClearedEvent(); 
  } 
} 
 
@Emit('search-triggered') 
public emitSearchEvent(): string { 
  console.log('Emitting search triggered event'); 
  return this.searchText; 
} 
 
@Emit('search-cleared') 
public emitSearchClearedEvent(): void { } 

Our searchHandler method checks the state of the input field in order to decide whether to emit a search-triggered or a search-cleared event.

You can find the completed code of the search component here in the code samples: Chapter10/lyricsfinder-v1/src/components/Search.vue.

Our component is now ready; we can now add it to the Home view:

  1. Open the src/views/Home.vue file and update the template as follows:
<template> 
  <el-container class="lf-home-view" direction="vertical"> 
    <Search></Search> 
  </el-container> 
</template> 
  1. Then, update the @Component decorator as well:
@Component({ 
  components: { 
    Search, 
  }, 
}) 

Again, you'll need to also add the import.

  1. Take a look at the application now:

Great, now we're getting somewhere!

We have used direction="vertical" in order for the elements to stack vertically.

Next up, we're going to implement the event handling on the Home view and see how to fetch artists and songs using MusicService.

Here are a list of references: