# Feathers Integration

This implements VueX using a feathers based server. It is ready configured to work with the API Server using websockets.

## Authentication

This is also ready configured.

## Setup Services

Therefore the ServicePlugin is used.

=== "store/services/users.js"

    ```js
    import feathersClient, { makeServicePlugin, BaseModel } from '../../feathers'

    class User extends BaseModel {
        // Required for $FeathersVuex plugin to work after production transpile.
        static modelName = 'User';
        // Define default properties here
        static instanceDefaults () {
          return {
            email: '',
            password: ''
          }
        }
    }

    const servicePath = 'users'
    const servicePlugin = makeServicePlugin({
      Model: User,
      service: feathersClient.service(servicePath),
      servicePath
    })

    // Setup the client-side Feathers hooks.
    feathersClient.service(servicePath).hooks({
      before: {
        all: [],
        find: [],
        get: [],
        create: [],
        update: [],
        patch: [],
        remove: []
      },
      after: {
        all: [],
        find: [],
        get: [],
        create: [],
        update: [],
        patch: [],
        remove: []
      },
      error: {
        all: [],
        find: [],
        get: [],
        create: [],
        update: [],
        patch: [],
        remove: []
      }
    })

    export default servicePlugin
    ```

This will be loaded automatically through webpack. Read more about defining the [service plugin](https://vuex.feathersjs.com/service-plugin.html#configuration).

You may access it through `this.$FeathersVuex.api.User({})`

## Store

### Getter

-   `list` Array - an array of items. The array form of keyedById Read only.
-   `find(params)` Function - a helper function that allows you to use the Feathers Adapter Common API and Query API 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 a query object and an optional paginate boolean property. The query is in the FeathersJS query format. You can set `params.paginate` to `false` to disable pagination for a single request.
-   `get(id[, params])` Function - a function that allows you to query the store for a single item, by id. It works the same way as get requests 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 Feathers query object.

### Mutations

!!! 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 to `this.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, including id, 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
    - `tempIds` 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

### 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.

!!! Note

    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.

#### find(params)

Query an array of records from the server and add to the Vuex store.

- `params` Object - an object containing a query object and an optional `paginate` boolean. You can set `params.paginate` to `false` to disable pagination for a single request.

```js
const params = {query: {completed: true}}
store.dispatch('todos/find', params)
```

Pagination can be used through the query object:

```js
const params = { query: { $limit: 25, $skip: 0 } }
store.dispatch('todos/find', params)
```

#### get(id) or get([id, params])

Query a single record from the server & add to Vuex store

- `id` Number|String - the id of the record being requested from the API server.
- `params` Object - an object containing a query object.

```js
store.dispatch('todos/get', 1)
// Use an array to pass params
let params = {}
store.dispatch('todos/get', [1, params])
```

#### 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 - if an object is provided, a single record will be created.
-   `ParamArray` Array - if an array is provided, it is assumed to have this structure. Array containing the two parameters that Feathers' `service.create` method 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 a query object. Can be useful in rare situations.

```js
const newTodo = {description: 'write good tests'}
store.dispatch('todos/create', newTodo)
```

#### update(paramArray)

Update (overwrite) a record.

-   `paramArray` Array - array containing the three parameters update accepts.
    -   `id` Number|String - the id of the existing record being requested from the API server.
    -   `data` Object - the data that will overwrite the existing record
    -   `params` Object - an object containing a query object.

```js
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

```js
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, {}])
    }
  }
}
```

#### patch(paramArray)

Patch (merge in changes) one or more records

-   `paramArray` Array - array containing the three parameters patch takes.
    - `id` Number|String - the id of the existing record being requested from the API server.
    - `data` Object - the data that will be merged into the existing record
    - `params` Object - an object containing a query object. If params.data is provided, it will be used as the patch data, providing a simple way to patch with partial data.

```js
let data = {description: 'write your tests', completed: true}
let params = {}
store.dispatch('todos/patch', [1, data, params])
```

#### remove(id)

Remove/delete the record with the given id.

- `id` Number|String - the id of the existing record being requested from the API server.

```js
store.dispatch('todos/remove', 1)
```

### Events

- `created` events will add new record to the store.
- `patched` events will add (if new) or update (if present) the record in the store.
- `updated` events will add (if new) or update (if present) the record in the store.
- `removed` events will remove the record from the store, if present.

## Model

Feathers also supports a model which can be used for easy access and while do the interaction with the store. It was already shown in the code above.

To get the model it should look like:

=== "Within Vue component"

    ```js
    created () {
      const { User } = this.$FeathersVuex.api
      // do something with it
    }
    ```

=== "Directly from Vue"

    ```js
    import Vue from 'vue'

    const { Todo } = Vue.$FeathersVuex.api
    // do something with it
    ```

### Static Methods

- `find(params)` - a proxy to the find action.
- `findInStore(params)` - a proxy to the find getter.
- `get(id, params)` - a proxy to the get action. Notice that the signature is more Feathers-like, and doesn't require using an array to passing both id and params.
- `getFromStore(id, params)` - a proxy to the get getter.

### Model Events

Setting eventhandlers will be done using:

- `on` - register event handlers to listen to events.
- `once` - register an event handler that only occurs once.
- `off` - remove an event handler.

All FeathersJS events are supported like:

- `.on('created')`
- `.on('updated')`
- `.on('patched')`
- `.on('removed')`

Here’s an example of how to use it in a component:

```js
export default {
    created() {
        this.$FeathersVuex.api.Todo.on(‘created’, this.handleTodoCreated)
   },
   destroyed() {
       this.$FeathersVuex.api.Todo.off(‘created’, this.handleTodoCreated)
   },
   methods: {
       handleTodoCreated(todo) {
           console.log(todo)
      }
   }
}
```

### Instantiation

Calling `new User({ firstName: 'Marshall' })` will create the instance with the firstName filled in, already. It will also include defaults which are set in the model.

### Instance Methods

- `.save()` - a convenience wrapper for the create/patch methods. If the records has no `_id`, the `.create()` method will be used, else `.patch()`.
- `.create()` - calls the create action (service method) using the instance data.
- `.patch(params)` - calls the patch action (service method) using the instance data. You can set `params.data` as the patch data.
- `.update()` - calls the update action (service method) using the instance data.
- `.remove()` - calls the remove action (service method) using the instance data.

### Working with clone

This allows you to make changes to the clone and not update visible data until you commit or save the data.

There's another use case for using `.clone()`. Vuex has a strict mode that's really useful in development. It throws errors if any changes occur in the Vuex store state outside of mutations. Clone really comes in handy here, because you can make changes to the clone without having to write custom Vuex mutations. When you're finished making changes, call .commit() to update the store. This gives you strict mode compliance with little effort!

- `.clone()` - creates a deep copy of the record and stores it on `Model.copiesById`.
- `.commit()` - update the data from the clone in the store.
- `.reset()` - reset the clone record to match the one in the store.

```js
const { User } = this.$FeathersVuex.api
const user = new User({ id: 1, description: 'Do something!' })
const userCopy = user.clone()

userCopy.description = 'Do something else!'
userCopy.commit() // --> Update the data in the store.

console.log(user.description) // --> 'Do something else!'
console.log(userCopy.description) // --> 'Do something else!'
```

## Components

There are two new renderless data provider components: `<FeathersVuexFind>` and `<FeathersVuexGet>`. They simplify performing queries against the store and/or the API server. They make the data available inside each component's default slot.

The `<FeathersVuexFormWrapper>` and `<FeathersVuexInputWrapper>` are renderless components which assist in connecting your feathers-vuex data to a form.

### FeathersVuexFind

The FeathersVuexFind component retrieves data from the API server, puts it in the Vuex store, then transparently retrieves the live, reactive data from the store and displays it to the user.

```vue
<template>
  <FeathersVuexFind service="users" :query="{}" watch="query">
    <section slot-scope="{ items: users }">
      {{users}}
    </section>
  </FeathersVuexFind>
</template>
```

By default, the following props are available in the scope data:

- `items` Array - the resulting array of records for find operations.
- `isFindPending` Boolean - when there's an active request to the API server, this will be true.
- `pagination` Object - pagination data from the Vuex store, keyed by the qid attribute. By default, this will be specific to this component instance.

### FeathersVuexGet

The FeathersVuexGet component allows fetching data from directly inside a template. It makes the slot scope available to the child components.

```vue
<template>
  <FeathersVuexGet service="users" :id="id" :watch="id">
    <template slot-scope="{ item: user }">
      {{ user }}
    </template>
  </FeathersVuexGet>
</template>
```

- `item` Object - the resulting object for get operations
- `isGetPending` Boolean - the same as the isFindPending, but for get requests.

### FeathersVuexFormWrapper

The FeathersVuexFormWrapper component uses the "clone and commit" pattern to connect a single record to a child form within its default slot.

```vue
<template>
  <FeathersVuexFormWrapper :item="currentItem" watch>
    <template v-slot="{ clone, save, reset, remove }">
      <SomeEditor
        :item="clone"
        @save="save().then(handleSaveResponse)"
        @reset="reset"
        @remove="remove"
      ></SomeEditor>
    </template>
  </FeathersVuexFormWrapper>
</template>

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

export default {
  name: 'MyComponent',
  components: { FeathersVuexFormWrapper },
  props: {
    currentItem: {
      type: Object,
      required: true
    }
  },
  methods: {
    handleSaveReponse(savedItem) {
      console.log(savedItem) // The item returned from the API call
    }
  }
}
</script>
```

Props:

- `item` Object - a model instance from the Vuex store.
- `watch` Boolean|Array - when enabled, if the original record is updated, the data will be re-cloned.
- `eager` Boolean - while this is enabled, using the save method will first commit the result to the store then it will send a network request. The UI display will update immediately, without waiting for any response from the API server. Default: true.

Slot:

- `clone` Object - the cloned record. Each record in the store can have a single clone. The clones are stored on the service's model class, by default.
- `save` Function - when called, it commits the data and saves the record (with eager updating, by default. See the eager prop.)
- `reset` Function - when called, the clone data will be reset back to the data that is currently found in the store for the same record.
- `remove` Function - when called, it removes the record from the API server and the Vuex store.

### FeathersVuexInputWrapper

Building on the same ideas as the FeathersVuexFormWrapper, the FeathersVuexInputWrapper reduces boilerplate for working with the clone and commit pattern on a single input. One use case for this component is implementing an "edit-in-place" workflow. The following example shows how to use the FeathersVuexInputWrapper to automatically save a record upon blur on a text input:

```vue
<template>
  <div class="p-3">
    <FeathersVuexInputWrapper :item="user" prop="email">
      <template #default="{ current, prop, createClone, handler }">
        <input
          v-model="current[prop]"
          type="text"
          @focus="createClone"
          @blur="e => handler(e, save)"
        />
      </template>
    </FeathersVuexInputWrapper>

    <!-- Simple readout to show that it's working. -->
    <pre class="bg-black text-white text-xs mt-2 p-1">{{user}}</pre>
  </div>
</template>

<script>
export default {
  name: 'InputWrapperExample',
  methods: {
    // Optionally make the event handler async.
    async save({ event, clone, prop, data }) {
      const user = clone.commit()
      return user.patch(data)
    }
  }
}
</script>
```

Props:

- `item` - the original (non-cloned) model instance.
- `prop` - the property name on the model instance to be edited.

Slot Scope:

Only the default slot is used. The following props are available in the slot scope:

- `current` clone|instance -  returns the clone if it exists, or the original record. `current = clone || item`
- `clone` clone - the internal clone. This is exposed for debugging purposes.
- `prop` String - the value of the prop prop. If you have the prop stored in a variable in the outer scope, this is redundant and not needed. You could just use this from the outer scope. It mostly comes in handy when you are manually specifying the prop name on the component.
- `createClone` Function - sets up the internal clone. Meant to be used as an event handler.
- `handler` Function - has the signature handler(event, callback). It prepared data before calling the callback function that must be provided from the outer scope.

{!docs/assets/abbreviations.md!}
