npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vuex-loopback

v1.5.4

Published

Vuex module factory for Loopback

Downloads

50

Readme

npm version license

Installing

Install axios and vuex-loopback.

yarn add axios vuex-loopback

or via npm

npm install axios vuex-loopback

Create 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 method set.
  • 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 of item.
  • 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 of item and tempItem is not the same.

Mutations

  • RESET
  • SET_ITEM(value: object)
  • RESET_ITEM
  • SET_TEMP_ITEM(value: object)
  • RESET_TEMP_ITEM
  • SET_ITEMS(value: object[])
  • RESET_ITEMS
  • SET_SKIP(value: number)
  • RESET_SKIP
  • SET_LIMIT(value: number)
  • RESET_LIMIT
  • SET_TOTAL(value: number)
  • RESET_TOTAL
  • SET_ORDER_BY(value: string)
  • RESET_ORDER_BY
  • SET_ORDER_DESC(value: boolean)
  • RESET_ORDER_DESC
  • SET_SEARCH_BY(value: string[])
  • RESET_SEARCH_BY
  • SET_SEARCH_QUERY(value: string)
  • RESET_SEARCH_QUERY
  • SET_WHERE(value: object)
  • RESET_WHERE
  • SET_LOADING(value: boolean)
  • RESET_LOADING
  • SET_INCLUDE(value: string[])
  • RESET_INCLUDE
  • SET_FIELDS(value: string[])
  • RESET_FIELDS
  • UPDATE_ITEM(item: object)
  • REMOVE_ITEM(id: number|string)

Actions:

  • FETCH_ITEM(payload)

    • id: number|string
    • filter: object = {}
    • noTempItem: boolean = false
  • FETCH_ITEMS(payload)

    • filter: object = {}
    • noGlobals: boolean = false
    • append: boolean = false
  • CREATE_ITEM(payload)

    • data: object
    • filter: object = {}
  • PATCH_ITEM(payload)

    • id: number|string
    • data: object
    • filter: object = {}
  • REMOVE_ITEM(id: number|string)

  • CREATE_TEMP_ITEM(item: object = null)

  • PUT_TEMP_ITEM(payload)

    • filter: object = {}
    • noPatch: boolean = false
    • reset: 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 start

2. 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 test

Examples

Vue CLI project vuex-loopback-example

Todo

  • [x] State factory.
  • [x] Mutations factory.
  • [x] Actions factory.
  • [x] Getters factory.
  • [x] Loader component.
  • [x] Editor component.
  • [ ] Documentation.
  • [x] Examples.