# Let's add some extra functionality

# Create the Actions component

First we have to move the actions footer from the App component to the TodosActions component.

Cut the footer with class "footer" from App and paste it to the TodosActions component inside the template tags. Then add the todos-actions tag in the same place.

<todos-actions />

It is now time to put some "actions" into the actions component. We will create a method that will set the active filter when we click on the anchors. Then we'll send the filter up to the mediator component and from there the computed filtered todos will change on the fly. It will also remain to do the cleaning of the completed ones.

Let's add the method to send the filter up the chain:

  1. Add a filter in the methods

Sending a value up to the parent component is done via the $emit method on any vue.js component. We create a method named changeFilter that will receive the new filter and will send it up. In the methods block of the component add:

,
 changeFilter(filter){
            if (filter)
                this.$emit('filterChanged', filter)
 }
  1. Change the anchor tags

Inside the template of the component we have to trigger this method and we do it using the click event. we also use the stop event modifier. Change the a tags using the specific filter as follows:

 <li>
    <a @click.stop="changeFilter('all')"  >All</a>
</li>
<li>
    <a  @click.stop="changeFilter('active')" >Active</a>
</li>    

Don't forget about the completed one!

  1. Send the active filter from the app component

In order to have access to the current selected filter we have to send it from the app component. This is done using the props property, that is an array, by adding inside the names of the data values from the parent like this(inside the script tag):

//TodosActions.vue
export default{
    props:['itemsAvailable','activeFilter'],

We added 2 properties from the parent because we also want to display the count of the filtered items.

  1. Set the selected class

Once we sent the filter up we also want to have the clicked anchor marked by the "selected class". The following could be one of the possible implementations: Inside the methods add a new one after the changeFilter

,
isClassSelected(cls){ 
    return this.activeFilter == cls ;}

Now let's update the anchor tags one more time.

<li>
    <a @click.stop="changeFilter('all')" :class="{selected: isClassSelected('all')}">All</a>
</li>
<li>
    <a  @click.stop="changeFilter('active')"  :class="{selected: isClassSelected('active')}" >Active</a>
</li>
<li>
    <a @click.stop="changeFilter('completed')"  :class="{selected: isClassSelected('completed')}" >Completed</a>
</li>

In this step we added the :class mapped to the result of the isClassSelected method. When the active filter matches the anchor filter then we set the anchor class to active.

  1. Update the items left counter

The last thing we have to do in the TodosAction component is to display the counter of the items left. For this to happen update the span marked by the todo-count class, like this:

<span class="todo-count">
    <strong> {{ itemsAvailable}}</strong> item(s) left
</span>

Next we update the App component to receive the event and to do something with it.

  1. Add the handler

Open the App.vue and then go to the template block and update the todos-list tag so that it will listen to the filterChange event. When the filterChange event is triggered from the child component the method attached to the event will be triggered.

<todos-actions @filterChanged="filterChangedHandler"  />
  1. Create the handler

This is where the action will end when the event is triggered. In the methods block, after the deleteTodoHandler, add a new method to handle the event:

,
filterChangedHandler(filter){
    this.filter = filter;
}
  1. Add filter data propery

The above method will set the value received to the filter data property of the component.

If we want this to work, we also have to update the data that the component knows about.

Update the data() method by adding one more property named filter.

data() {
    return { 
        ...,
        filter:'all'
        };
    }
  1. Create computed

Vue has a special property named computed . this one is special because it will evaluate every time whatever you use inside it, like the data properties, will change. What we want is to change the todos based on the selected filter. Every time the filter is changed the computed properties that uses it will be re evaluated! Let's add a computed property that will return the todos based on the current filter. Inside the export default object add a new propery named computed like this:

export default {
    .....,
    computed:{
        filteredTodos:function(){
        return {
            'all':this.todos,
            'completed':this.todos.filter(x=>x.isCompleted == true),
            'active':this.todos.filter(x=>x.isCompleted == false)
        }[this.filter.toLowerCase()];
        }
    },  

We also have to use this computed property if we want to see the filtered todos. This is done by updating the todos-list component by changing the :todos= from todos to filteredTodos like this:

<todos-list :todos="filteredTodos" @deleteTodo="deleteTodoHandler"  />               

It remains only to update the actions so that we use the active filter and the items cound:

<todos-actions
    :activeFilter="filter"
    :itemsAvailable="filteredTodos.length"
    @filterChanged="filterChangedHandler"
    />

# Well done !


Return Home