# Service Plugin
The makeServicePlugin method creates a vuex plugin which connects a Feathers service to the Vuex store. Once you create a plugin, you must register it in the Vuex store's plugins section.
# Setup
See the setup documentation to learn the basics of setting up a Service Plugin.
# Configuration
The following options are supported on makeServicePlugin:
import Model from "../users.model";
const servicePath = 'users'
const servicePlugin = makeServicePlugin({
// necesarry
Model,
service: feathersClient.service(servicePath),
// optional and configurable also by global config
idField: 'id',
tempIdField: '__id',
nameStyle: 'short',
debug: false,
addOnUpsert: false,
autoRemove: false,
preferUpdate: false,
replaceItems: false,
skipRequestIfExists: false,
paramsForServer: ['$populateParams'],
whitelist: [],
enableEvents: true,
handleEvents: {
created: (item, { model, models }) => options.enableEvents,
patched: (item, { model, models }) => options.enableEvents,
updated: (item, { model, models }) => options.enableEvents,
removed: (item, { model, models }) => options.enableEvents
},
// optional and only configurable per service
servicePath: '',
namespace: null,
modelName: 'User',
instanceDefaults: () => ({}),
setupInstance: instance => instance,
state: {},
getters: {},
mutations: {},
actions: {},
//...
});
The following options can also be configured in Global Configuration for every service initialized using feathers-client.js:
idField {String}- Default:globalConfig: 'id'- The field in each record that will contain the idtempIdField {Boolean}- Default:globalConfig: '__id'- The field in each temporary record that contains the idnameStyle {'short'|'path'}- Default:globalConfig: 'short'- Use the full service path as the Vuex module name, instead of just the last section.debug {Boolean}- Default:globalConfig: false- Enable some logging for debuggingaddOnUpsert {Boolean}- Default:globalConfig: false- Iftrueadd new records pushed by 'updated/patched' socketio events into store, instead of discarding them.autoRemove {Boolean}- Default:globalConfig: false- Iftrueautomatically remove records missing from responses (only use with feathers-rest)preferUpdate {Boolean}- Default:globalConfig: false- Iftrue, callingmodel.save()will do anupdateinstead of apatch.replaceItems {Boolean}- Default:globalConfig: false- Iftrue, updates & patches replace the record in the store. Default is false, which merges in changes.skipRequestIfExists {Boolean}- Default:globalConfig: false- For get action, iftruethe record already exists in store, skip the remote request.paramsForServer {Array}- Default:['$populateParams']- Custom query operators that are ignored in the find getter, but will pass through to the server. It is preconfigured to work with the$populateParamscustom operator from feathers-graph-populate (opens new window).whitelist {Array}- Custom query operators that will be allowed in the find getter.enableEvents {Boolean}- Default:globalConfig: true- Iffalsesocket event listeners will be turned offhandleEvents {Object}: For this to workenableEventsmust betruecreated {Function}- Default:(item, { model, models }) => options.enableEvents- handlecreatedevents, return true to add to the storepatched {Function}- Default:(item, { model, models }) => options.enableEvents- handlecreatedevents, return true to update in the storeupdated {Function}- Default:(item, { model, models }) => options.enableEvents- handlecreatedevents, return true to update in the storeremoved {Function}- Default:(item, { model, models }) => options.enableEvents- handleremovedevents, return true to remove from the store
The following options can only configured individually per service plugin
servicePath {String}- Not all Feathers service plugins expose the service path, so it can be manually specified when missing.namespace {String}, - Default:nameStyle === 'short' ? ${afterLastSlashOfServicePath} : ${stripSlashesFromServicePath}- Customize the Vuex module name. Overrides nameStyle.modelName {String}- Default:${ServicePlugin.Model.modelName}instanceDefaults {Function}- Default:() => ({})- Override this method to provide default data for new instances. If using Model classes, specify this as a static class property.setupInstance {Function}- Default:instance => instance- Override this method to setup data types or related data on an instance. If using Model classes, specify this as a static class property.state {Object}- Default::null- Pass customstatesto the service plugin or modify existing onesgetters {Object}- Default:null- Pass customgettersto the service plugin or modify existing onesmutations {Object}- Default:null- Pass custommutationsto the service plugin or modify existing onesactions {Object}- Default:null- Pass customactionsto the service plugin or modify existing ones
# Realtime by Default
Service plugins automatically listen to all socket messages received by the Feathers Client. This can be disabled by setting enableEvents: false in the options, as shown above.
# The FeathersClient Service
Once the service plugin has been registered with Vuex, the FeathersClient Service will have a new service.FeathersVuexModel property. This provides access to the service's Model class.
import { models } from 'feathers-vuex'
feathersClient.service('todos').FeathersVuexModel === models.api.Todo // true
# Service State
Each service comes loaded with the following default state:
{
ids: [],
idField: 'id',
keyedById: {},
tempsById: {},
tempsByNewId: {},
pagination: {
defaultLimit: null,
defaultSkip: null
},
servicePath: 'v1/todos'
modelName: 'Todo',
autoRemove: false,
replaceItems: false,
pagination: {
ids: []
limit: 0
skip: 0
ip: 0
total: 0,
mostRecent: any
},
paramsForServer: ['$populateParams'],
whitelist: [],
isFindPending: false,
isGetPending: false,
isCreatePending: false,
isUpdatePending: false,
isPatchPending: false,
isRemovePending: false,
errorOnfind: undefined,
errorOnGet: undefined,
errorOnCreate: undefined,
errorOnUpdate: undefined,
errorOnPatch: undefined,
errorOnRemove: undefined,
isIdCreatePending: [],
isIdUpdatePending: [],
isIdPatchPending: [],
isIdRemovePending: [],
}
ids {Array}- an array of plain ids representing the ids that belong to each object in thekeyedByIdmap.idField {String}- the name of the field that holds each item's id. Default:'id'keyedById {Object}- a hash map keyed by the id of each item.tempsById {Object}- a hash map of temporary records, keyed by tempIdField of each itemtempsByNewId {Object}- temporary storage for temps while getting transferred from tempsById to keyedByIdservicePath {String}- the full service path, even if you alias the namespace to something else.modelName {String}- the key in the $FeathersVuex plugin where the model will be found.autoRemove {Boolean}- indicates that this service will not automatically remove results missing from subsequent requests. Only use with feathers-rest. Default is false.replaceItems {Boolean}- When set to true, updates and patches will replace the record in the store instead of merging changes. Default is falsepagination {Object}- provides informaiton about the last made queriesparamsForServer {Array}- Custom query operators that are ignored in the find getter, but will pass through to the server.whitelist {Array}- Custom query operators that will be allowed in the find getter.
The following state attributes allow you to bind to the pending state of requests:
isFindPending {Boolean}-trueif there's a pendingfindrequest.falseif not.isGetPending {Boolean}-trueif there's a pendinggetrequest.falseif not.isCreatePending {Boolean}-trueif there's a pendingcreaterequest.falseif not.isUpdatePending {Boolean}-trueif there's a pendingupdaterequest.falseif not.isPatchPending {Boolean}-trueif there's a pendingpatchrequest.falseif not.isRemovePending {Boolean}-trueif there's a pendingremoverequest.falseif not.
The following state attribute will be populated with any request error, serialized as a plain object:
errorOnFind {Error}errorOnGet {Error}errorOnCreate {Error}errorOnUpdate {Error}errorOnPatch {Error}errorOnRemo {Error}
The following state attributes allow you to bind to the pending state of requests per item ID
isIdCreatePending {Array}- Containsidif there's a pendingcreaterequest forid.isIdUpdatePending {Array}-Containsidif there's a pendingupdaterequest forid.isIdPatchPending {Array}- Containsidif there's a pendingpatchrequest forid.isIdRemovePending {Array}- Containsidif there's a pendingremoverequest forid.
# Service Getters
Service modules include the following getters:
list {Array}- an array of items. The array form ofkeyedByIdRead only.find(params) {Function}- a helper function that allows you to use the Feathers Adapter Common API (opens new window) and Query API (opens new window) to pull data from the store. This allows you to treat the store just like a local Feathers database adapter (but without hooks).params {Object}- an object with aqueryobject and optional properties. You can set the following properties:params.query {Boolean}- Thequeryis in the FeathersJS query format.params.temps {Boolean}- Default:false- iftruealso consider temporary records fromtempsByIdparams.copies {Boolean}- Default:false- iftrue: first search for the regular records and then replace the records with the related copies fromcopiesById
count(params) {Function}- a helper function that counts items in the store matching the provided query in the params and returns this number 3.12.0+params {Object}- an object with aqueryobject and an optionaltempsboolean property.
get(id[, params]) {Function}- a function that allows you to query the store for a single item, by id. It works the same way asgetrequests in Feathers database adapters.id {Number|String}- the id of the data to be retrieved by id from the store.params {Object}- an object containing a Feathersqueryobject.
The following getters ease access to per-instance pending status
isCreatePendingById(id) {Function}- Check ifcreateis pending foridisUpdatePendingById(id) {Function}- Check ifupdateis pending foridisPatchPendingById(id) {Function}- Check ifpatchis pending foridisRemovePendingById(id) {Function}- Check ifremoveis pending foridisSavePendingById(id) {Function}- Check ifcreate,update, orpatchis pending foridisPendingById(id) {Function}- Check ifcreate,update,patchorremoveis pending forid
# Service Mutations
The following mutations are included in each service module.
Note: you would typically not call these directly, but instead with
store.commit('removeItem', 'itemId'). Using vuex's mapMutations on a Vue component can simplify that tothis.removeItem('itemId')
# addItem(state, item)
Adds a single item to the keyedById map.
item {Object}- The item to be added to the store.
# addItems(state, items)
Adds an array of items to the keyedById map.
items {Array}- the items to be added to the store.
# updateItem(state, item)
Updates an item in the store to match the passed in item.
item {Object}the item, includingid, to replace the currently-stored item.
# updateItems(state, items)
Updates multiple items in the store to match the passed in array of items.
items {Array}- An array of items.
# removeItem(state, item)
Removes a single item. item can be
item {Number|String|Object}- The item or id of the item to be deleted.
# removeTemps(state, tempIds)
// Removes temp records. Also cleans up tempsByNewId
items {Array}- An array of ids or of objects with tempIds that will be removed from the data store
# removeItems(state, items)
Removes the passed in items or ids from the store.
items {Array}- An array of ids or of objects with ids that will be removed from the data store.
# clearAll(state)
Clears all data from ids, keyedById, and currentId
# Mutations for Managing Pending State
The following mutations are called automatically by the service actions, and will rarely, if ever, need to be used manually.
setPending(state, method)- sets theis${method}Pendingattribute to truesetIdPending(state, { method, id })- addsidtoisId${method}PendingarrayunsetPending(state, method)- sets theis${method}Pendingattribute to falseunsetIdPending(state, { method, id })- removesidfromisId${method}Pendingarray
# Mutations for Managing Errors
The following mutations are called automatically by the service actions, and will rarely need to be used manually.
setError(state, { method, error })- sets theerrorOn${method}attribute to the errorclearError(state, method)- sets theerrorOn${method}attribute tonull
# Service Actions
An action is included for each of the Feathers service interface methods. These actions will affect changes in both the Feathers API server and the Vuex store.
All of the Feathers Service Methods (opens new window) are supported. Because Vuex only supports providing a single argument to actions, there is a slight change in syntax that works well. If you need to pass multiple arguments to a service method, pass an array to the action with the order of the array elements matching the order of the arguments. See each method for examples.
Note: If you use the Feathers service methods, directly, the store will not change. Only the actions will cause store changes.
# find(params)
Query an array of records from the server & add to the Vuex store.
params {Object}- An object containing aqueryobject and an optionalpaginateboolean. You can setparams.paginatetofalseto disable pagination for a single request.
let params = {query: {completed: true}}
store.dispatch('todos/find', params)
See the section about pagination, below, for more information that is applicable to the find action. Make sure your returned records have a unique field that matches the idField option for the service plugin.
# afterFind(response)
The afterFind action is called by the find action after a successful response is added to the store. It is called with the current response. By default, it is a no-op (it literally does nothing), and is just a placeholder for you to use when necessary. See the sections on customizing the default store and Handling custom server responses for example usage.
# count(params) 3.12.0+
Count items on the server matching the provided query.
params {Object}- An object containing aqueryobject. In the background$limit: 0will be added to thequeryto perform a (fast) counting query against the database.
Note: it only works for services with enabled pagination!
let params = {query: {completed: false}}
store.dispatch('todos/count', params)
This will run a (fast) counting query against the database and return a page object with the total and an empty data array.
# get(id) or get([id, params])
Query a single record from the server & add to Vuex store
id {Number|String}- theidof the record being requested from the API server.params {Object}- An object containing aqueryobject.
store.dispatch('todos/get', 1)
// Use an array to pass params
let params = {}
store.dispatch('todos/get', [1, params])
Make sure your returned records have a unique field that matches the idField option for the service plugin.
# create(data|ParamArray)
Create one or multiple records. Note that the method is overloaded to accept two types of arguments. If you want a consistent interface for creating single or multiple records, use the array syntax, described below. Creating multiple records requires using the paramArray syntax.
data {Object|ParamArray}- if an object is provided, a single record will be created.
let newTodo = {description: 'write good tests'}
store.dispatch('todos/create', newTodo)
data {ParamArray}- if an array is provided, it is assumed to have this structure:ParamArray {Array}- array containing the two parameters that Feathers'service.createmethod accepts.data {Object|Array}- the data to create. Providing an object creates a single record. Providing an array of objects creates multiple records.params {Object}- optional - an object containing aqueryobject. Can be useful in rare situations.
Make sure your returned records have a unique field that matches the idField option for the service plugin.
# update(paramArray)
Update (overwrite) a record.
paramArray {Array}- array containing the three parameters update accepts.id {Number|String}- theidof the existing record being requested from the API server.data {Object}- the data that will overwrite the existing recordparams {Object}- An object containing aqueryobject.
let data = {id: 5, description: 'write your tests', completed: true}
let params = {}
// Overwrite item 1 with the above data (FYI: Most databases won't let you change the id.)
store.dispatch('todos/update', [1, data, params])
Alternatively in a Vue component
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions('todos', [ 'update' ]),
addTodo () {
let data = {id: 5, description: 'write your tests', completed: true}
this.update([1, data, {}])
}
}
}
Make sure your returned records have a unique field that matches the idField option for the service plugin.
# patch(paramArray)
Patch (merge in changes) one or more records
paramArray {Array}- array containing the three parameters patch takes.id {Number|String}- theidof the existing record being requested from the API server.data {Object}- the data that will be merged into the existing recordparams {Object}- An object containing aqueryobject. If params.data is provided, it will be used as the patch data, providing a simple way to patch with partial data.
let data = {description: 'write your tests', completed: true}
let params = {}
store.dispatch('todos/patch', [1, data, params])
Make sure your returned records have a unique field that matches the idField option for the service plugin.
# remove(id)
Remove/delete the record with the given id.
id {Number|String}- theidof the existing record being requested from the API server.
store.dispatch('todos/remove', 1)
Make sure your returned records have a unique field that matches the idField option for the service plugin.
# Service Events
By default, the service plugin listens to all of the FeathersJS events:
createdevents will add new record to the store.patchedevents will add (if new) or update (if present) the record in the store.updatedevents will add (if new) or update (if present) the record in the store.removedevents will remove the record from the store, if present.
This behavior can be turned off completely by passing enableEvents: false in either the global Feathers-Vuex options or in the service plugin options. If you configure this at the global level, the service plugin level will override it. For example, if you turn off events at the global level, you can enable them for a specific service by setting enableEvents: true on that service's options.
# Custom Event Handlers 3.1.0+
As of version 3.1, you can customize the behavior of the event handlers, or even perform side effects based on the event data. This is handled through the new handleEvents option on the service plugin. Here is an example of how you might use this:
handleEvents: {
created: (item, { model, models }) => {
// Perform a side effect to remove any record with the same `name`
const existing = Model.findInStore({ query: { name: item.name }}).data[0]
if (existing) {
existing.remove()
}
// Perform side effects with other models.
const { SomeModel } = models.api
new SomeModel({ /* some custom data */ }).save()
// Access the store through model.store
const modelState = model.store.state[model.namespace]
if (modelState.keyedById[5]) {
console.log('we accessed the vuex store')
}
// If true, the new item will be stored.
return true
},
updated: () => false, // Ignore `updated` events.
patched: item => item.hasPatchedAttribute && item.isWorthKeeping,
removed: item => true // The default value, will remove the record from the store
}
As shown above, each handler has two possible uses:
- Control the default behavior of the event by returning a boolean.
- For
created,patched, andupdateda truthy return will add or update the item in the store. - For
removeda truthy return will remove the item from the store, if present.
- Perform side effects using the current service
modelor with othermodels. Themodelsobject is the same as the$FeathersVuexobject in the Vue plugin.
Each handler receives the following arguments:
item: the record sent from the API serverutils: an object containing the following propertiesmodelThe current service's Model class.modelsThe same as the$FeathersVuexobject, gives you access to each api with their respective model classes.
You do not have to specify a handler for every event. Any that are not specified in your service-specific handleEvents, will fall back to using the handleEvents handler in your global options. If none are defined for the service or globally, the default behavior is controlled by the enableEvents option.
# Handling complex events 3.10.0+
If your application emits the standard Feathers service events inside a nested object with additional data, you can use handleEvents to tell FeathersVuex what part of that data is actually the model data that should be used to update the store.
To do this, use handleEvents as described before, but return a tuple [affectsStore, modelData] from your handler.
affectsStorea truthy value indicates the event should update the storemodelDatais the model data used to update the store
For example, you've configured your Feathers API to emit patched events for your Todos service that include context about the event which look like
{
"$context": {
"time": 1445411009000,
"userId": 121,
"deviceId": "Marty's iPhone"
},
"event": {
"id": 88,
"text": "Get back to the past",
"done": true
}
}
For this service to play nicely with FeathersVuex, you'll need to use handleEvents
handleEvents: {
patched: (item, { model, models }) => {
// Perform any side effects...
// If the first element is truthy, the item will update the store
// The second element is the actual model data to add to the store
return [true, item.event]
}
}
The original event data is bubbled to Model events so listeners receive the full event context.
# Pagination and the find action
Both the find action and the find getter support pagination. There are differences in how they work.
Important: For the built in pagination features to work, you must not directly manipulate the context.params object in any before hooks. You can still use before hooks as long as you clone the params object, then make changes to the clone.
# The find action
The find action queries data from the remote server. It returns a promise that resolves to the response from the server. The presence of pagination data will be determined by the server.
feathers-vuex@1.0.0 can store pagination data on a per-query basis. The pagination store attribute maps queries to their most-recent pagination data. The default pagination state looks like this:
{
pagination: {
defaultLimit: null,
defaultSkip: null
}
}
You should never manually change these values. They are managed internally.
There's not a lot going on, by default. The defaultLimit and defaultSkip properties are null until a query is made on the service without $limit or $skip. In other words, they remain null until an empty query comes through, like the this one:
params = { query: {} }
{
pagination : {
defaultLimit: 25,
defaultSkip: 0,
default: {
mostRecent: {
query: {},
queryId: '{}',
queryParams: {},
pageId: '{$limit:25,$skip:0}',
pageParams: { $limit: 25, $skip: 0 },
queriedAt: 1538594642481
},
'{}': {
total: 155,
queryParams: {},
'{$limit:25,$skip:0}': {
pageParams: { $limit: 25, $skip: 0 },
ids: [ 1, 2, 3, 4, '...etc', 25 ],
queriedAt: 1538594642481
}
}
}
}
}
It looks like a lot just happened, so let's walk through it. First, notice that we have values for defaultLimit and defaultSkip. These come in handy for the find getter, which will be covered later.
# The qid
The state now also contains a property called default. This is the default qid, which is a "query identifier" that you choose. Unless you're building a small demo, your app will require to storing pagination information for more than one query. For example, two components could make two distinct queries against this service. You can use the params.qid (query identifier) property to assignn identifier to the query. If you set a qid of mainListView, for example, the pagination for this query will show up under pagination.mainListView. The pagination.default property will be used any time a params.qid is not provided. Here's an example of what this might look like:
params = { query: {}, qid: 'mainListView' }
// Data in the store
{
pagination : {
defaultLimit: 25,
defaultSkip: 0,
mainListView: {
mostRecent: {
query: {},
queryId: '{}',
queryParams: {},
pageId: '{$limit:25,$skip:0}',
pageParams: { $limit: 25, $skip: 0 },
queriedAt: 1538594642481
},
'{}': {
total: 155,
queryParams: {},
'{$limit:25,$skip:0}': {
pageParams: { $limit: 25, $skip: 0 },
ids: [ 1, 2, 3, 4, '...etc', 25 ],
queriedAt: 1538594642481
}
}
}
}
}
The above example is almost exactly the same as the previous one. The only difference is that the default key is now called mainListView. This is because we provided that value as the qid in the params. Let's move on to the properties under the qid.
# The mostRecent object
The mostRecent propery contains information about the most recent query. These properties provide insight into how pagination works. The two most important properties are the queryId and the pageId.
- The
queryIddescribes the set of data we're querying. It's a stable, stringified version of all of the query params except for$limitand$skip. - The
pageIdholds information about the current "page" (as in "page-ination"). A page is described using$limitand$skip.
The queryParams and pageParams are the non-stringified queryId and pageId. The query attribute is the original query that was provided in the request params. Finally, the queriedAt is a timestamp of when the query was performed.
# The queryId and pageId tree
The rest of the qid object is keyed by queryId strings. Currently, we only have a single queryId of '{}'. In the queryId object we have the total numer of records (as reported by the server) and the pageId of '{$limit:25,$skip:0}'
'{}': { // queryId
total: 155,
queryParams: {},
'{$limit:25,$skip:0}': { // pageId
pageParams: { $limit: 25, $skip: 0 },
ids: [ 1, 2, 3, 4, '...etc', 25 ],
queriedAt: 1538594642481
}
}
The pageId object contains the queriedAt timestamp of when we last queried this page of data. It also contains an array of ids, holding only the ids of the records returned from the server.
# Additional Queries and Pages
As more queries are made, the pagination data will grow to represent what we have in the store. In the following example, we've made an additional query for sorted data in the mainListView qid. We haven't filtered the list down any, so the total is the same as before. We have sorted the data by the isComplete attribute, which changes the queryId. You can see the second queryId object added to the mainListView qid:
params = { query: {}, qid: 'mainListView' }
params = { query: { $limit: 10, $sort: { isCompleted: 1 } }, qid: 'mainListView' }
// Data in the store
{
pagination : {
defaultLimit: 25,
defaultSkip: 0,
mainListView: {
mostRecent: {
query: { $sort: { isCompleted: 1 } },
queryId: '{$sort:{isCompleted:1}}',
queryParams: { $sort: { isCompleted: 1 } },
pageId: '{$limit:10,$skip:0}',
pageParams: { $limit: 10, $skip: 0 },
queriedAt: 1538595856481
},
'{}': {
total: 155,
queryParams: {},
'{$limit:25,$skip:0}': {
pageParams: { $limit: 25, $skip: 0 },
ids: [ 1, 2, 3, 4, '...etc', 25 ],
queriedAt: 1538594642481
}
},
'{$sort:{isCompleted:1}}': {
total: 155,
queryParams: {},
'{$limit:10,$skip:0}': {
pageParams: { $limit: 10, $skip: 0 },
ids: [ 4, 21, 19, 29, 1, 95, 62, 21, 67, 125 ],
queriedAt: 1538594642481
}
}
}
}
}
In summary, any time a query param other than $limit and $skip changes, we get a new queryId. Whenever $limit and $skip change, we get a new pageId inside the current queryId.
# Why use this pagination structure
Now that we've reviewed how pagination tracking works under the hood, you might be asking "Why?" There are a few reasons:
- Improve performance with cacheing. It's now possible to skip making a query if we already have valid data for the current query. The
makeFindMixinmixin makes this very easy with its built-inqueryWhenfeature. - Allow fall-through cacheing of paginated data. A common challenge occurs when you provide the same query params to the
findaction and thefindgetter. As you'll learn in the next section, thefindgetter allows you to make queries against the Vuex store as though it were a Feathers database adapter. But what happens when you pass{ $limit: 10, $skip: 10 }to the action and getter?
First, lets review what happens with thefindaction. The database is aware of all 155 records, so it skips the first 10 and returns the next 10 records. Those records get populated in the store, so the store now has 10 records. Now we pass the query to thefindgetter and tell it to$skip: 10. It skips the only 10 records that are in the store and returns an empty array! That's definitely not what we wanted.
Since we're now storing this pagination structure, we can build a utility around thefindgetter which will allow us to return the same data with the same query. The data is still reactive and will automatically update when a record changes.
There's one limitation to this solution. What happens when you add a new record that matches the current query? Depending on where the new record would be sorted into the current query, part or all of the cache is no longer valid. It will stay this way until a new query is made. To get live (reactive) lists, you have to use the find getter with its own distinct query, removing the $limit and $skip values. This way, when a new record is created, it will automatically get added to the array in the proper place.
# Pagination and the find getter
The find getter queries data from the local store using the same Feathers query syntax as on the server. It is synchronous and returns the results of the query with pagination. Pagination cannot be disabled. It accepts a params object with a query attribute. It does not use any other special attributes. The returned object looks just like a paginated result that you would receive from the server:
params = { query: {} }
// The returned results object
{
data: [{ _id: 1, ...etc }, ...etc],
limit: 0,
skip: 0,
total: 3
}
# Customizing a Service's Default Store
# New extend option for makeServicePlugin 3.14.0+
As of version 3.14.0, the makeServicePlugin now supports an extend method that allows customizing the store and gives access to the actual Vuex store object, as shown in this example:
import { makeServicePlugin } from ‘feathers-vuex’
import { feathersClient } from ‘./feathers-client.js’
class Todo { /* truncated */ }
export default makeServicePlugin({
Model: Todo,
service: feathersClient.service(‘todos’),
extend({ store, module }) {
// Listen to other parts of the store
store.watch(/* truncated */)
return {
state: {},
getters: {},
mutations: {},
actions: {}
}
}
})
# Deprecated options for customizing the store
Before version 3.14.0, you can customize the store using the options for state, getters, mutations, and actions, as shown below. This method is now deprecated and will be removed from Feathers-Vuex 4.0.
// src/store/services/users.js
import feathersClient, { makeServicePlugin, BaseModel } from '../../feathers-client'
class Asset extends BaseModel {
constructor(data, options) {
super(data, options)
}
// Required for $FeathersVuex plugin to work after production transpile.
static modelName = 'Asset'
// Define default properties here
static instanceDefaults() {
return {
email: '',
password: ''
}
}
}
const servicePath = 'assets'
const servicePlugin = makeServicePlugin({
Model: Asset,
service: feathersClient.service(servicePath),
servicePath,
state: {
test: true
},
getters: {
getSomeData () {
return 'some data'
}
},
mutations: {
setTest (state, val) {
state.test = val;
},
},
actions: {
// Overwriting the built-in `afterFind` action.
afterFind ({ commit, dispatch, getters, state }, response) {
// Do something with the response.
// Keep in mind that the data is already in the store.
},
asyncStuff ({ state, getters, commit, dispatch }, args) {
commit('setTestToTrue')
return new Promise.resolve("")
}
}
})
export default servicePlugin