Advanced Vue Features: Directives, Filters, and Mixins
Tags: vue, javascript
Published: 2020-04-13 15:48:28

---
title: Advanced Vue Features: Directives, Filters, and Mixins
published: true
description: Some more advanced Vue features can help you solve more specific code needs. In this tutorial, we explore directives, filters, and mixins.
tags: vue, javascript
canonical_url: https://blog.jscrambler.com/advanced-vue-features-directives-filters-and-mixins/
cover_image: https://blog.jscrambler.com/content/images/2020/04/jscrambler-blog-vue-directives-filters-mixins.jpg
---

Vue supports several advanced features that let us do things that other pieces of Vue code can't do.

To manipulate DOM elements in ways that aren't provided by built-in directives, we have to write our own directives.

If we want to format our output with reusable code, then we have to define our own filters. Filters are just functions that can be applied to templates.

Mixins are code that has reusable parts of a Vue component. We can add merge mixins into our Vue component code so that we can have one piece of code that's shared between multiple components.

In this article, we'll look at how to define and use Vue directives, filters, and mixins in our Vue apps.

## Directives

Vue directives are reusable pieces of code that let us manipulate DOM elements in our apps.

There are built-in ones like `v-model` to bind our input data into component model properties, and `v-show` which lets us show and hide elements with CSS based on some conditions.

The built-in Vue directives can't do everything - so, if we want directives with custom functionality, we have to create them ourselves.

We can define a global directive with the `Vue.directive` method with the directive name string as the first argument. The second argument is an object that has the directive hooks methods.

A directive can have the following hooks:

* `bind` - this is called only once: when the directive is first bound to the element. We can run the setup code that only runs once in this function.
* `inserted` - this is called when the bound element has been inserted into its parent node. The parent node is guaranteed to be present but it's not necessarily in the document.
* `update` - this is called after the containing components VNode has been updated but its children may not necessarily have been updated. The directive's value may or may not have changed.
* `componentUpdated` - this is called when the component's VNode and the VNode of its children have been updated
* `unbind` - this is called only once when the directive is unbound from the element.

For instance, we can define a simple app-wide directive as follows:

`index.js`

```javascript
Vue.directive("highlight", {
  inserted(el) {
    el.style.color = "red";
  }
});

new Vue({
  el: "#app"
});
```

`index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <p v-highlight>foo</p>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

In the code above, we defined the directive called `'highlight'` that has the inserted hook, which we used to change the color of the content that's bound to this directive. We changed the color of the content to red when the VNode is inserted into the virtual DOM tree with:

```javascript
el.style.color = "red";
```

The `el` above is the DOM element that the directive is bound to. Since DOM element objects have the `style` property (which has the `color` property), we can set it to set the color of the content of the DOM element.

`el` is used to manipulate the DOM directly.

Then, in `index.html`, we added the `highlight` directive into our template by writing `v-highlight`. Vue knows that anything with a `v-` prefix in the opening tag of an element is a directive. It'll look for the directive with the name without the `v-` prefix.

Therefore, the `p` element in `index.html` will have the red color applied to it.

We don't have to define and register directives globally, which makes them available for the whole app. We can also define directives that are only available within a component by adding a `directive` property into our component.

For instance, we can define a directive as follows:

`index.js`

```javascript
new Vue({
  el: "#app",
  directives: {
    highlight: {
      inserted(el) {
        el.style.color = "red";
      }
    }
  }
});
```

In the code above, we added the `directives` property to the Vue instance. Inside it, we added the `highlight` property so that we can add the same `highlight` directive as we did before.

Then, we can use them the same way we did before.

### Directive Hook Arguments
Hooks take multiple arguments. As we can see from the examples above, the `el` parameter is the first argument of the hook.

The second argument is `binding`, which is an object containing the following properties:

* `name` - the name of the directive without the `v-` prefix
* `value` - the value passed to the directive. For instance, if we have `v-directive:foo='1'` then `value` is 1
* `oldValue` - the value previously passed to the directive; it's only available in the `updated` and `componentUpdated` hooks. It's available regardless of whether the value has changed
* `expression` - the expression of the binding as a string. For instance, if we have  `v-directive:foo='1 + 2'` then `expression` is `'1 + 2'`
* `arg` - the argument passed into the directive. For instance, in `v-directive:foo`, `foo` is the value of `arg`
* `modifiers` - an object containing modifiers. For instance, if we have `v-directive.bar.baz` then the `modifiers` object value is `{ bar: true, baz: true }` 

The 3rd argument is `vnode` which is the virtual node object produced by Vue's compiler.

The last argument is `oldVnode`, which is the previous virtual node and it's only updated in the `update` and `componentUpdated` hooks.

All arguments other than `el` are read-only.

For instance, we can use them as follows:

`index.js`

```javascript
Vue.directive("padding", {
  bind(el, binding) {
    const { value } = binding;
    const { top, left, bottom, right } = value;
    el.style.padding = `${top || 0}px ${right || 0}px ${bottom || 0}px ${left ||
      0}px`;
  }
});

new Vue({
  el: "#app"
});

```

`index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <p v-padding="{ top: 30, bottom: 30, left: 20, right: 20 }">
        foo
      </p>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

In the code above, we have a `padding` that takes an object as its value and gets that object via the `binding` parameter of the `bind` method of the directive. Then, it takes the destructured values from the object that is passed into the directive.

We used those values to set the padding on each side of the p element.

### Dynamic Directive Arguments
We can have dynamic arguments in a directive. To add them into a directive, we can use the bracket notation in our template as follows:

`index.js`

```javascript
Vue.directive("top-position", {
  bind(el, binding, vnode) {
    const { value, arg } = binding;
    el.style.position = arg;
    el.style.top = `${value}px`;
  }
});

new Vue({
  el: "#app",
  data: {
    position: "fixed"
  }
});
```

`index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <p v-top-position:[position]="200">foo</p>
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

In the code above, we defined the `top-position` directive, which takes a number as a value and a dynamic `position` argument, which we've set as `'fixed'` in the `data` property of the `Vue` instance.

Therefore, the content of the `p` element will be moved 200px down from its regular position.

<a href="https://blog.jscrambler.com/how-to-protect-your-vue-js-application-with-jscrambler/?utm_source=dev.to&utm_medium=referral" target="_blank"><img alt="Protect your Vue App with Jscrambler" src="https://media.jscrambler.com/blog/V1-Vue.jpg"></a>

### Function Shorthand
If we only want the same behavior as on the `bind` and `update`, we can pass in a function as the 2nd argument of the `Vue.directive` method as follows:

```javascript
Vue.directive("top-position", (el, binding, vnode) => {
  const { value, arg } = binding;
  el.style.position = arg;
  el.style.top = `${value}px`;
});

new Vue({
  el: "#app"
});
```

The code above does the same thing as our previous example. The only difference is that it's shorter.

## Filters
Filters let us format data that we displayed on templates. They can be used in template interpolation and as expressions in `v-bind`.

We can define filters globally with the `Vue.filter` method as follows:

`index.js`

```javascript
Vue.filter("localeString", function(value) {
  if (value instanceof Date) {
    return value.toLocaleDateString();
  }
  return value;
});

new Vue({
  el: "#app"
});
```

`index.html`

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      {{new Date() | localeString}}
    </div>
    <script src="index.js"></script>
  </body>
</html>
```

In the code above, we defined the `localeString` filter. It's defined by the `Vue.filter` method with the filter name string passed in as the first argument and a function to transform the value into something we want to display as the second argument.

Then, in `index.html`, we used the `localeString` filter as we did in the `div`. Filters are applied by using the `|` symbol.

Therefore, we should get the current date as a formatted date string.

We can also define filters within a component as follows:

```javascript
new Vue({
  el: "#app",
  filters: {
    localeString(value) {
      if (value instanceof Date) {
        return value.toLocaleDateString();
      }
      return value;
    }
  }
});
```

In the code above, we have the `filter` property in our Vue instance. Inside it, we have the `localeString` function, which is our filter function.

It does the same thing as the global version we defined above, except that it only works within the component.

Filters can also be chained as follows:

```html
{{ message | capitalize | format }}
```

As a result, the `capitalize` and `format` filters are invoked one after the other.

Filters can also take an argument with an `arg` parameter as shown below:

```javascript
new Vue({
  el: "#app",
  filters: {
    multiply(value, arg) {
      if (typeof value === "number") {
        return value * arg;
      }
      return value;
    }
  }
});
```

Then, we can use it as follows:

```html
{{1 | multiply(2)}}
```

As a result, we see the number 2 displayed since 2 is passed into the `multiply` filter.

### Mixins
Mixins are reusable pieces of code that can be incorporated into multiple components.

A mixin is just an object with the regular properties of a Vue component like `methods` and hooks like the `created` hook.

For instance, we can create a mixin and use it as follows:

```javascript
const helloMixin = {
  created() {
    this.hello();
  },
  methods: {
    hello() {
      alert("hello");
    }
  }
};

new Vue({
  el: "#app",
  mixins: [helloMixin]
});
```

In the code above, we defined a mixin called `helloMixin`, which has the `created` hook. This hook calls the `hello` method defined in the `methods` property of a mixin.

Mixin hooks are merged into an array so that all of them will be called.

It’s worth it to note that mixin hooks are called before the component's own hooks.

Property hooks that have object values like `methods`, `components` and `directives` will be merged into one object.

A plain object mixin has to be explicitly incorporated into a component. However, we can also define a global mixin with the `Vue.mixin` method as follows:

```javascript
Vue.mixin({
  created() {
    this.hello();
  },
  methods: {
    hello() {
      alert("hello");
    }
  }
});

new Vue({
  el: "#app"
});
```

In the code above, we defined a mixin with the `Vue.mixin` method, which incorporates the mixin automatically into our Vue instance without writing any code to do so.

Therefore, we should use this carefully since it affects all components in our app.

## Conclusion
Directives are useful for manipulating the DOM. They take modifiers, expressions that are evaluated, and arguments to customize how a directive acts.

It can take various lifecycle hooks to let us run code when the VNode is added, when it updates, or when it uploads.

Filters are code that let us format our template data the way we wish. They can be chained and they also take arguments.

Mixins are reusable pieces of code that can be incorporated into components. They can either be defined globally, which automatically incorporates them into our components, or defined as an object, which has to be explicitly incorporated.

---

As a final word, if you're developing commercial or enterprise Vue apps, make sure you are protecting their code against reverse-engineering, abuse, and tampering by following <a href="https://blog.jscrambler.com/how-to-protect-your-vue-js-application-with-jscrambler/?utm_source=dev.to&utm_medium=referral&utm_campaign=advanced-vue-directives">this tutorial</a>.