Filtering the list

We did a lot of work in laying a foundation for the app in the last step, so now we’ll do something simple: we will add full text search (yes, it will be simple!).

Modifying beer-list template

We use Twitter Bootstrap column model to divide the page in two (fully responsive) columns, the left one for the search box, the right one for the beer list.

We need to add a standard HTML <input> tag, give them some magical data-binding properties and adding a filtering function to the v-for to show only the searched results.

This lets a user enter search criteria and immediately see the effects of their search on the beer list.

Let’s begin by modifying the template to add the search input.

<div class="container">
    <div class="row">
        <div class="col-md-3">
        <!--Sidebar content-->
        <div>Search:</div> 
        <div><input id="searchInput"></div>
        </div>
        <div class="col-md-9">
            <div class="beers">
                <div class="beer" v-for="beer in beers">
                    <beer-list-item 
                        v-bind:name='beer.name'
                        v-bind:description='beer.description'>
                    </beer-list-item>
                </div>
            </div>
        </div>
    </div>
</div>  

Two-ways data-binding

Now we need to link the search input field value to a property of the object.

First we begin by declaring filterText as a internal state variable for the component, i.e. we put it in the data object:

data: function() {
    return { 
        filterText: '',   
        [...]
    };
}

In the template we use value to link the input event of the input item to the filterText data property, and we add a label under it to show the current value of filterText:


<div class="col-md-3">
    <!--Sidebar content-->
    <div>Search:</div> 
    <div>
        <input id="searchInput" v-model="filterText">
    </div>    
    <div>
        <div>Current search:</div>
        <div>{{filterText}}</div>
    </div>
</div>

when testing that you will learn that Vue.js templates need to have a single main tag, not two, so you will need to rewrite your whole template:

<div class="container">
    <div class="row">
        <div class="col-md-3">
            <div>Search:</div> 
            <div>
                <input id="searchInput" v-model="filterText">
            </div>
            <div>
                <div>Current search:</div>
                <div></div>
            </div>
        </div>
        <div class="col-md-9">
            <div class="beers">
                <div class="beer" 
                        v-for="beer in beers">
                    <beer-list-item 
                        v-bind:name='beer.name'
                        v-bind:description='beer.description'>
                    </beer-list-item>
                </div>
            </div>
        </div>
    </div>
</div> 

And now we have a two-way data-binding between the input field and the label under it.

Vue Beers

Affligem Tripel

The king of the abbey beers. It is amber-gold and pours with a deep head and original aroma, delivering a complex, full bodied flavour. Pure enjoyment! Secondary fermentation in the bottle..

Rochefort 8

A dry but rich flavoured beer with complex fruity and spicy flavours..

Chimay Rouge

This Trappist beer possesses a beautiful coppery colour that makes it particularly attractive. Topped with a creamy head, it gives off a slight fruity apricot smell from the fermentation. The aroma felt in the mouth is a balance confirming the fruit nuances revealed to the sense of smell. This traditional Belgian beer is best savoured at cellar temperature .

Adding a filter to the list

Now we want to use that filterText property to filter the list.

In order to do it we can use a filteredText depending on filterText. The methods of a Vue component are called everytime the depending properties change.

So we add a filteredText object to our beer-list component options:

methods: {
    filteredList: function (beers,filterText) {
        if (!filterText) {
            return  [ ... beers];;
        }
        return beers.filter( (beer) => {
            return beer.name.match(new RegExp(filterText, 'i'));
        })
    }
},

And in the v-for directive, we iterate on the filtered list:

<div class="beer" v-for="beer in filteredList(beers, filterText)">
    <beer-list-item 
        v-bind:name='beer.name'
        v-bind:description='beer.description'>
    </beer-list-item>
</div>

And now we have a working filter for our beers!

Vue Beers

Affligem Tripel

The king of the abbey beers. It is amber-gold and pours with a deep head and original aroma, delivering a complex, full bodied flavour. Pure enjoyment! Secondary fermentation in the bottle..

Rochefort 8

A dry but rich flavoured beer with complex fruity and spicy flavours..

Chimay Rouge

This Trappist beer possesses a beautiful coppery colour that makes it particularly attractive. Topped with a creamy head, it gives off a slight fruity apricot smell from the fermentation. The aroma felt in the mouth is a balance confirming the fruit nuances revealed to the sense of smell. This traditional Belgian beer is best savoured at cellar temperature .