---
title: Mixins
sidebarDepth: 3
---

# Mixins

`Feathers-Vuex` mixins provide quick and easy best practices directly inside a component's viewModel.  They are similar to [Renderless Data Components](./components.md), but are more powerful for two reasons.

1. You can do lots of them together. Handle multiple queries against multiple services at the same time.  The Renderless Data Components aren't capable of handling more than one query without doing ugly nesting.
2. They bring the data directly into the component's actual viewModel.  The Renderless Data Components only pull the data into the template scope, so the only clean way to get access to the data was by passing it to a component as props.  This is a great solution until you run into number 1, above.

If you're not using the [Feathers-Vuex Composition API](./composition-api.md), the mixins are probably going to be your preferred solution for development.

## Usage

Here are the steps to using mixins:

1. Import the `makeFindMixin` utility from FeathersVuex.
2. Register it in a component's mixins once for each query to be made in the component.
3. Provide a set of params in a computed property (getter only)
4. Iterate over the computed "items" prop named after the service.

```vue
<script>
import { makeFindMixin } from 'feathers-vuex' // Step 1

export default {
  name: 'ServerTaskList',
  mixins: [ makeFindMixin({ service: 'server-tasks' })], // Step 2
  computed: {
    serverTasksParams() {
      return { query: {} } // Step 3
    }
  }
}
</script>

<template>
  <div>
    <ul>
      <!-- Step 4 -->
      <li v-for="task in serverTasks" :key="task._id">
        {{task.name}}
      </li>
    </ul>
  </div>
</template>
```

In the above example, any records returned from the server will automatically show up when they become available.  It also automatically responds to realtime events when you're using one of FeathersJS's realtime transports, like Socket.io.

Notice in the above example that using the mixin automatically makes the `serverTasks` available in the template.  The mixins automatically setup a few properties in the viewModel based on the camelCased name of the service.  You can also provide a `name` attribute to override the defaults:

## makeFindMixin

### Options

- `service {String|Function}` - **required** the service path. This must match a service that has already been registered with FeathersVuex.
  - **{String}** - The service namespace
  - **{Function}** - Any provided function will become a computed property in the component and will be used to determine its value.
- `name {String}` - The name to use in all of the dynamically-generated property names. See the section about Dynamically Generated Props
- `items {String}` - The attribute name to use for the records.
- `params {String|Function}` - One of two possible params attributes.  (The other is `fetchParams`)  When only `params` is provided, it will be used for both the `find` getter and the `find` action.  When using server-side pagination, use `fetchParams` for server communciation and the `params` prop for pulling data from the local store. If the params is `null` or `undefined`, the query against both the API will be skipped. The find getter will return an empty array. **Default {String}: `${camelCasedService}Params`** (So, by default, it will attempt to use the property on the component called serviceName + "Params")
  - **{String}** - The name of the attribute in the current component which holds or returns the query object.
  - **{Function}** - A provided function will become a computed property in the current component.
- `watch {String|Array<String>}` - specifies the attributes of the `params` or `fetchParams` to watch.  When a watched prop changes, a new request will be made to the API server. Pass 'params' to watch the entire params object.  Pass 'params.query.name' to watch the 'name' property of the query. Watch is turned off by default, meaning only one initial request is made. **Default {String}: `${camelCasedService}Params`**
  - **{Boolean}** - If `true`: `[${camelCasedService}Params]` will be watched, else `[]`
  - **{String}** - The name of the component's prop to use as the value. Transformed to an `Array<String>`
  - **{Array<String>}** - Names of the component's prop
- `fetchParams {String|Function}` - when provided, the `fetchParams` serves as the params for the API server request. When `fetchParams` is used, the `param` attribute will be used against the service's local Vuex store. **Default: undefined**
  - **{String}** - The name of the attribute in the current component which holds or returns the params object.
  - **{Function}** - A provided function will become a computed property in the current component.
- `queryWhen {Boolean|String|Function}` - the query to the server will only be made when this evaluates to true.  **Default: true**
  - **{Boolean}** - As a boolean, the value provided determines whether this is on or off.
  - **{String}** - The name of the component's prop to use as the value.
  - **{Function}** - Any provided function will become a method in the component and will receive the current params object as an argument.
- `local {Boolean|String|Function}` - when true, will only use the `params` prop to pull data from the local Vuex store. It will disable queries to the API server. The value of `local` will override `queryWhen`. **Default:false**
  - **{Boolean}** - As a boolean, the value provided determines whether this is on or off.
  - **{String}** - The name of the component's prop to use as the value.
  - **{Function}** - Any provided function will become a computed property in the component and will be used to determine its value.
- `qid {String}` - The "query identifier" ("qid", for short) is used for storing pagination data in the Vuex store. See the service module docs to see what you'll find inside.  The `qid` and its accompanying pagination data from the store will eventually be used for cacheing and preventing duplicate queries to the API.

### Injected Properties

With `makeFindMixin` the following properties will be injected into your component and can become handy to use manually. Since the names of the mixin are basically dynamically generated by the `service` and `name` props you pass. Here the general names to understand what's going on under the hood:

#### Dynamically Generated Props:
```vue
<script>
// general
export default {
  data: {
    [IS_FIND_PENDING]: false, // `isFind${capitalized}Pending`
    [HAVE_ITEMS_BEEN_REQUESTED_ONCE]: false, // `have${capitalized}BeenRequestedOnce`
    [HAVE_ITEMS_LOADED_ONCE]: false, // `have${capitalized}LoadedOnce`
    [MOST_RECENT_QUERY]: null, // `${prefix}LatestQuery`
    [ERROR]: null // ${prefix}Error
  },
  computed: {
    [PAGINATION]() {/* ... */} // `${prefix}PaginationData`
    [ITEMS]() {/* ... */}, // `${items}` || `${name}` || `${camelCasedPluralService}`
    [ITEMS_FETCHED]() {/* ... */} // `${items}Fetched` || `${name}Fetched` || `${camelCasedPluralService}Fetched`
    [FIND_GETTER]() {/* ... */} // `find${capitalized}InStore``
  },
  methods: {
    [`${FIND_ACTION}DebouncedProxy`](params) {/* ... */}  // `get${capitalized}`
    [FIND_ACTION](params) {/* ... */}
  }
}
```
#### Example with `service: 'server-tasks`
```vue
<script>
// example with 'server-tasks' service
export default {
  mixins: [
    makeGetMixin({
      service: 'server-tasks' // depending on service
    })
  ],
  data: {
    isFindServerTasksPending: false,
    haveServerTasksBeenRequestedOnce: false,
    haveServerTasksLoadedOnce: false,
    serverTasksError: null
  },
  computed: {
    serverTasksPaginationData() { /* ... */ }
    serverTasks() { /* ... */ },
    serverTasksFetched() { /* .. */ },
    findServerTasksInStore(params) { /* ... */ },
  },
  methods: {
    findServerTasksDebouncedProxy(params) { /* ... */ },
    findServerTasks(params) { /* ... */ }
  }
}
</script>

```

## makeGetMixin

### Options

- `id {String|Function}` - when performing a `get` request, serves as the id for the request. This is automatically watched, so if the `id` changes, an API request will be made and the data will be updated.  If `undefined` or `null`, no request will be made.  **Default: undefined**
  - **{String}** - The name of the component's prop to use as the value.
  - **{Function}** - Any provided function will become a computed property in the component and will be used to determine its value.
- `service {String|Function}` - **required** the service path. This must match a service that has already been registered with FeathersVuex.
  - **{String}** - The service namespace
  - **{Function}** - Any provided function will become a computed property in the component and will be used to determine its value.
- `name {String}` - The name to use in all of the dynamically-generated property names. See the section about Dynamically Generated Props
- `item {String}` - The attribute name to use for the record.
- `params {String|Function}` - One of two possible params attributes.  (The other is `fetchParams`)  When only `params` is provided, it will be used for both the `find` getter and the `find` action.  When using server-side pagination, use `fetchParams` for server communciation and the `params` prop for pulling data from the local store. If the params is `null` or `undefined`, the query against both the API will be skipped. The find getter will return an empty array. **Default {String}: `${camelCasedSingularizedService}Params`** (So, by default, it will attempt to use the property on the component called serviceName + "Params")
  - **{String}** - The name of the attribute in the current component which holds or returns the query object.
  - **{Function}** - A provided function will become a computed property in the current component.
- `watch {Boolean|String|Array<String>}` - specifies the attributes of the `params` or `fetchParams` to watch.  When a watched prop changes, a new request will be made to the API server. Pass 'params' to watch the entire params object.  Pass 'params.query.name' to watch the 'name' property of the query. Watch is turned off by default, meaning only one initial request is made. **Default {Array}: `[]`**
  - **{Boolean}** - If `true`: `[${camelCasedService}Params]` will be watched, else `[]`
  - **{String}** - The name of the component's prop to use as the value. Transformed to an `Array<String>`
  - **{Array<String>}** - Names of the component's prop
- `fetchParams {String|Function}` - when provided, the `fetchParams` serves as the params for the API server request. When `fetchParams` is used, the `param` attribute will be used against the service's local Vuex store. **Default: undefined**
  - **{String}** - The name of the attribute in the current component which holds or returns the params object.
  - **{Function}** - A provided function will become a computed property in the current component.

- `queryWhen {Boolean|String|Function}` - the query to the server will only be made when this evaluates to true.  **Default: true**
  - **{Boolean}** - As a boolean, the value provided determines whether this is on or off.
  - **{String}** - The name of the component's prop to use as the value.
  - **{Function}** - Any provided function will become a method in the component and will receive the current params object as an argument.

- `local {Boolean|String|Function}` - when true, will only use the `params` prop to pull data from the local Vuex store. It will disable queries to the API server. The value of `local` will override `queryWhen`. **Default:false**
  - **{Boolean}** - As a boolean, the value provided determines whether this is on or off.
  - **{String}** - The name of the component's prop to use as the value.
  - **{Function}** - Any provided function will become a computed property in the component and will be used to determine its value.

### Injected Properties

With `makeGetMixin` the following properties will be injected into your component and can become handy to use manually. Since the names of the mixin are basically dynamically generated by the `service` and `name` props you pass. Here the general names to understand what's going on under the hood:

#### Dynamically Generated Props:
```vue
<script>
export default {
  data: {
    [IS_GET_Pending]: false, // `isGet${capitalized}Pending`
    [HAS_ITEM_BEEN_REQUESTED_ONCE]: false, // `has${capitalized}BeenRequestedOnce`
    [HAS_ITEM_LOADED_ONCE]: false, // `has${capitalized}LoadedOnce`
    [ERROR]: null // `${prefix}Error`
  },
  computed: {
    [ITEM]() { /* ... */ }, // `${item}` || `${name}` || ${camelCasedSingularService}`
    [GET_GETTER]() { /* ... */ } // `get${capitalized}FromStore`
  },
  methods: {
    [GET_ACTION]() { /* ... */ }  // `get${capitalized}`
  }
}
```
#### Example with `service: 'server-tasks`
```vue
<script>
// example
export default {
  mixins: [
    makeGetMixin({
      service: 'server-tasks' // depending on service
    })
  ],
  data: {
    isGetServerTaskPending: false,
    hasServerTaskBeenRequestedOnce: false,
    hasServerTaskLoadedOnce: false,
    serverTaskError: null
  },
  computed: {
    serverTask() { /* ... */ },
    getServerTaskFromStore(params) { /* ... */ },
  },
  methods: {
    getServerTask(params) { /* ... */ }
  }
}
</script>

```

## Patterns & Examples

### Dynamically Generated Props

Based on what options you provide to each mixin, some dynamically-generated props will be added to the current component.  Note that the example below only shows the return values from the computes, not the functions.

```js
makeFindMixin({ service: 'videos' }) = {
  data: () => ({
    isFindVideosPending: false,
    haveVideosBeenRequestedOnce: false,
    haveVideosLoadedOnce: false,
    videosLocal: false,
    videosQid: 'default',
    videosQueryWhen: true,
    videosWatch: []
  }),
  // Only showing the return values, not the actual functions
  computed: {
    // pulled from the store using the find getter
    videos: [ /* results */ ],

    // The pagination data with matching qid from the store
    videosPaginationData: {
      queriedAt: 1539682100148, // the timestamp of the last query
      query: {}, // The last query used with this qid
      ids: [], // The ids of the records returned in the response
      limit: 20, // based on the response from the server
      skip: 0, // The value of the $skip param in the query
      total: 1 // The total as reported by the server.
    },

    // The mixin will expect to find this. This won't be created automatically.
    videosQuery () {}
  }
}
```

If you were to handle two queries from the same service, you would use the `name` attribute to rename one of them.  The results would be named accordingly.  Note that the example below only shows the return values from the computes, not the functions.

```js
makeFindMixin({ service: 'videos', name: 'myVideos' }) = {
  data: () => ({
    isFindMyVideosPending: false,
    haveMyVideosBeenRequestedOnce: false,
    haveMyVideosLoadedOnce: false,
    myVideosLocal: false,
    myVideosQid: 'default',
    myVideosQueryWhen: true,
    myVideosWatch: []
  }),
  // Only showing the return values, not the actual functions
  computed: {
    // pulled from the store using the find getter
    myVideos: [ /* results */ ],

    // The pagination data with matching qid from the store
    myVideosPaginationData: {
      queriedAt: 1539682100148, // the timestamp of the last query
      query: {}, // The last query used with this qid
      ids: [], // The ids of the records returned in the response
      limit: 20, // based on the response from the server
      skip: 0, // The value of the $skip param in the query
      total: 1 // The total as reported by the server.
    },

    // The mixin will expect to find this. This won't be created automatically.
    myVideosQuery () {}
  }
}
```

### Using a dynamic service

It's possible to change the service name on the fly.  To do this, pass a function (which becomes a computed property) that returns another string property from the viewModel.  Below is an example of how to set that up.  The `serviceName` attribute is set to `"videos"`, initially.  The `setTimeout` in the `created` method changes the value to `"users"` after three seconds.  When the serviceName changes, the users service is queried automatically.  The `items` property will then update to be the newly fetched users instead of the video records that it contained before.  The `items` option is used to rename the items to something more generic.

```html
<template>
  <div>
    {{items}}
  </div>
</template>

<script>
import { makeFindMixin } from 'feathers-vuex'

export default {
  name: 'my-component',
  data: () => ({
    serviceName: 'videos'
  }),
  mixins: [
    makeFindMixin({
      service () { return this.serviceName },
      name: 'service', // the default value when `service` is a function.
      items: 'items' // the default value when `service` is a function.
    })
  ],
  computed: {
    serviceParams () {
      return { query: { $limit: 1 } }
    }
  },
  created () {
    setTimeout(() => {
      this.serviceName = 'users'
    }, 3000)
  }
}
</script>

<style lang="scss">
</style>
```

In the above example, the mixin data would look like this:

```js
const mixedInDataFromAboveExample = {
  data: () => ({
    isFindServicePending: false,
    serviceLocal: false,
    serviceQid: 'default',
    serviceQueryWhen: true,
    serviceWatch: []
  }),
  // Only showing the return values, not the actual functions
  computed: {
    items: [ /* results */ ],

    // The pagination data with matching qid from the store
    servicePaginationData: {},

    // The mixin will expect to find this. This won't be created automatically.
    serviceQuery () {}
  }
}
```

### Pagination with fall-through cacheing

The `makeFindMixin` in `feathers-vuex@2.x` features a great new, high performance, fall-through cacheing feature, which only uses a single query!  Read the service module documentation for details of how it works under the hood.  It really makes easy work of high-performance pagination.  To use the pagination, provide `$limit` and `$skip` attributes in `params.query`.  This is exactly the same way you would normally do with any FeathersJS query.  So this is completely transparent to how you'd normally do it.

> Note: By default, the pagination feature is turned on.  To simplify updating existing apps using `feathers-vuex`, you can turn this feature off in any part of your app by passing `paginate: false` in the params for that particular query.  This will completely restore the previous behavior and re-enable live lists.

Let's extend the first example on this page to support pagination.  We'll do the following:

1. Setup the `makeFindMixin` to use the `watch` property.
2. Add a `data` attribute to the component with `limit` and `skip` properties.
3. Reference the `limit` and `skip` in `params.query`.
4. Add methods for `previousPage` and `nextPage`
5. Create buttons for changing the limit and skip.

```vue
<script>
import { makeFindMixin } from 'feathers-vuex'

export default {
  name: 'ServerTaskList',
  mixins: [ makeFindMixin({ service: 'server-tasks', watch: true })], // Step 1
  data: () => ({ // Step 2
    limit: 5,
    skip: 0
  }),
  computed: {
    serverTasksParams() {
      return { query: { $limit: this.limit, $skip: this.skip } } // Step 3
    }
  },
  methods: { // Step 4
    previousPage() {
      this.skip = this.skip - this.limit
    },
    nextPage() {
      this.skip = this.skip + this.limit
    }
  }
}
</script>

<template>
  <div>
    <ul>
      <li v-for="task in serverTasks" :key="task._id">
        {{task.name}}
      </li>
    </ul>
    <!-- Step 5 -->
    <button @click="previousPage">Previous Page</button>
    <button @click="">Next Page</button>
  </div>
</template>
```

In the above example, since we've enabled the `watch` attribute on the makeFindMixin, every time the params change, the query will run again.  `feathers-vuex` will keep track of the queries and the pages that are visited, noting which records are returned on each page.  When a page is revisited, the data in the store will *immedately* display to the user.  The query will (by default) go out to the API server, and data will be updated in the background when the response arrives.

### Debouncing requests

What happens when a query with a watcher is attached to an attribute that might change rapidly?  A lot of API requests can get sent in succession.  If too many are sent, some of them will start to fail (a.k.a. bounce).  The `makeFindMixin` has a built-in utility for debouncing requests.  Enabling it makes it so requests only are sent after a specific amount of time has passed.  To enable it, pass a `debounce` attribute in the `params`, as shown in the next example.

Let's build on our previous example by adding a `search` feature where the user can type some input.  Here are the steps:

1. Add an attribute to the data to which we will bind user input. We'll call it `search`.
2. Modify params to include the `search` attribute in a supportive way.
3. Enable the the debounce feature.
4. Add an `input:text` to the template which binds to the attribute in step 1.

```vue
<script>
import { makeFindMixin } from 'feathers-vuex'

export default {
  name: 'ServerTaskList',
  mixins: [ makeFindMixin({ service: 'server-tasks', watch: true })],
  data: () => ({
    limit: 5,
    skip: 0,
    search: '' // Step 1
  }),
  computed: {
    serverTasksParams() {
      return {
        query: {
          $limit: this.limit,
          $skip: this.skip,
          name: { $regex: this.search, $options: 'igm' } // Step 2
        },
        debounce: 500 // Step 3
      }
    }
  },
  methods: {
    previousPage() {
      this.skip = this.skip - this.limit
    },
    nextPage() {
      this.skip = this.skip + this.limit
    }
  }
}
</script>

<template>
  <div>
    <!-- Step 4 -->
    <label for="server-task-search">
      Search Server Tasks by Name
    </label>
    <input
      v-model="search"
      id="server-task-search"
      type="text"
      placeholder="Enter a task name"
    />

    <ul>
      <li v-for="task in serverTasks" :key="task._id">
        {{task.name}}
      </li>
    </ul>
    <button @click="previousPage">Previous Page</button>
    <button @click="">Next Page</button>
  </div>
</template>
```

Notice a couple of things in the above example.  We enabled the internal `debounce` feature by simply adding `debounce: 500` to the params (outside the query).  This means that as the user types, requests will be queued inside a 500 ms interval.  The request will be sent as soon as the user stops typing for 500 milliseconds.  For example, if the user types a single character, waits ~400ms, then types a second character, the first request will be cancelled and another request will be sent 500ms after typing the second character.  It's more likely that these requests will not bounce. :)

We also added a `$regex` search to the params.  This is a MongoDB feature, which naturally also works with Mongoose services (since Mongoose is a tool built for MongoDB).  If you're using another type of service, you will need to come up with a solution for performing searches safely.  The solution will vary depending on the database used.

Feel free to make a PR for using something else that could be useful to the community!  We love those!

### Enabling live lists with pagination

The new fall-through cacheing pagination does not currently support live sorting of lists.  This means that when a new record arrives from the database, it doesn't automatically get sorted into the correct page and shuffle the other records around it.  The lists will update as the user navigates to previous/next pages.  Coming up with a solution for this will be a top priority after 2.x ships.  In the meantime, here are some alternatives.

### Use `paginate:false` in the params

Restore the previous default behavior by putting `paginate:false` in the params.  This is the easiest way to upgrade existing apps using the `makeFindMixin`.  Look at the `todosParams` in this example:

```vue
<script>
import { makeFindMixin } from 'feathers-vuex'

export default {
  name: 'SomeExampleComponent',
  mixins: [makeFindMixin({ service: 'todos', watch: true })]
  computed: {
    todosParams() {
      return {
        query: {},
        paginate: false // This restores previous functionality
      }
    }
  },
  methods: {
    refresh() {
      this.findTodos()
    }
  }
}
</script>

<template>
  <div>
    <TodosList :items="todos"></TodosList>
    <TodoEntryForm @created="refresh"></TodoEntryForm>
  </div>
</template>
```

The `paginate` property will not be sent to the server, but it will locally disable the pagination and enable the live lists from the `find` getter.

### Refresh the current query after changes

This is a simplistic approach. In some cases, when you expect the data to have changed in whatever list you are currently showing to the user, you can simply call the find action for that list and get new data from the server.  In the below example, whenever the `TodoEntryForm` component emits the `created` event, it triggers the `findTodos` method.  Note: you wouldn't want to do `@created="findTodos` because that would potentially pass the new todo as the params like `findTodos(newTodo)` instead of `findTodos()`.  Passing no params will automatically use the `todosParams` for the query.

```vue
<script>
import { makeFindMixin } from 'feathers-vuex'

export default {
  name: 'SomeExampleComponent',
  mixins: [makeFindMixin({ service: 'todos', watch: true })]
  computed: {
    todosParams() {
      return { query: {} }
    }
  },
  methods: {
    refresh() {
      this.findTodos()
    }
  }
}
</script>

<template>
  <div>
    <TodosList :items="todos"></TodosList>
    <TodoEntryForm @created="refresh"></TodoEntryForm>
  </div>
</template>
```

### Use the "FetchQuery" params

Let's suppose we have a todos service that we're mixing into our component:

```js
makeFindMixin({ service: 'todos', watch: true })
```

The `makeFindMixin` by default will look for a single set of params called `todosParams`. If it finds only this set of params, the params will be used for fetching data and pulling it from the Vuex store.  However, if another set of params, called the `todosFetchParams`, this new set of params will be used to fetch data and the `todosParams` will be used against the internal store.  In this scenario, the internal pagination tracking is also turned off, which allows you to make queries directly against the Vuex store again.

```vue
<script>
import { makeFindMixin } from 'feathers-vuex'

export default {
  name: 'SomeExampleComponent',
  mixins: [makeFindMixin({ service: 'todos', watch: true })]
  computed: {
    // This query will retrieve all records from the local Vuex store.
    todosParams() {
      return { query: {} }
    },
    // This query will retrieve 10 records from the API server.
    todosFetchParams() {
      return {
        query: {
          $limit: 10,
          $skip: 0
        }
      }
    }
  },
  methods: {
    refresh() {
      this.findTodos()
    }
  }
}
</script>

<template>
  <div>
    <TodosList :items="todos"></TodosList>
    <TodoEntryForm @created="refresh"></TodoEntryForm>
  </div>
</template>
```

### Debugging the makeFindMixin

**Important: For the built in pagination features to work, you must not directly manipulate the `context.params` object in any hooks.**

If the makeFindMixin is not returning any results, but you can see the results coming in across the websocket  or rest transport, make sure you're not directly modifying the `context.params` object in a hook, as mentioned in bold, above. ;)  The best place to debug if this is your issue is in `make-find-mixin` in the `[ITEMS]` computed property.  Set a breakpoint at `const items = getItemsFromQueryInfo(pagination, queryInfo, keyedById)`.  Maybe even make it a conditional breakpoint around the `serviceName` variable: `serviceName === 'assets' && Object.keys(keyedById).length > 0`.

When you hit the above breakpoint, check the `keyedById` variable.  If it has records, but the `items` is an empty array, there may be a problem with the `queryInfo` not matching from the `context.params` getting modified.
