Package Exports
- vuex-loopback
- vuex-loopback/dist/main.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (vuex-loopback) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Installing
Install axios and vuex-loopback.
yarn add axios vuex-loopbackor via npm
npm install axios vuex-loopbackCreate Vuex module
1. Import axios and module factory.
import axios from 'axios';
import {createModule} from 'vuex-loopback';2. Create axios instance with baseURL option.
const client = axios.create({
baseURL: 'https://my-domain.com/api/',
});3. Define collection model with default fields.
const model = {
id: '',
title: '',
body: '',
}4. Create Vuex module by the module factory.
Before use built-in components ItemsLoader and ItemEditor you need to create the Vuex module of Loopback collection which you want to manage. For example we will create a named module vlArticles of Articles collection.
new Vuex.Store({
modules: {
// ...
vlArticles: {
namespaced: true,
...createModule({
client, // (required) Axios instance.
model, // (required) Collection model.
collection: 'Articles', // (required) Plural collection name.
state: {}, // Extend default state.
getters: {}, // Extend default getters.
actions: {}, // Extend default actions.
mutations: {}, // Extend default mutations.
}),
},
// ...
}
});It's recommended to prefer vl prefix of a module name to mark module is created by vuex-loopback.
Vuex module usage
The following fields will contain data when you get, create or update a single item.
item: object = null- Persisted item.tempItem: object = null- New or modified item.
And a state of a multiple items:
items: object[] = []- Fetched items.
It's a general part of module state.
Create item
In the previous step we provided the model with default fields to the module factory. An action CREATE_TEMP_ITEM will create a new item by this model automatically (only tempItem state, not in database).
store.dispatch(
'vlArticles/CREATE_TEMP_ITEM',
{title: 'My Article'},
);The second argument is not required but you can patch data of new item.
State of tempItem now is:
{
"id": "",
"title": "My Article",
"body": ""
}By an action PUT_TEMP_ITEM the data of tempItem will be created or updated (if exists) in database.
await store.dispatch(
'vlArticles/PUT_TEMP_ITEM',
);During request a state of loading is true.
State of item and tempItem now is:
{
"id": "5fd491fceea2be937cb838fc",
"title": "My Article",
"body": ""
}After that, we have a new state of item which contains persisted data, but the tempItem has updated also (by a new id value). So if you will change the state of tempItem then you can check differences between persisted data item and modified tempItem, and discard changes by SET_TEMP_ITEM mutation to a previous value from item state.
Type of generated ID is depends to your database.
Fetch items
Create another one article.
store.dispatch(
'vlArticles/CREATE_TEMP_ITEM',
{title: 'Second Article'}
);
await store.dispatch(
'vlArticles/PUT_TEMP_ITEM'
);Dispatch an action FETCH_ITEMS to get an array in items state.
await store.dispatch(
'vlArticles/FETCH_ITEMS',
);Use a second argument to provide fetching options.
State of items is:
[
{
"id": "5fd491fceea2be937cb838fc",
"title": "My Article",
"body": ""
},
{
"id": "5fd491fceea2be937cb838fb",
"title": "Second Article",
"body": ""
}
]The FETCH_ITEMS action will request an items by conditions defined in the state which you can set by mutations.
Fetch item by ID
An action FETCH_ITEM will update item and tempItem state by fetched data.
await store.dispatch(
'vlArticles/FETCH_ITEM',
{id: '5fd491fceea2be937cb838fc'},
);State of item and tempItem now is:
{
"id": "5fd491fceea2be937cb838fc",
"title": "My Article",
"body": ""
}Update item
Before update a database, we need to modify the data of tempItem which was fetched in the previous step.
const {tempItem} = store
.state
.vlArticles;
store.commit('vlArticles/SET_TEMP_ITEM', {
...tempItem,
body: 'Article body',
});State of tempItem now has a new body value:
{
"id": "5fd491fceea2be937cb838fc",
"title": "My Article",
"body": "Article body"
}Commit changes by PUT_TEMP_ITEM action.
await store.dispatch(
'vlArticles/PUT_TEMP_ITEM',
);Now your database and item state has updated by modified tempItem.
Remove item
An action REMOVE_ITEM will remove an item from database.
await store.dispatch(
'vlArticles/REMOVE_ITEM',
'5fd491fceea2be937cb838fc',
);The item will be removed from the state automatically.
Load items by Vue Component
Built-in component ItemsLoader will help you to load collection items right in Vue template. A scope of default slot has some usefull methods and properties to create items list with lazy-load or pagination behaviours.
Props
module: string- Name of Vuex module.noAutoload: boolean- Do not autoload items after mount.
Scope of default slot
items: object[]- Loaded items.loading: boolean- Loading state.page: number- Current page.pages: number- Total number of pages.hasMore: boolean- Can we load more?load()- Load items.loadPage(page: number)- Load specific page.loadMore()- Load more items.
* Component will load items automatically if prop noAutoload has not specified.
* All properties and methods of slot scope are accessible by component reference (ref attribute).
Basic example
1. Import ItemsLoader from vuex-loopback.
import {ItemsLoader} from 'vuex-loopback';2. Define local component.
export default {
// ...
components: {
ItemsLoader,
},
// ...
}3. Use it to load collection items.
<!-- Loader -->
<items-loader
module="vlArticles">
<template
slot-scope="{items, hasMore, loadMore}">
<!-- Item -->
<div
:key="item.id"
v-for="item in items">
{{ item.title }}
</div>
<!-- More Button -->
<button
v-if="hasMore"
@click="loadMore">
More
</button>
</template>
</items-loader>Manage an item by Vue Component
You are able to create, update or remove collection item by built-in component ItemEditor. Same as above ItemEditor has a scope of default slot which provides specific methods and properties.
Props
module: string- Name of Vuex module.extend: object- Extend an item fields.
Scope of default slot
item: object- Selected item.loading: boolean- Loading state.edit(item: object)- Select or create item if no argument specified.set(item: object)- Update selected or created item temporary.save()- Commit temporary changes applied by methodset.remove()- Remove selected item from collection.
* All properties and methods of slot scope are accessible by component reference (ref attribute).
Basic example
1. Import ItemEditor from vuex-loopback.
import {ItemEditor} from 'vuex-loopback'; // new line
import {ItemsLoader} from 'vuex-loopback';2. Define local component.
export default {
// ...
components: {
ItemEditor, // new line
ItemsLoader,
},
// ...
}3. Use it to create editor form.
<!-- Editor -->
<item-editor
ref="editor"
module="vlArticles">
<template
slot-scope="{item, set, save, remove}">
<form
@submit.prevent="save">
<!-- Title Field -->
<input
:value="item.title"
@input="set({...item, title: $event})"/>
<!-- Save Button -->
<button
type="submit">
Save
</button>
<!-- Remove Button -->
<button
v-if="item.id"
@click="remove">
Remove
</button>
</form>
</template>
</item-editor>4. Update items loader template.
<!-- Loader -->
<items-loader
module="vlArticles">
<template
slot-scope="{items, hasMore, loadMore}">
<!-- Item -->
<div
:key="item.id"
v-for="item in items">
{{ item.title }}
<!-- Edit Button -->
<button
@click="() => $refs.editor.edit(item)">
Edit
</button>
</div>
<!-- More Button -->
<button
v-if="hasMore"
@click="loadMore">
More
</button>
<!-- Create Button -->
<button
@click="() => $refs.editor.edit()">
Create
</button>
</template>
</items-loader>Module structure
You may want to use Vuex module directly.
Let's see what it has.
State
item: object = null- Loaded item.tempItem: object = null- Clone ofitem.items: object[] = []- Loaded items.skip: number = 0- Items offset.limit: number = 20- Items limit.total: number = 0- Total items.orderBy: string = ''- Sort by field.orderDesc: boolean = ''- Sort descending.searchBy: string[] = ['name']- Search by fields.searchQuery: string = ''- Searching query.where: object = {}- Fetching condition.loading: boolean = false- Loading state.include: string[] = []- Fetching relations.fields: string[] = []- Fetching fields.
Getters
page: number- Number of current page.totalPages: number- Number of total pages.hasMore: boolean- Can we load more? (lazy loading)itemChanged: boolean- State ofitemandtempItemis not the same.
Mutations
RESETSET_ITEM(value: object)RESET_ITEMSET_TEMP_ITEM(value: object)RESET_TEMP_ITEMSET_ITEMS(value: object[])RESET_ITEMSSET_SKIP(value: number)RESET_SKIPSET_LIMIT(value: number)RESET_LIMITSET_TOTAL(value: number)RESET_TOTALSET_ORDER_BY(value: string)RESET_ORDER_BYSET_ORDER_DESC(value: boolean)RESET_ORDER_DESCSET_SEARCH_BY(value: string[])RESET_SEARCH_BYSET_SEARCH_QUERY(value: string)RESET_SEARCH_QUERYSET_WHERE(value: object)RESET_WHERESET_LOADING(value: boolean)RESET_LOADINGSET_INCLUDE(value: string[])RESET_INCLUDESET_FIELDS(value: string[])RESET_FIELDSUPDATE_ITEM(item: object)REMOVE_ITEM(id: number|string)
Actions:
FETCH_ITEM(payload)id: number|stringfilter: object = {}noTempItem: boolean = false
FETCH_ITEMS(payload)filter: object = {}noGlobals: boolean = falseappend: boolean = false
CREATE_ITEM(payload)data: objectfilter: object = {}
PATCH_ITEM(payload)id: number|stringdata: objectfilter: object = {}
REMOVE_ITEM(id: number|string)CREATE_TEMP_ITEM(item: object = null)PUT_TEMP_ITEM(payload)filter: object = {}noPatch: boolean = falsereset: boolean = false
SEARCH_ITEMS(payload)query: string = ''searchBy: string[] = null
FETCH_PAGE(payload)page: number = 1
FETCH_MORE()
Tests
1. Clone loopback-example-relations and start web-server.
git clone https://github.com/strongloop/loopback-example-relations.git
cd loopback-example-relations
yarn
yarn start2. Clone vuex-loopback in a new terminal session and run the tests.
git clone https://github.com/mikeevstropov/vuex-loopback.git
cd vuex-loopback
yarn
yarn testExamples
Vue CLI project vuex-loopback-example
Todo
- State factory.
- Mutations factory.
- Actions factory.
- Getters factory.
- Loader component.
- Editor component.
- Documentation.
- Examples.