Skip to content

Commit 00829e3

Browse files
committed
docs: updated data modeling page
1 parent ddc6f77 commit 00829e3

File tree

1 file changed

+95
-113
lines changed

1 file changed

+95
-113
lines changed

docs/model-classes.md

Lines changed: 95 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,55 @@
11
---
22
title: Data Modeling
3+
sidebarDepth: 3
34
---
45

5-
<!-- markdownlint-disable MD002 MD033 MD041 -->
6-
Every service now includes a new `FeathersVuexModel` Class and new records are instantiated with that class before getting added to the store.
6+
# Data Modeling with Model Classes
7+
8+
Feathers-Vuex 1.0 introduced some lightweight data modeling. Every service had its own, internal `FeathersVuexModel`. In version 2.0 this `FeathersVuexModel` is now called the `BaseModel` and is extendable, so you can add your own functionality.
9+
10+
11+
## Extending the BaseModel Class
12+
13+
While [setting up Feathers-Vuex](/api-overview.html#feathers-client-feathers-vuex), we exported the `BaseModel` class so that we could extend it. The below example shows how to import and extend the `BaseModel`. Each service must now have its own unique Model class.
14+
15+
```js
16+
import feathersClient, { makeServicePlugin, BaseModel } from '../feathers-client'
17+
18+
class User extends BaseModel {
19+
// Required for $FeathersVuex plugin to work after production transpile.
20+
static modelName = 'User'
21+
// Define default properties here
22+
static instanceDefaults() {
23+
return {
24+
email: '',
25+
password: ''
26+
}
27+
}
28+
}
29+
30+
const servicePath = 'users'
31+
const servicePlugin = makeServicePlugin({
32+
Model: User,
33+
service: feathersClient.service(servicePath),
34+
servicePath
35+
})
36+
```
37+
38+
In case you're wondering, the `modelName` property is used to get around transpilation errors when using Babel with ES3 or ES5. Babel is still installed by default in most projects and generators. The `modelName` is used instead of the `name` property to provide a reliable name AFTER transpilation.
39+
40+
If you're working in an environment that doesn't support static properties on classes, you can always specify the static properties using the dot operator:
41+
42+
```js
43+
class User extends BaseModel {}
44+
45+
User.modelName = 'User'
46+
User.instanceDefaults = function() {
47+
return {
48+
email: '',
49+
password: ''
50+
}
51+
}
52+
```
753

854
## Model attributes
955

@@ -15,62 +61,85 @@ The following attributes are available on each model:
1561

1662
## Model Methods
1763

18-
### Model.find(params)
64+
### find(params)
1965

2066
Model classes have a `find` method, which is a proxy to the [`find` action](./service-plugin.html#find-params). <Badge text="1.7.0+" />
2167

2268
```js
2369
// In your Vue component
2470
created () {
25-
const { Todo } = this.$FeathersVuex
71+
const { Todo } = this.$FeathersVuex.api
2672
Todo.find({ query: {} }).then(/* ... */)
2773
}
2874
```
2975

30-
### Model.findInStore(params)
76+
### findInStore(params)
3177

3278
Model classes have a `findInStore` method, which is a proxy to the [`find` getter](./service-plugin.html#Service-Getters). <Badge text="1.7.0+" />
3379

3480
```js
3581
// In your Vue component
3682
created () {
37-
const { Todo } = this.$FeathersVuex
83+
const { Todo } = this.$FeathersVuex.api
3884
const todos = Todo.findInStore({ query: {} })
3985
}
4086
```
4187

42-
### Model.get(id, params)
88+
### get(id, params)
4389

44-
Model classes have a `get` method, which is a proxy to the [`get` action](./service-plugin.html#get-id-or-get-id-params). <Badge text="1.7.0+" />Notice that the signature is more Feathers-like, and doesn't require using an array to passing both id and params.
90+
Model classes have a `get` method, which is a proxy to the [`get` action](./service-plugin.html#get-id-or-get-id-params). <Badge text="1.7.0+" /> Notice that the signature is more Feathers-like, and doesn't require using an array to passing both id and params.
4591

4692
```js
4793
// In your Vue component
4894
created () {
49-
const { Todo } = this.$FeathersVuex
95+
const { Todo } = this.$FeathersVuex.api
5096
Todo.get(this.id).then(/* ... */)
5197
}
5298
```
5399

54-
### Model.getFromStore(id, params)
100+
### getFromStore(id, params)
55101

56102
Model classes have a `getFromStore` method, which is a proxy to the [`get` getter](./service-plugin.html#Service-Getters). <Badge text="1.7.0+" /> Notice that the signature is more Feathers-like, and doesn't require using an array to passing both id and params.
57103

58104
```js
59105
// In your Vue component
60106
created () {
61-
const { Todo } = this.$FeathersVuex
107+
const { Todo } = this.$FeathersVuex.api
62108
const todo = Todo.getFromStore(this.id)
63109
}
64110
```
65111

112+
### instanceDefaults <Badge text="1.7.0+" />
113+
114+
`instanceDefaults(data, { store, Models })`
115+
116+
Starting with version 2.0, `instanceDefaults` must be provided as a function. The function will be called with the following arguments and should return an object of default properties for new instances.
117+
118+
- `data {Object}` - The instance data
119+
- An `utils` object containing these props:
120+
- `store` - The vuex store
121+
- `Models {Object}` The `globalModels` object, which is the same as you'll find inside a component at `this.$FeathersVuex`.
122+
123+
### setupInstance <Badge text="2.0.0+" />
124+
125+
`setupInstance(data, { store, Models })`
126+
127+
A new `setupinstance` class method is now available in version 2.0. The function will be called with the following arguments and should return an object of default properties for new instances.
128+
129+
- `data {Object}` - The instance data
130+
- An `utils` object containing these props:
131+
- `store` - The vuex store
132+
- `Models {Object}` The `globalModels` object, which is the same as you'll find inside a component at `this.$FeathersVuex`.
133+
134+
66135
## Creating instances
67136

68137
The [FeathersVuex plugin for Vue](./vue-plugin.md) allow convenient access to all Model constructors. You can create a Model instance by getting a reference to a Model class from the `$FeathersVuex` object:
69138

70139
```js
71140
// In your Vue component
72141
created () {
73-
const { Todo } = this.$FeathersVuex
142+
const { Todo } = this.$FeathersVuex.api
74143
const todo = new Todo({ description: 'Do something!' })
75144
}
76145
```
@@ -80,7 +149,7 @@ You can also reference this directly from the Vue module:
80149
```js
81150
import Vue from 'vue'
82151

83-
const { Todo } = Vue
152+
const { Todo } = Vue.$FeathersVuex.api
84153
const todo = new Todo({ description: 'Do something!' })
85154
```
86155

@@ -111,93 +180,6 @@ store.dispatch('todos/find', { query: {} })
111180
})
112181
```
113182

114-
## instanceDefaults | Object
115-
116-
Do you find yourself spending time writing defaults into your form components? Maybe you wrote a utility for yourself or found one on npm that can do the trick for you. That's a thing of the past. You can now specify the default values for Model instances by using the `instanceDefaults` option when using the service plugin. Here's what it looks like:
117-
118-
```js
119-
import Vue from 'vue'
120-
import Vuex from 'vuex'
121-
import feathersVuex from 'feathers-vuex'
122-
import feathersClient from './feathers-client'
123-
124-
const { service, auth, FeathersVuex } = feathersVuex(feathersClient, { idField: '_id' })
125-
126-
Vue.use(FeathersVuex)
127-
Vue.use(Vuex)
128-
129-
export default new Vuex.Store({
130-
plugins: [
131-
service('todos', {
132-
instanceDefaults: {
133-
description: '',
134-
isComplete: false
135-
}
136-
})
137-
]
138-
})
139-
```
140-
141-
With the above configuration, when you create a [`Todo` instance](./model-classes.md), it will have the attributes provided as `instanceDefaults`. This is especially useful for binding to form data. If the attributes aren't defined while binding, the automatic Vue reactivity won't work. Remember to not set any of the attributes to `undefined`, but instead use `null`. If not, the reactivity breaks, and you might spend some time wondering why your form is broken.
142-
143-
### A Word Of Warning
144-
145-
One thing to be aware of when using `instanceDefaults` as an object is that values can persist between instances and mutate separate instances. For example, when including an `Array`, changes made to one instance will affect any other instances of this model too.
146-
147-
Using `instanceDefaults` as an object will be deprecated in the next major version of `feathers-vuex` so it's best to stick to the function option below.
148-
149-
## instanceDefaults | Function <Badge text="1.7.0+" /> <Badge text="recommended" type="warn"/>
150-
151-
A much more powerful API is available when you provide `instanceDefaults` as a function. The function will be called with the following arguments and should return an instanceDefaults object.
152-
153-
- `data {Object}` - The instance data
154-
- An `utils` object containing these props:
155-
- `store` - The vuex store
156-
- `Model {FeathersVuexModel}` - The current Model (the same as the current instance's constructor)
157-
- `Models {Object}` The `globalModels` object, which is the same as you'll find inside a component at `this.$FeathersVuex`.
158-
159-
This API allows for a lot of flexibility. In the below example, each todo instance has a `get user` property. If the instance has a `userId`, the correct user record will automatically be fetched from the store.
160-
161-
```js
162-
import Vue from 'vue'
163-
import Vuex from 'vuex'
164-
import feathersVuex from 'feathers-vuex'
165-
import feathersClient from './feathers-client'
166-
167-
const { service, auth, FeathersVuex } = feathersVuex(feathersClient, { idField: '_id' })
168-
169-
Vue.use(FeathersVuex)
170-
Vue.use(Vuex)
171-
172-
export default new Vuex.Store({
173-
plugins: [
174-
service('todos', {
175-
instanceDefaults (data, { store, Model, Models }) {
176-
return {
177-
description: '',
178-
isComplete: false,
179-
userId: null,
180-
get user () {
181-
if (this.userId) {
182-
const user = Models.User.getFromStore(this.userId)
183-
184-
// Fetch the User record if we don't already have it
185-
if (!user) {
186-
Models.User.get(this.userId)
187-
}
188-
189-
return user
190-
} else {
191-
return null
192-
}
193-
}
194-
}
195-
}
196-
})
197-
]
198-
})
199-
```
200-
201183
## Instance Methods
202184

203185
### `instance.save(params)`
@@ -207,7 +189,7 @@ The `save` method is a convenience wrapper for the `create/patch` methods, by de
207189
```js
208190
// In your Vue component
209191
created () {
210-
const { Todo } = this.$FeathersVuex
192+
const { Todo } = this.$FeathersVuex.api
211193
const todo = new Todo({ description: 'Do something!' })
212194

213195
todo.save() // --> Creates the todo on the server.
@@ -220,12 +202,12 @@ As mentioned, `save` performs either `create` or `patch`, but you can use the `p
220202

221203
### `instance.create(params)`
222204

223-
The `create` method is a shortcut for calling the `create` action (service method) using the instance data. The `params` argument will be used in the Feathers client request. See the [Feathers Service](https://docs.feathersjs.com/api/services.md#service-methods) docs, for reference.
205+
The `create` method calls the `create` action (service method) using the instance data. The `params` argument will be used in the Feathers client request. See the [Feathers Service](https://docs.feathersjs.com/api/services.md#service-methods) docs, for reference.
224206

225207
You might not ever need to use `.create()`, but can instead use the `.save()` method. Let `feathers-vuex` call `create` or `patch`.
226208

227209
```js
228-
const { Todo } = this.$FeathersVuex
210+
const { Todo } = this.$FeathersVuex.api
229211
const data = { description: 'Do something!' }
230212
const todo = new Todo(data)
231213

@@ -234,12 +216,12 @@ todo.create() // --> Creates the todo on the server using the instance data
234216

235217
### `instance.patch(params)`
236218

237-
The `patch` method is a shortcut for calling the `patch` action (service method) using the instance data. The instance's id field is used for the `patch` id. The `params` argument will be used in the Feathers client request. See the [Feathers Service](https://docs.feathersjs.com/api/services.md#service-methods) docs, for reference.
219+
The `patch` method calls the `patch` action (service method) using the instance data. The instance's id field is used for the `patch` id. The `params` argument will be used in the Feathers client request. See the [Feathers Service](https://docs.feathersjs.com/api/services.md#service-methods) docs, for reference.
238220

239221
Similar to the `.create()` method, you might not ever need to use `.patch()` if you just use `.save()` and let `feathers-vuex` figure out how to handle it.
240222

241223
```js
242-
const { Todo } = this.$FeathersVuex
224+
const { Todo } = this.$FeathersVuex.api
243225
const todo = new Todo({ id: 1, description: 'Do something!' })
244226

245227
todo.description = 'Do something else'
@@ -251,12 +233,12 @@ todo.patch() // --> Sends a `patch` request the with the id and description.
251233

252234
### `instance.update(params)`
253235

254-
The `update` method is a shortcut for calling the `update` action (service method) using the instance data. The instance's id field is used for the `update` id. The `params` argument will be used in the Feathers client request. See the [Feathers Service](https://docs.feathersjs.com/api/services.md#service-methods) docs, for reference.
236+
The `update` method calls the `update` action (service method) using the instance data. The instance's id field is used for the `update` id. The `params` argument will be used in the Feathers client request. See the [Feathers Service](https://docs.feathersjs.com/api/services.md#service-methods) docs, for reference.
255237

256238
Use `.update()` whenever you want to completely replace the data on the server with the instance data. You can also set the `preferUpdate` option to `true` to make `.save()` call `.update()` when an id field is present on the instance.
257239

258240
```js
259-
const { Todo } = this.$FeathersVuex
241+
const { Todo } = this.$FeathersVuex.api
260242
const todo = new Todo({ id: 1, description: 'Do something!' })
261243

262244
todo.description = 'Do something else'
@@ -266,10 +248,10 @@ todo.update() // --> Sends a `update` request the with all instance data.
266248

267249
### `instance.remove(params)`
268250

269-
The `remove` method is a shortcut for calling the `remove` action (service method) using the instance data. The instance's id field is used for the `remove` id. The `params` argument will be used in the Feathers client request. See the [Feathers Service](https://docs.feathersjs.com/api/services.md#service-methods) docs, for reference.
251+
The `remove` method calls the `remove` action (service method) using the instance data. The instance's id field is used for the `remove` id. The `params` argument will be used in the Feathers client request. See the [Feathers Service](https://docs.feathersjs.com/api/services.md#service-methods) docs, for reference.
270252

271253
```js
272-
const { Todo } = this.$FeathersVuex
254+
const { Todo } = this.$FeathersVuex.api
273255
const todo = new Todo({ id: 1, description: 'Do something!' })
274256

275257
todo.save()
@@ -283,7 +265,7 @@ todo.save()
283265
The `.clone()` method creates a deep copy of the record and stores it on `Model.copiesById`. This allows you to make changes to the clone and not update visible data until you commit or save the data.
284266

285267
```js
286-
const { Todo } = this.$FeathersVuex
268+
const { Todo } = this.$FeathersVuex.api
287269
const todo = new Todo({ id: 1, description: 'Do something!' })
288270
const todoCopy = todo.clone()
289271

@@ -296,12 +278,12 @@ console.log(todoCopy.description) // --> 'Do something else!'
296278

297279
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!
298280

299-
Finally, if for some reason you prefer to keep the copies in the Vuex store and use custom mutations for all update, you can set the `keepCopiesInStore` option to `true`. This will cause the copies to be stored in `state.copiesById`.
281+
> Nonte: You could previously use the `keepCopiesInStore` option to keep copies in `state.copiesById`. In 2.0, this feature is deprecated and will be removed from the next release.
300282
301283
### `instance.commit()`
302284

303285
```js
304-
const { Todo } = this.$FeathersVuex
286+
const { Todo } = this.$FeathersVuex.api
305287
const todo = new Todo({ id: 1, description: 'Do something!' })
306288
const todoCopy = todo.clone()
307289

@@ -315,7 +297,7 @@ console.log(todoCopy.description) // --> 'Do something else!'
315297
### `instance.reset()`
316298

317299
```js
318-
const { Todo } = this.$FeathersVuex
300+
const { Todo } = this.$FeathersVuex.api
319301
const todo = new Todo({ id: 1, description: 'Do something!' })
320302
const todoCopy = todo.clone()
321303

0 commit comments

Comments
 (0)