Skip to content

Commit 0a24ba3

Browse files
committed
Add CRUD form wrapper example
1 parent d45732e commit 0a24ba3

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

docs/feathers-vuex-form-wrapper.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,122 @@ The default slot contains only four attributes. The `clone` data can be passed
126126
- `save`: {Function} When called, it commits the data and saves the record (with eager updating, by default. See the `eager` prop.) The save method calls `instance.save()`, internally, so you can pass a params object, if needed.
127127
- `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.
128128
- `remove`: {Function} When called, it removes the record from the API server and the Vuex store.
129+
130+
## Example Usage: CRUD Form
131+
132+
It's a pretty common scenario to have the same form handle editing and creating data. Below is a basic example of how you could use the FeathersVuexFormWrapper for this. A few things to notice about the example:
133+
134+
1. It uses a `Todo` Model class to create and edit todos. The `$FeathersVuex` object is available on `this` only when the [Feathers-Vuex Vue plugin](./vue-plugin.md) is used.
135+
2. It assumes that you have a route setup with an `:id` parameter.
136+
3. It assumes that the data has a MongoDB-style `_id` property, where an SQL-based service would probably use `id`.
137+
138+
```vue
139+
<template>
140+
<FeathersVuexFormWrapper :item="item" watch>
141+
<template v-slot="{ clone, save, reset, remove }">
142+
<TodoEditor
143+
:item="clone"
144+
@save="save().then(handleSaveResponse)"
145+
@reset="reset"
146+
@remove="remove"
147+
></TodoEditor>
148+
</template>
149+
</FeathersVuexFormWrapper>
150+
</template>
151+
152+
<script>
153+
import { FeathersVuexFormWrapper } from 'feathers-vuex'
154+
import TodoEditor from './TodoEditor.vue'
155+
156+
export default {
157+
name: 'Todo',
158+
components: {
159+
FeathersVuexFormWrapper,
160+
TodoEditor
161+
},
162+
props: {
163+
currentItem: {
164+
type: Object,
165+
required: true
166+
}
167+
},
168+
computed: {
169+
id() {
170+
return this.$route.params.id
171+
},
172+
// Returns a new Todo if the route `id` is 'new', or returns an existing Todo.
173+
item() {
174+
const { Todo } = this.$FeathersVuex.api
175+
176+
return this.id === 'new' ? new Todo() : Todo.getFromStore(this.id)
177+
},
178+
},
179+
watch: {
180+
id: {
181+
handler(val) {
182+
// Early return if the route `:id` is 'new'
183+
if (val === 'new') {
184+
return
185+
}
186+
const { Todo } = this.$FeathersVuex.api
187+
const existingRecord = Todo.getFromStore(val)
188+
189+
// If the record doesn't exist, fetch it from the API server
190+
// The `item` getter will automatically update after the data arrives.
191+
if (!existingRecord) {
192+
Todo.get(val)
193+
}
194+
},
195+
// We want the above handler handler to run immediately when the component is created.
196+
immediate: true
197+
}
198+
},
199+
methods: {
200+
handleSaveReponse(savedTodo) {
201+
// Redirect to the newly-saved item
202+
if (this.id === 'new') {
203+
this.$router.push({ params: { id: savedTodo._id } })
204+
}
205+
}
206+
}
207+
}
208+
</script>
209+
```
210+
211+
Here is a minimal example showing a 'TodoEditor' component. A few things to notice about this component:
212+
213+
1. It's minimal on purpose to show you the important parts of working with the `FeathersVuexFormWrapper`.
214+
1. It emits the `save`, `reset`, and `remove` events, which are connected to the `FeathersVuexFormWrapper` in the above code snippet.
215+
1. It's not styled to keep it simple. You'll probably want to add some styles. ;)
216+
1. The Delete button immediately emits remove, so the instance will be deleted immediately. You probably want, instead, to show a prompt or confirmation dialog to ask the user to confirm deletion.
217+
1. This is HTML, so the button `type` is important. If you forget to add `type="button"` to a button, it will default to `type="submit"`. Clicking the button would submit the form and call the `@submit.prevent` handler on the `<form>` element. This even applies to buttons inside child components of the form. You definitely want to remember to put `type` attributes on all of your buttons.
218+
219+
```vue
220+
<template>
221+
<form @submit.prevent="$emit('save')">
222+
<input type="checkbox" v-model="item.isComplete" />
223+
<input type="text" v-model="item.description" />
224+
225+
<!-- Submits the form, see the @submit handler, above -->
226+
<button type="submit">Save</button>
227+
228+
<!-- Emitting reset will restore the item back to the stored version. -->
229+
<button type="button" @click="$emit('reset')>Reset</button>
230+
231+
<!-- Delete's the instance -->
232+
<button type="button" @click="$emit('remove')>Delete</button>
233+
</form>
234+
</template>
235+
236+
<script>
237+
export default {
238+
name: 'TodoEditor',
239+
props: {
240+
item: {
241+
type: Object,
242+
required: true
243+
}
244+
}
245+
}
246+
</script>
247+
```

0 commit comments

Comments
 (0)