Giter VIP home page Giter VIP logo

feathers-vuex's Introduction

Feathers-Vuex

Build Status Dependency Status Download Status Greenkeeper badge

Feathers-Vuex is a first class integration of FeathersJS and Vuex. It implements many Redux best practices under the hood, eliminates a lot of boilerplate code with flexible data modeling, and still allows you to easily customize the Vuex store.

feathers-vuex service logo

Demo & Documentation

Demo

See https://vuex.feathersjs.com for full documentation.

Installation

npm install feathers-vuex --save
yarn add feathers-vuex

IMPORTANT: Feathers-Vuex is (and requires to be) published in ES6 format for full compatibility with JS classes. If your project uses Babel, it must be configured properly. See the Project Configuration section for more information.

Contributing

This repo is pre-configured to work with the Visual Studio Code debugger. After running yarn install, use the "Mocha Tests" debug script for a smooth debugging experience.

License

Copyright (c) Forever and Ever, or at least the current year.

Licensed under the MIT license.

feathers-vuex's People

Contributors

andrewharvey avatar beeplin avatar calvinwalzel avatar cl3mm avatar cmeissl avatar daffl avatar dallinbjohnson avatar dependabot-preview[bot] avatar dependabot[bot] avatar ericirish avatar fossprime avatar fratzinger avatar greenkeeper[bot] avatar guzz avatar hamiltoes avatar imrec avatar j3m5 avatar jeffborg avatar jorgenvatle avatar marshallswain avatar marsimeau avatar metareason avatar miguelrk avatar morphatic avatar mrfrase3 avatar ndamjan avatar nickbolles avatar sebastien-prudhomme avatar tylermmorton avatar wdmtech avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

feathers-vuex's Issues

Won't connect to feathersjs services

Apologies for the noob question, but I'm just getting started out with Nuxt/feathers-vuex and am having issues. I'm sure I'm missing something very basic, but feathers-vuex doesn't seem to be "connecting" to the feathers services I've defined.

Here's store/index.js:

import Vuex from 'vuex'
import feathersVuex from 'feathers-vuex'
import feathersClient from '../feathers-client'

const { service } = feathersVuex(feathersClient, { idField: 'id' })

Vue.use(Vuex)
 
const createStore = () => { 
    
    return new Vuex.Store({
     plugins: [ 
            service('api/users')
    ]
    })
}

  
  export default createStore;

And here's feathers-client.js:

import feathers from '@feathersjs/client'
import restClient from '@feathersjs/rest-client'
import feathersVuex from 'feathers-vuex'
import axios from '~axios'

const feathersClient = feathers()
     .configure(restClient('http://localhost:3030').axios(axios));

export default feathersClient

I have a feathers api endpoint at /api/users, but no matter what variant of 'users' or 'api/users' etc i put in service(), nothing seems to be rendering in the vue template:

<template>
  <section class="container">
    <ul>
          <li v-for="user in users" :key="user.email">{{user.id}}</li>
    </ul>
  </section>
</template>

<script>
import { mapGetters, mapState } from 'vuex'

export default { 
    name: 'test',
    computed: mapState([
        'users'
    ])
}

</script>

This shows nothing, despite users having records populated populated in the SQL database.

Any ideas would be more than welcome! I'm sure I'm missing something, I'm just not sure what...

How can I keep authenticated in all components

I need to use feathersVuex actions in lots of components. I dont want to put this.$store.dispatch('auth/authenticate') in every component to use the vuex store.

Where would you recommend that line of authentication?
I tried in the mounted() of App.vue, but it does not work

Thanks

setCurrent copy only works with object, not when passing id

Steps to reproduce

(First please check that this issue is not already solved as described
here
)

  • Tell us what broke. The more detailed the better.
  • If you can, please create a simple example that reproduces the issue and link to a gist, jsbin, repo, etc.

Expected behavior

When calling mutation setCurrent(id) it should copy the current item into copy per the README

Actual behavior

If id is passed the copy is set to the id instead of the object.

System configuration

Tell us about the applicable parts of your setup.

Module versions
feathers-vuex: 0.8.0

NodeJS version: v8.5.0

Error Running Tests with Feathers-Vuex in Jest

Steps to reproduce

  1. Add Jest to a project with Feathers-Vuex (as in the Vue webpack template PR here

Expected behavior

Test should be run!

Actual behavior

Test suite failed to run

    No service was found. Please configure a transport plugin on the Feathers Client. Make sure you use the client version of the transport, like `feathers-socketio/client` or `feathers-rest/client`.
      
      at createServiceModule (node_modules/feathers-vuex/lib/service-module/service-module.js:68:13)
      at Object.<anonymous> (src/store/index.js:30:3)
      at Object.<anonymous> (src/utils.js:2:14)
      at src/components/Create/MovieSuggest.vue:20:66
      at Object.<anonymous> (src/components/Create/MovieSuggest.vue:101:3)
      at Object.<anonymous> (test/unit/specs/MovieSuggest.spec.js:9:241)
          at Generator.next (<anonymous>)
          at new Promise (<anonymous>)
          at Generator.next (<anonymous>)
          at <anonymous>

This occurs for every test. It appears the return value of client.service() is undefined when run in Jest. This behaviour is not seen when run with Karma/Mocha.

I tried to get a minimal version working with feathers-vuex-chat but it was quite behind the current webpack template branch as well as the current version of feathers-vuex. You can see the branch I'm testing this on here.

System configuration

Tell us about the applicable parts of your setup.

Module versions (especially the part that's not working):

"feathers": "^2.2.0",
"feathers-authentication-client": "^0.3.3",
"feathers-hooks": "^2.0.2",
"feathers-socketio": "^2.0.0",
"feathers-vuex": "^1.0.4",
"babel-jest": "^21.2.0",
"jest": "^21.2.1",
"vue-jest": "^1.0.2",
"vue": "^2.4.2",

NodeJS version:
Node 8.7 and 7.5

Operating System:
Ubuntu 17

Hoping to support server paging parameters

feathersjs server return the data structure

{
"total": "",
"limit": "",
"skip": "<number of skipped items (offset)>",
"data": [/* data */]
}

feathers-vuex removed total, limit, skip .I hope to be able to keep these data.

Thanks

persist auth module state

Steps to reproduce

(First please check that this issue is not already solved as described
here
)

  • If you can, please create a simple example that reproduces the issue and link to a gist, jsbin, repo, etc.
  • Tell us what broke. The more detailed the better.

Expected behavior

The authentication persist as it stored in browser storage

Actual behavior

the authentication ignore the token in storage

System configuration

Tell us about the applicable parts of your setup.

Module versions (especially the part that's not working):
latest
NodeJS version:
8.9
Operating System:
Win10
Browser Version:
chrome 62
React Native Version:

Module Loader:

Reactive auth user object

When you authenticate via feathers you can have it return a user object with the authenticated user. Currently that user object is not reactive like everything else from feathers services. It does not update automatically if there are changes on the server. This small fix will make it reactive. marshall suggested posting it here to make it easier to add to the code base in the future. (He also came up with the original psuedo-code so thanks for that! ;))

function updateAuthUser(updatedUser) {
  const currentUser = store.state.auth.user;
  if (currentUser && (currentUser._id === updatedUser._id)) {
    store.commit('auth/setUser', updatedUser);
  }
}

feathersClient.service('users').on('patched', (user) => {
  updateAuthUser(user);
});
feathersClient.service('users').on('updated', (user) => {
  updateAuthUser(user);
});

I personally have this code in main.js and am importing the feathersClient. If you place it elsewhere you may need to make some modifications to the code so that it will work with your store object.

pushing update logic to background worker

With some larger number of records kept in store the UI becomes unresponsive during updates. Some quick profiling revealed that the addOrUpdateList function is taking most time.

Proposal: put the list manipulation logic to background worker, add some state like newDataProcessing to indicate that something is going on.

How to unsubscribe?

I'm loving this package, but one thing puzzles me. store.dispatch('things/find') keeps my data reactive, so how do I unsubscribe?

Integration with Nuxt

So, like I mentioned on Slack, I'm having a hard time trying to add feathers-vuex into a Feathers + Nuxt starting template I'm working on (repo can be found here.)

Since Nuxt enforces a directory structure and it somewhat abstracts you from how a Vue app is made (taking away things like webpack's config, or, more importantly, your Vue app's entry point) it becomes harder to determine which is the best place for initializing the Feathers client.

Steps to reproduce

With the above in mind, I replaced Nuxt's default layout with my own which looks like this:

<template>
  <nuxt />
</template>

<script>
import '~feathers'; // This is the feathers client

export default {
  name: 'default-layout',
};
</script>

And this is my Feathers client code:

import feathers from 'feathers/client';
import auth from 'feathers-authentication-client';
import hooks from 'feathers-hooks';
import feathersVuex from 'feathers-vuex';
import socketio from 'feathers-socketio/client';
import { CookieStorage } from 'cookie-storage';
import io from 'socket.io-client';
import store from '~store';

const socket = io('http://localhost:3030');
const app = feathers()
  .configure(socketio(socket))
  .configure(hooks())
  .configure(auth({ storage: new CookieStorage() }))
  .configure(feathersVuex(store, {
    idField: '_id',
    auth: {
      userService: '/users',
    },
  }));

app.service('users');

export default app;

Expected behavior

SSR should work and I should get a Vuex store with feathers' services.

Actual behavior

Nuxt fails at rendering the app in the server with this message:

 DONE  Compiled successfully in 737ms                                                                                                12:05:16 PM

> Open http://127.0.0.1:3000

  nuxt:render Rendering url / +36s
/Users/silvestre/Projects/feathers-nuxt/node_modules/vue-meta/lib/vue-meta.js:824
    var htmlTag = document.getElementsByTagName('html')[0];
                  ^

ReferenceError: document is not defined
    at updateClientMetaInfo (/Users/silvestre/Projects/feathers-nuxt/node_modules/vue-meta/lib/vue-meta.js:824:19)
    at Vue$2.refresh (/Users/silvestre/Projects/feathers-nuxt/node_modules/vue-meta/lib/vue-meta.js:885:35)
    at /Users/silvestre/Projects/feathers-nuxt/node_modules/vue-meta/lib/vue-meta.js:1013:74
    at Timeout._onTimeout (/Users/silvestre/Projects/feathers-nuxt/node_modules/vue-meta/lib/vue-meta.js:924:5)
    at ontimeout (timers.js:386:14)
    at tryOnTimeout (timers.js:250:5)
    at Timer.listOnTimeout (timers.js:214:5)
[nodemon] app crashed - waiting for file changes before starting...

System configuration

Module versions:

{
  "dependencies": {
    "body-parser": "^1.17.1",
    "compression": "^1.6.2",
    "cors": "^2.8.3",
    "feathers": "^2.1.1",
    "feathers-authentication": "^1.2.0",
    "feathers-authentication-jwt": "^0.3.1",
    "feathers-authentication-local": "^0.3.4",
    "feathers-configuration": "^0.4.1",
    "feathers-errors": "^2.6.2",
    "feathers-hooks": "^1.8.1",
    "feathers-hooks-common": "^2.0.3",
    "feathers-rest": "^1.7.1",
    "feathers-sequelize": "^1.4.5",
    "feathers-socketio": "^1.5.2",
    "feathers-vuex": "^0.2.2",
    "helmet": "^3.5.0",
    "nuxt": "^0.10.5",
    "pg": "^6.1.5",
    "sequelize": "^3.30.4",
    "serve-favicon": "^2.4.2",
    "socket.io-client": "^1.7.3",
    "winston": "^2.3.1"
  },
  "devDependencies": {
    "eslint": "^3.19.0",
    "eslint-config-airbnb": "^14.1.0",
    "eslint-plugin-html": "^2.0.1",
    "eslint-plugin-import": "^2.2.0",
    "mocha": "^3.2.0",
    "nodemon": "^1.11.0",
    "request": "^2.81.0",
    "request-promise": "^4.2.0"
  }
}

NodeJS version:

$ node -v
v7.9.0

Operating System:

I'm running macOS Sierra 10.12.4

Browser Version:

Google Chrome 57.0.2987.133

Module Loader:

Webpack, provided by Nuxtโ€ฆ so there's no actual webpack config because it's "created dynamically" by Nuxt.

Nuxt does not know window.localStorage

I just wanted to give feathersjs a try in combination with VueJS/Nuxt and feathers-vuex, but the docs seem to leave one small detail out that makes my whole application not work: When I add feathers-vuex (version 1.0.0-pre3) and I add .configure(auth({ storage: window.localStorage })) inside feathers-client.js, Nuxt complains that window is not defined due to it running both client and server side.

Incompatible with latest version of feathers-reactive

This error appears to come only when I start using the feathers-reactive v0.5.1. With v0.4.1 there appears to be no such error

TypeError: Method Promise.prototype.then called on incompatible receiver #
at Promise.then ()
at Promise.catch ()
at find (actions.js?1939:38)
at Array.wrappedActionHandler (vuex.esm.js?358c:598)
at Store.dispatch (vuex.esm.js?358c:341)
at Store.boundDispatch [as dispatch] (vuex.esm.js?358c:266)
at VueComponent.created (RfidReader.vue?c5fe:69)
at callHook (vue.esm.js?efeb:2556)
at VueComponent.Vue._init (vue.esm.js?efeb:4000)
at new VueComponent (vue.esm.js?efeb:4169)

if (service.rx) {
      Object.getPrototypeOf(request).catch(handleError) // <-----
} else {
       request.catch(handleError)
}

wrong import

Steps to reproduce

(First please check that this issue is not already solved as described
here
)

  • Tell us what broke. The more detailed the better.
  • If you can, please create a simple example that reproduces the issue and link to a gist, jsbin, repo, etc.

Expected behavior

it should import the proxied file on lib/client/index

Actual behavior

not import the correct file

// quick solution for that is
import feathersClient from 'feathers/lib/client'

System configuration

Tell us about the applicable parts of your setup.

Module versions (latest):

NodeJS version: 6.11.4

Operating System: Windows 10

Browser Version: Chrome 61.0.3163.100 (Official Build) (64-bit)

React Native Version:

Module Loader: webpack

conflict merging as part of this package

Proposal: implement some conflict merge strategies for cases of simultaneous editing of the same object when feathers-reactive is used.

For example: Alice and Bob open the same record. Alice changes a field Title and Bob changes field Content. Depending on who saves first, other person loses his work as his current record is replaced. Another case is that Alice deletes the record while Bob is working on it.

Currently I implemented such detection logic in a mixin and a decision mechanism on which version to keep, but maybe it would be good to have it as part of this package.

What do you think?

`clearList` mutation behaves unexpectedly if `current` isn't defined

The latest update introduced a much helpful clearList mutation which, unfortunately, behaves unexpectedly when there's no current element defined and redefines the list as an Array with a single undefined element.

Here's Vue DevTools after calling the clearList mutation:

captura de pantalla 2017-04-18 a la s 15 40 50

Here's a quick workaround I put together by editing the package's code (this is the transpiled code):

    clearList: function clearList(state) {
      var currentId = state.currentId;
      var current = state.keyedById[currentId];

      if (currentId && current) {
        state.keyedById = _defineProperty({}, currentId, current);
        state.ids = [currentId];
      } else {
        state.keyedById = {};
        state.ids = [];
      }
    },

using deep-assign package

I stumbled upon some strange exception where a nested field from a JSON object was missing... Can't reproduce it currently in JSFiddle.

To me it seems some like cloning issue so I checked where it happens, and the responsibility is on deep-assign package.

According to https://github.com/sindresorhus/deep-assign:

[DON'T USE THIS MODULE PLEASE]

Replacing it with object-assign doesn't work. I will see some alternatives and investigate further...

Update Pagination After Create / Remove

Once a create has happened and doing a check on the store pagination object this does not reflect the newest addition.

I am using the pagination.default.total in order to keep a pagination component up to date with how many items and how many pages needs to be displayed.

Release article

This deserves a fancy release article after the Auk announcement.

errorOnAuthenticate is not reset

Steps to reproduce

Use auth/authenticate action with wrong credentials
Use auth/authenticate action with right credentials

Expected behavior

The auth.errorOnAuthenticate must be undefined.

Actual behavior

The auth.errorOnAuthenticate keeps previous error.

All the best

namespaces cannot be arrays for nested modules (supported by vuex)

Steps to reproduce

You cannot provide string array namespaces to feathers-vuex.

I've made an example repo here: https://github.com/jskrzypek/feathers-chat-vuex/tree/array-namespaces. If you clone & install from this branch the app will fail.

You can swap the commented line here to make it work:
https://github.com/jskrzypek/feathers-chat-vuex/blob/array-namespaces/src/api/feathers-client.js#L25-L26

While it's working you can inspect the vuex store with vue-devtools and see that it looks something like this:
feathers-chat-vuex

Expected behavior

Providing namespaces as arrays should allow the user to create service-modules at arbitrarily deep levels of module nesting as described here: https://github.com/vuejs/vuex/blob/dd7f8178d93e6121a447c410b9c652f40cd80937/docs/en/modules.md#dynamic-module-registration

Actual behavior

When you switch the line comments as I mentioned above, you can notice that while the getters work to target the right state information, the modules states are not correctly nested. Look at my todos module's state, the tasks there is actually the state of a nested submodule with the namespace todos/tasks/. todos/otherTasks is another module, that looks nested, but is not.
The todos/tasks/ module obeys the desired behavior for nested modules because an array is passed as the namespace to store.registerModule(), something that currently is not possible with feathers-vuex.

For a more in-depth look, I added a breakpoint after these lines so you can see the inner workings of the vuex module:
feathers-chat-vuex

FWIW, the logic for resolving getters according to namespaces is the same regardless of whether a single string or an array is used, so this app continues to work even when the child modules are not really children, but there may be points at which this behavior breaks down.

System configuration

Tell us about the applicable parts of your setup.

Module versions (especially the part that's not working):

{
  "babel-polyfill": "^6.23.0",
  "date-fns": "^2.0.0-alpha.1",
  "deep-assign": "^2.0.0",
  "feathers": "^2.1.4",
  "feathers-authentication-client": "^0.3.2",
  "feathers-authentication-popups": "^0.1.2",
  "feathers-hooks": "^2.0.1",
  "feathers-reactive": "^0.4.1",
  "feathers-socketio": "^2.0.0",
  "feathers-vuex": "^0.7.2",
  "getbase": "^3.4.2",
  "global": "^4.3.2",
  "rubberduck": "^1.1.1",
  "rxjs": "^5.4.1",
  "steal": "^1.5.4",
  "vue": "^2.3.4",
  "vue-router": "^2.6.0",
  "vuex": "^2.3.1"
}

NodeJS version:
Observed on [email protected], [email protected]
Operating System:
Os X Sierra 10.12.6
Browser Version:
Chrome 61.0.3163.31 (Official Build) beta (64-bit)

Beta test the pre-release

A Beta version of 1.0.0 is available and published on npm. If you would like to try it out, just do

npm install feathers-vuex@pre

You can find docs in the 1.0 branch readme.md:
https://github.com/feathersjs/feathers-vuex/tree/1.0

The internal API stays almost 100% the same, and only the general usage instructions change. The big breaking changes are

  1. No more using it as a Feathers plugin. This design was flawed and required complicated logic, making it more difficult to maintain. It also caused problems with SSR. Configuration is all done inside the Vuex store:
import Vue from 'vue'
import Vuex from 'vuex'
import feathersClient from '../feathers-client'
import feathersVuex from 'feathers-vuex'

const { service, auth } = feathersVuex(feathersClient)

Vue.use(Vuex)

const store = new Vuex.Store({
  plugins: [
    service('todos'),
    auth()
  ]
})

export default store
  1. Feathers services are now untouched. This means the .vuex method is gone, as is the vuexOptions object.

I would love it if somebody could try this out with Nuxt and let me know how it goes.

OAuth with Google and feathers-vuex

Thanks for this fantastic plugin!

I cannot seem to properly construct the OAuth login flow with Google and hope the explanation to this issue could be helpful for many.

Steps to reproduce

I have connected the feathers-vuex plugin with the client as in the docs here:

'use strict'

import 'babel-polyfill'
import feathers from 'feathers/client'
import hooks from 'feathers-hooks'
import auth from 'feathers-authentication-client'
import restClient from 'feathers-rest/client'
import feathersVuex from 'feathers-vuex'
import axios from 'axios'
import store from '@/store/'

const feathersClient = feathers()
  .configure(hooks())
  .configure(restClient('http://localhost:3030').axios(axios))
  .configure(auth({ storage: window.localStorage }))
  .configure(feathersVuex(store, {
    idField: 'id',
    auth: {
      userService: '/users',
    }
  }))

feathersClient.service('/users')

export default feathersClient

On the server side I have created local and oauth authentication with the feathers generator. I added my google client secret and ID in the config.

Now I have created a sign up page:

<template>
  <v-card raised class="center-text white">
    <v-btn @click.native="googleSignUp" secondary raised dark>Sign up with Google</v-btn>
    <p class="my-3 center-text">or</p>
    <v-card-text>
       <v-text-field 
        class="center-input" 
        label="Your work email"
        type="text"
        prepend-icon="email"
        required
        v-model="email"
        name="email"
      ></v-text-field> 
      <v-text-field 
        class="center-input"
        label="Enter a secure password"
        required
        prepend-icon="fingerprint"
        v-model="password"
        :append-icon="passwordVisible ? 'visibility' : 'visibility_off'"
        :append-icon-cb="() => (passwordVisible = !passwordVisible)"
        :type="passwordVisible ? 'password' : 'text'"
      ></v-text-field>
    </v-card-text>
    <v-card-actions>
      <v-btn class="center-btn" primary raised dark @click.native="register(email,password)">Get started now</v-btn>
    </v-card-actions>
    <v-card-text>
      <p class="my-3 center-text">Already have an account?
        <router-link :to="{ name: 'login' }">Login here.</router-link>
      </p>
    </v-card-text>
  </v-card>
</template>

<script>
import { mapActions } from 'vuex'
export default {
  data () {
    return {
      company: undefined,
      email: undefined,
      password: undefined,
      passwordVisible: true
    }
  },
  methods: {
    register (email, password) {
      this.createUser({ email, password })
        .then(res => this.authenticate({strategy: 'local', email, password}))
        .then(this.$router.push('/'))
        .then(err => {
          console.log(err)
        })
    },
    googleSignUp () {
      window.location.href = '/auth/google'
    },
    ...mapActions('users', {
      createUser: 'create'
    }),
    ...mapActions('auth', [
      'authenticate'
    ])
  }
}
</script>

The local registration works flawlessly. For the oauth registration all that should be required on the client side is to link to the relative path '/auth/google' that has been created by feathers:

image

Expected behavior

The user should be directed to the Google OAuth page and then redirected to the pre-specified callback URL.

Actual behavior

If I use a relative path, the browser directs to a blank page with the given URL. When I change the URL to direct to the same URL on the server (by changing the port), the user is redirected to the Google OAuth page. However, the redirect does not seem to work back to the client.

I wonder which URL is the correct one (client or server side), and how the flow can be implemented correctly. Thanks a lot for your help!

System configuration

{
  "name": "seads-app",
  "version": "1.0.0",
  "description": "The client for the seads app.",
  "author": "Johannes Herrmann <[email protected]>",
  "private": true,
  "scripts": {
    "dev": "node build/dev-server.js",
    "start": "node build/dev-server.js",
    "build": "node build/build.js",
    "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
    "test": "npm run unit",
    "lint": "eslint --ext .js,.vue src test/unit/specs"
  },
  "dependencies": {
    "axios": "^0.16.2",
    "babel-polyfill": "^6.23.0",
    "feathers": "^2.1.4",
    "feathers-authentication-client": "^0.3.2",
    "feathers-hooks": "^2.0.1",
    "feathers-rest": "^1.8.0",
    "feathers-vuex": "^0.7.0",
    "vee-validate": "^2.0.0-rc.8",
    "vue": "^2.3.4",
    "vue-router": "^2.3.1",
    "vuetify": "^0.13.0",
    "vuex": "^2.3.1"
  },
  "devDependencies": {
    "autoprefixer": "^6.7.2",
    "babel-core": "^6.22.1",
    "babel-eslint": "^7.1.1",
    "babel-loader": "^6.2.10",
    "babel-plugin-istanbul": "^4.1.1",
    "babel-plugin-transform-object-rest-spread": "^6.23.0",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-es2017": "^6.24.1",
    "babel-preset-stage-2": "^6.22.0",
    "babel-register": "^6.22.0",
    "chai": "^3.5.0",
    "chalk": "^1.1.3",
    "connect-history-api-fallback": "^1.3.0",
    "copy-webpack-plugin": "^4.0.1",
    "cross-env": "^4.0.0",
    "css-loader": "^0.28.0",
    "eslint": "^3.19.0",
    "eslint-config-airbnb-base": "^11.1.3",
    "eslint-config-standard": "^10.2.1",
    "eslint-friendly-formatter": "^2.0.7",
    "eslint-import-resolver-webpack": "^0.8.1",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-html": "^2.0.0",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^5.1.1",
    "eslint-plugin-promise": "^3.5.0",
    "eslint-plugin-standard": "^3.0.1",
    "eventsource-polyfill": "^0.9.6",
    "express": "^4.14.1",
    "extract-text-webpack-plugin": "^2.0.0",
    "file-loader": "^0.11.1",
    "friendly-errors-webpack-plugin": "^1.1.3",
    "html-webpack-plugin": "^2.28.0",
    "http-proxy-middleware": "^0.17.3",
    "inject-loader": "^3.0.0",
    "karma": "^1.4.1",
    "karma-coverage": "^1.1.1",
    "karma-mocha": "^1.3.0",
    "karma-phantomjs-launcher": "^1.0.2",
    "karma-phantomjs-shim": "^1.4.0",
    "karma-sinon-chai": "^1.3.1",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-spec-reporter": "0.0.30",
    "karma-webpack": "^2.0.2",
    "lolex": "^1.5.2",
    "mocha": "^3.2.0",
    "opn": "^4.0.2",
    "optimize-css-assets-webpack-plugin": "^1.3.0",
    "ora": "^1.2.0",
    "phantomjs-prebuilt": "^2.1.14",
    "rimraf": "^2.6.0",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "sinon": "^2.1.0",
    "sinon-chai": "^2.8.0",
    "stylus": "^0.54.5",
    "stylus-loader": "^3.0.1",
    "url-loader": "^0.5.8",
    "vue-loader": "^11.3.4",
    "vue-style-loader": "^2.0.5",
    "vue-template-compiler": "^2.3.4",
    "webpack": "^2.3.3",
    "webpack-bundle-analyzer": "^2.2.1",
    "webpack-dev-middleware": "^1.10.0",
    "webpack-hot-middleware": "^2.18.0",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 4.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

Real time updates stops working sometimes depending on the query

I'm not sure if this can be considered as a but when using mongoose and a $populate query the filters stops working and real-time updates stops working.

methods: {
	...mapActions('notifications', { findNotifications: 'find' }),

	fetch() {
		this.findNotifications({ query: { $populate: 'from' } })
	},
},

errorOn state set to empty object by action error handlers

Steps to reproduce

Execute an action on the store that results in a rejected promise from the feathers service.

The action error handlers use Objects.assign({}, error) to construct the mutation payload which results in an empty object. You can see this in action here, https://runkit.com/embed/4dduppvm6ldg

The mutation methods call serializeError(payload) which seems to indicate that is expecting an error type, so the Objects.assign can probably be removed.

Expected behavior

Expect errorOn* state (i.e. errorOnFind) to have a non-empty Object with properties from the error.

errorOnFind: {
  message: 'an error happened'
}

Actual behavior

An empty object is assigned

errorOnFind: {}

System configuration

Module versions (especially the part that's not working):
feathers-vuex: 1.0.3

Operating System:
macOS Sierra

Browser Version:
Chrome 61

[feature] remove action API, with params

Expected behavior

feathers-vuex action API should be remove([id, params]), as the one for the update action is update([id, data, params]) and the feathers service method is remove(id, params)

This prevents passing parameters to remove, disabling softDelete or doing multi-record query deletes.

Actual behavior

The current API is remove(id). parameters are not supported.

Workaround

Use the feathers service method directly.

I'm not sure if this handles soft delete or any sort of complicated remove hook. I assume the record is removed from the store by the id given on the removed service event.

How to setup vuex and vue-router to redirect when a store value is not set?

Steps to reproduce

Hi I'm creating a project based on the feathers-chat-vuex example and making a couple of changes in the router to check if a route has the property "requiresAuth": true in the meta.json file. If it does then check the value of store.state.auth.user provided by feathers-vuex, if this value is not set then redirect to login.

My code is as follows:
router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import store from '../store'

const meta = require('./meta.json')

// Route helper function for lazy loading
function route (path, view) {
  return {
    path: path,
    meta: meta[path],
    component: () => import(`../components/${view}`)
  }
}

Vue.use(Router)

export function createRouter () {
  const router = new Router({
    mode: 'history',
    scrollBehavior: () => ({ y: 0 }),
    routes: [
      route('/login', 'Login')
      route('/private', 'Private'),
      { path: '*', redirect: '/' }
    ]
  })

  router.beforeEach((to, from, next) => {
    if (to.meta.requiresAuth) {
      if (!store.state.auth.user) {
        next('/login')
      } else {
        next()
      }
    } else {
      next()
    }
  })

  return router
}

router/meta.json

{
  "/private": {
    "requiresAuth": true
  }
}

Expected behavior

Get the store.state.auth.user value inside router.beforeEach to redirect even after reloading a protected page.

Actual behavior

Everything works fine except when I'm logged in and if I reload my protected page called /private then it gets redirected to login even though the user is logged in.

So it seems that store.state.auth.user is not available inside router.beforeEach when reloading page

React Native not working if remove data

Hi. I have a problem in Service Actions. When doing remove items, it does not seem to commit ('removeItem', id) . No changes to getters in different browsers
reactive

Thank you

[Proposal] Allow existing store modules to provide additional properties like the customActions, etc.

Current state

Currently, if the namespace for a service resolves to the namespace of an existing store module that is not a service module, the existing module is overwritten without consideration of its setup. This behavior may be confusing for some users and probably hurts adoption, as it makes it difficult to go from a working store with its own custom service interactions to a working store that uses feathers-vuex, since they are silently incompatible.

Proposal

I'd like to propose adding a flag to the vuexOptions object (perhaps respectExisting) that would instruct new service-modules to take on the state/getters/actions/mutations of any modules with the same resolved namespace that exist in the store.

I've made a POC: jskrzypek/feathers-vuex@feat-array-namespaces...feat-respect-existing (this is based on my PR #35)

Alternatives

The other possible fix I can think of would be to automatically nest the service module on the existing module, though this can result in unpredictable namespaces.

What do you think?

[1.0] initAuth not exported (or readme is wrong?)

The readme tells us to import the initAuth function like this:

import feathersVuex, { initAuth } from 'feathers-vuex';

but apparently initAuth is never exported inside index.js.

Importing it like this works though:

import feathersVuex from 'feathers-vuex';
import { initAuth } from 'feathers-vuex/lib/utils';

Either the readme should be updated to reflect that, or initAuth should also be exported from the index.js

auth-module do not register custom getters

Steps to reproduce

Create a new Vuex store, registering the auth-module with a custom getter.
Call the custom getter.

const customGetters = {
  oneTwoThree (state) {
    return 123
  }
}
const store = new Vuex.Store({
  plugins: [
    auth({ getters: customGetters })
  ]
})

assert(store.getters['auth/oneTwoThree'] === 123, 'the custom getter was available')

(First please check that this issue is not already solved as described
here
)

  • Tell us what broke. The more detailed the better.
  • If you can, please create a simple example that reproduces the issue and link to a gist, jsbin, repo, etc.

Expected behavior

The getter returns the correct value from the store

Actual behavior

The getter is not registered

System configuration

Tell us about the applicable parts of your setup.

Module versions (especially the part that's not working):

NodeJS version:

Operating System:

Browser Version:

React Native Version:

Module Loader:

[discussion] using feathers-vuex as a client-side incremental cache

One of the wonderful things about feathers-vuex is that it loads back-end data, keeps them in browser's memory (vuex states), and updates them via socketio when needed. This makes it a handy tool to do client-side cache so that we don't need to waste band-width to request the same data again and again.

Here I want to discuss what we should do to make it easier to turn feathers-vuex into an out-of-box client-side incremental cache.

Previously I use raw client-side feathers services to cache data, and use feathers-reactive and vue-rx to let vue components be able to subscribe these data from the client-side feathers services. This approach requires considerable knowledge of rxJS, and not all team members feel comfortable with it.

Another possibility is to use the newly developed feathers-offline-realtime and feathers-offline-publications. Pros: they provide out-of-box data-replica and syncing between client and server, and furthermore, allow easy configuration and optimization of event filtering on the the server side. Cons: 1) they are designed to sync the whole back-end service data or a subset of the data with a given query, so they do not support incremental cache (i.e. querying and caching some records at first, and then run new find\get methods to add more records into the cache later); 2) Still need to write some rxJS code to glue feathers data and vue components.

I have discussed similar topic with @eddyystop on the feathers-offline-realtime project (feathersjs-ecosystem/feathers-authentication-management#8 (comment)). Later I realized the realtime strategy, by its nature, is for replication of a given service over a given query, not for incremental caching.

I think feathers-vuex is currently the best way to fulfill a full-functional client-side incremental cache for applications using feathers and vue. It naturally allows incrementally adding new records into the store, and since it uses vuex, no need for rxJS subscriptions.

Based on what we already have, I propose several new APIs for the service module, which can make the caching process easier:

  1. a new option in the params object for the get action, which makes the get firstly look for the given id in the vuex state (similar to the get gettter). If the item exists, bypass the remote request and just return the item in the vuex state with a resolved promise; if not, request the item from remote server normally, cache it in the vuex store, and return it (similar to the original get action).

  2. a new option in the params object for the update and patch actions, which enables optimistic mutation, i.e., mutating the data in the vuex state first, letting the back-end do the same mutation, and in case of back-end error, restoring the old data to the vuex state. Currently we can write some code to use the copy object to do this job, but it would be nice to include this in the offical API.

  3. (not necessary) some volume-control strategies to prevent the unlimited growing of the cache in the vuex store. It would be wonderful to provide some API to let user determine the maximum size of the keyedById object of a certain service module, and use LRU or random strategy to expire some old records in the module when it grows too big. Or we can have an expiration time for all the records in the service module.

What do you guys think of it?

Mapped Action is not a function

Steps to reproduce

Hi there, thanks for creating this fantastic plugin. I went through the feathers-vuex-chat app and documentation. When I tried to use feathers-vuex in my own app with a REST client I can't seem to resolve one error.

When I try to register a user with the same syntax used in the example, I get an error that this.createUser is not a function:

image

Here is the script tag of my Register.vue component where the error occurs:

<script>
import { mapActions } from 'vuex'
export default {
  data () {
    return {
      email: undefined,
      password: undefined
    }
  },
  methods: {
    register (email, password) {
      console.log(email, password)
      this.createUser({ email, password })
    },
  },
  ...mapActions('users', {
    createUser: 'create'
  })
}
</script>

This is my vuex store index.js:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {}
})

And this is my feathers-client.js that handles the registration of the feathers client and the plugin:

import 'babel-polyfill'
import feathers from 'feathers/client'
import hooks from 'feathers-hooks'
import auth from 'feathers-authentication-client'
import restClient from 'feathers-rest/client'
import feathersVuex from 'feathers-vuex'
import axios from 'axios'
import store from '@/store/'

const feathersClient = feathers()
  .configure(hooks())
  .configure(restClient('http://localhost:3030').axios(axios))
  .configure(auth({ storage: window.localStorage }))
  .configure(feathersVuex(store, {
    idField: '_id',
    auth: {
      userService: '/users',
    }
  }))
feathersClient.service('/users')

export default feathersClient

I have used the vue cli with a vuetify template to create the basic application:

vue init vuetifyjs/webpack-advanced

These are my dependencies in the package.json file:

"dependencies": {
    "axios": "^0.16.2",
    "babel-polyfill": "^6.23.0",
    "feathers": "^2.1.4",
    "feathers-authentication-client": "^0.3.2",
    "feathers-hooks": "^2.0.1",
    "feathers-rest": "^1.8.0",
    "feathers-vuex": "^0.7.0",
    "vue": "^2.3.4",
    "vue-router": "^2.3.1",
    "vuetify": "^0.13.0",
    "vuex": "^2.3.1"
  },
  "devDependencies": {
    "autoprefixer": "^6.7.2",
    "babel-core": "^6.22.1",
    "babel-eslint": "^7.1.1",
    "babel-loader": "^6.2.10",
    "babel-plugin-istanbul": "^4.1.1",
    "babel-plugin-transform-object-rest-spread": "^6.23.0",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-es2017": "^6.24.1",
    "babel-preset-stage-2": "^6.22.0",
    "babel-register": "^6.22.0",
    "chai": "^3.5.0",
    "chalk": "^1.1.3",
    "connect-history-api-fallback": "^1.3.0",
    "copy-webpack-plugin": "^4.0.1",
    "cross-env": "^4.0.0",
    "css-loader": "^0.28.0",
    "eslint": "^3.19.0",
    "eslint-config-airbnb-base": "^11.1.3",
    "eslint-config-standard": "^10.2.1",
    "eslint-friendly-formatter": "^2.0.7",
    "eslint-import-resolver-webpack": "^0.8.1",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-html": "^2.0.0",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^5.1.1",
    "eslint-plugin-promise": "^3.5.0",
    "eslint-plugin-standard": "^3.0.1",
    "eventsource-polyfill": "^0.9.6",
    "express": "^4.14.1",
    "extract-text-webpack-plugin": "^2.0.0",
    "file-loader": "^0.11.1",
    "friendly-errors-webpack-plugin": "^1.1.3",
    "html-webpack-plugin": "^2.28.0",
    "http-proxy-middleware": "^0.17.3",
    "inject-loader": "^3.0.0",
    "karma": "^1.4.1",
    "karma-coverage": "^1.1.1",
    "karma-mocha": "^1.3.0",
    "karma-phantomjs-launcher": "^1.0.2",
    "karma-phantomjs-shim": "^1.4.0",
    "karma-sinon-chai": "^1.3.1",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-spec-reporter": "0.0.30",
    "karma-webpack": "^2.0.2",
    "lolex": "^1.5.2",
    "mocha": "^3.2.0",
    "opn": "^4.0.2",
    "optimize-css-assets-webpack-plugin": "^1.3.0",
    "ora": "^1.2.0",
    "phantomjs-prebuilt": "^2.1.14",
    "rimraf": "^2.6.0",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "sinon": "^2.1.0",
    "sinon-chai": "^2.8.0",
    "stylus": "^0.54.5",
    "stylus-loader": "^3.0.1",
    "url-loader": "^0.5.8",
    "vue-loader": "^11.3.4",
    "vue-style-loader": "^2.0.5",
    "vue-template-compiler": "^2.3.4",
    "webpack": "^2.3.3",
    "webpack-bundle-analyzer": "^2.2.1",
    "webpack-dev-middleware": "^1.10.0",
    "webpack-hot-middleware": "^2.18.0",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 4.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

And finally, this is my .babelrc setup:

{
  "presets": [
    ["env", { "modules": false }],
    "stage-2"
  ],
  "plugins": ["transform-runtime"],
  "comments": false,
  "env": {
    "test": {
      "plugins": [ "istanbul" ]
    }
  }
}

It would be fantastic, if someone knows how to resolve this error! Thanks!

Weird / destructive behaviour using mapActions service find between components

I'm having a weird behaviour using find, this is how I'm using it:

I'm using feather-vuex 0.4.2, I also tried 0.3.1 and I get the same result.

First component

On the first component I do a find without a query, it returns all the results and store them on vuex.

methods: {
	...mapActions('profiles', { findProfiles: 'find' }),

	fetch() {
		this.findProfiles({})
	},
},

created() {
	this.fetch()
},

Screenshot of Vuex state after find:
screen shot 2017-06-09 at 10 40 13

Second component

Now I do a get and after it the results fetched with the find are still in the store. Everything is fine here.

methods: {
	...mapActions('profiles', { getProfile: 'get' }),

	fetch() {
		this.getProfile(this.user.profile)
	},
},

created() {
	this.fetch()
},

screen shot 2017-06-09 at 11 06 24

Third component

Now I do other find but with a custom query, I just want to find an element, the query works fine but it destroy the results of the first find :(

methods: {
	...mapActions('profiles', { findProfile: 'find' }),

	fetch() {
		this.findProfile({
			query: { slug: this.$route.params.slug },
		})
	},
},

created() {
	this.fetch()
},

screen shot 2017-06-09 at 11 10 29

Is this a bug or the expected behaviour? I'm missing something?

Auth module reactivity is inconsistent

I've created a simple app with nuxt and feathers to test feathers-vuex and see what I could do with it. I created a git repository here https://github.com/marsimeau/feathers-nuxt-new. I've played with authentication and ran into a problem.

When I dispatch the authenticate action for the first time (after a browser refresh) my component won't re-render with the updated payload. In the following example, I still see "No user connected" even though I can see the store has been updated:

<template v-if="payload">
  Current user : {{ payload.userId }} <button type="button" @click="logout">Logout</button>
</template>
<template v-else>
  No user connected
</template>

If I refresh the page, everything works as it should. I can logout and log back in without facing the issue. The moment I refresh the page while being logged out, the issue comes back.

If feathers-vuex were to be the culprit, I think the problem would be related to the auth store's default values:

// feathers-vuex/src/auth-module/state.js
const state = {
  accessToken: undefined, // The JWT
  payload: undefined, // The JWT payload
// ...

In my experience with Vue.js and Vuex, in order to be reactive a property needs to be defined. It would explain my issue. Another solution would be to use Vue.set(state, 'payload', payload) instead of state.payload = payload in mutations (https://vuex.vuejs.org/en/mutations.html#mutations-follow-vues-reactivity-rules) here:

// feathers-vuex/src/auth-module/mutations.js
setPayload (state, payload) {
  state.payload = payload
},

Doing this would ensure reactivity for any of the state items. After a bit of testing I cannot find any other cause to this issue.

unnecessary console.log "no cookies found"

Steps to reproduce

Using "initAuth" with no cookie set.

Expected behavior

It shouldn't log to the console. It already returns undefined and works as expected, no need to flood the log.

Actual behavior

It logs to the console at this line.

items not being removed from the list - fix proposal

I noticed that when I have 2 browsers open and remove item in one browser, the other one doesn't react to the removal although it gets the notification when using -reactive extension. Same thing happens when re-querying the data and having some deleted records in the meantime between refresh: the list only gets additions and removals are kept.

So I updated the action addOrUpdateList with the removal logic (see comments).
Could there be some side-effects of changing this I could not see?

  const actions = {
    addOrUpdateList ({ state, commit }, list) {
      let toAdd = []
      let toUpdate = []
      let toRemove = [] // Added

      // Find IDs from the state which are not in the list
      state.ids.forEach(id => {
        if (!list.some(c => c.id === id)) {
          toRemove.push(state.keyedById[id])
        }
      })

      list.forEach(item => {
        let id = item[idField]
        let existingItem = state.keyedById[id]

        checkId(id, item)

        existingItem ? toUpdate.push(item) : toAdd.push(item)
      })

      commit('removeItems', toRemove) // commit removal
      commit('addItems', toAdd)
      commit('updateItems', toUpdate)
    },

Update mutation not changing store or backend

Steps to reproduce

I want to populate a name field for one record of the user model that has already been created. The Vue component for this process:

<script>
import { mapActions, mapGetters } from 'vuex'
export default {
  data () {
    return {
      firstName: undefined,
      company: undefined
    }
  },
  computed: {
    currentUserId () {
      return this.getCurrentUser.id
    },
    currentCompanyId () {
      return this.getCurrentCompany.id
    },
    ...mapGetters('users', {
      getCurrentUser: 'current'
    }),
    ...mapGetters('companies', {
      getCurrentCompany: 'current'
    })
  },
  methods: {
    finish (firstName, company) {
      const userId = this.currentUserId
      const userData = {name: this.firstName}
      this.updateUser([userId, userData])
    },
    // Map the actions provided by feathers-vuex to easy functions
    ...mapActions('users', {
      updateUser: 'update'
    }),
    ...mapActions('auth', [
      'authenticate'
    ]),
    ...mapActions('companies', {
      createCompany: 'create'
    })
  }
}
</script>

Expected behavior

The action should update the vuex state and database entries in the feathers backend.

Actual behavior

The action triggers a mutation, as seen in the Vue Dev tools, but there is no value updated:
image
There is no change added in the backend either.

System configuration

feathers-vuex config

'use strict'

import 'babel-polyfill'
import feathers from 'feathers/client'
import hooks from 'feathers-hooks'
import auth from 'feathers-authentication-client'
import restClient from 'feathers-rest/client'
import feathersVuex from 'feathers-vuex'
import axios from 'axios'
import store from '@/store/'

const feathersClient = feathers()
  .configure(hooks())
  .configure(restClient('http://localhost:3030').axios(axios))
  .configure(auth({ storage: window.localStorage }))
  .configure(feathersVuex(store, {
    idField: 'id',
    auth: {
      userService: '/users',
    }
  }))

feathersClient.service('/users')
feathersClient.service('/companies')

export default feathersClient

package.json

{
  "name": "seads-app",
  "version": "1.0.0",
  "description": "The client for the seads app.",
  "author": "Johannes Herrmann <[email protected]>",
  "private": true,
  "scripts": {
    "dev": "node build/dev-server.js",
    "start": "node build/dev-server.js",
    "build": "node build/build.js",
    "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
    "test": "npm run unit",
    "lint": "eslint --ext .js,.vue src test/unit/specs"
  },
  "dependencies": {
    "axios": "^0.16.2",
    "babel-polyfill": "^6.23.0",
    "feathers": "^2.1.4",
    "feathers-authentication-client": "^0.3.2",
    "feathers-hooks": "^2.0.1",
    "feathers-reactive": "^0.4.1",
    "feathers-rest": "^1.8.0",
    "feathers-vuex": "^0.7.0",
    "rxjs": "^5.4.2",
    "vee-validate": "^2.0.0-rc.8",
    "vue": "^2.3.4",
    "vue-router": "^2.3.1",
    "vuetify": "^0.13.0",
    "vuex": "^2.3.1"
  },
  "devDependencies": {
    "autoprefixer": "^6.7.2",
    "babel-core": "^6.22.1",
    "babel-eslint": "^7.1.1",
    "babel-loader": "^6.2.10",
    "babel-plugin-istanbul": "^4.1.1",
    "babel-plugin-transform-object-rest-spread": "^6.23.0",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-es2017": "^6.24.1",
    "babel-preset-stage-2": "^6.22.0",
    "babel-register": "^6.22.0",
    "chai": "^3.5.0",
    "chalk": "^1.1.3",
    "connect-history-api-fallback": "^1.3.0",
    "copy-webpack-plugin": "^4.0.1",
    "cross-env": "^4.0.0",
    "css-loader": "^0.28.0",
    "eslint": "^3.19.0",
    "eslint-config-airbnb-base": "^11.1.3",
    "eslint-config-standard": "^10.2.1",
    "eslint-friendly-formatter": "^2.0.7",
    "eslint-import-resolver-webpack": "^0.8.1",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-html": "^2.0.0",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^5.1.1",
    "eslint-plugin-promise": "^3.5.0",
    "eslint-plugin-standard": "^3.0.1",
    "eventsource-polyfill": "^0.9.6",
    "express": "^4.14.1",
    "extract-text-webpack-plugin": "^2.0.0",
    "file-loader": "^0.11.1",
    "friendly-errors-webpack-plugin": "^1.1.3",
    "html-webpack-plugin": "^2.28.0",
    "http-proxy-middleware": "^0.17.3",
    "inject-loader": "^3.0.0",
    "karma": "^1.4.1",
    "karma-coverage": "^1.1.1",
    "karma-mocha": "^1.3.0",
    "karma-phantomjs-launcher": "^1.0.2",
    "karma-phantomjs-shim": "^1.4.0",
    "karma-sinon-chai": "^1.3.1",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-spec-reporter": "0.0.30",
    "karma-webpack": "^2.0.2",
    "lolex": "^1.5.2",
    "mocha": "^3.2.0",
    "opn": "^4.0.2",
    "optimize-css-assets-webpack-plugin": "^1.3.0",
    "ora": "^1.2.0",
    "phantomjs-prebuilt": "^2.1.14",
    "rimraf": "^2.6.0",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "sinon": "^2.1.0",
    "sinon-chai": "^2.8.0",
    "stylus": "^0.54.5",
    "stylus-loader": "^3.0.1",
    "url-loader": "^0.5.8",
    "vue-loader": "^11.3.4",
    "vue-style-loader": "^2.0.5",
    "vue-template-compiler": "^2.3.4",
    "webpack": "^2.3.3",
    "webpack-bundle-analyzer": "^2.2.1",
    "webpack-dev-middleware": "^1.10.0",
    "webpack-hot-middleware": "^2.18.0",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 4.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

removeItems action added after create when upgrading version from version 0.4.0 to 0.4.1

When creating an action with:
this.createMessage({'text': 'some message'})

I expect a new message to be added to the store.

This happens in version 0.4.0, but after upgrading to 0.4.1 there is an additional unwanted action added: messages/removeItems

This makes the state for the messages module 0, which is unexpected and undesirable behaviour.

How can I resolve this issue?

Module versions (especially the part that's not working): feathers-vuex 0.4.0 - 0.4.1
NodeJS version: v6.10.2
Operating System: Windows 8.1
Browser Version: Chrome Version 58.0.3029.110 (64-bit)
React Native Version: not applicable.
Module Loader: webpack

Creating multiple records using service.create(data) with an array yields: no id error

When dispatching create action on a service with an array of multiple objects as data:

var data = [
{name: 'index', permissions: 'guest'},
{name: 'about', permissions: 'guest'},
{name: 'admin', permissions: 'superuser'}
]
store.dispatch('/pages/create', data)

, the following error appears:

Error: No id found for item. Do you need to customize the `idField`?

The data is succesfully added to the database. The problem is when the promise is returned to the action and sent to the addOrUpdate action.

Upon analyzing the create action in src/service-module/actions.js, it seems that the error is produced by treating the response of the service.create(data) as a single object and passing that to addOrUpdate instead of addOrUpdateList:

create ({ commit, dispatch }, data) {
      commit('setCreatePending')

      return service.create(data)
        .then(item => {
          dispatch('addOrUpdate', item)
          commit('setCurrent', item)
          commit('unsetCreatePending')
          return item
        })
        .catch(error => {
          commit('setCreateError', error)
          commit('unsetCreatePending')
          return Promise.reject(error)
        })
}

getCopy

It would be useful to have a getCopy getter that fetched the deepCloned copy of the currentItem.

Currently this has to be done through using the state.copy

wait for find in combination with feathers-reactive

How can I wait for a find action in combination with feathers-reactive?

I have a nuxt application with server side rendering. If i am using feathers-vuex without feathers-reative, I get the expected behaviour, my asyncData function wait for the find and the data is in my store.

With feathers-reactive i have the problem that I dont know when the find finish, because the obseverable get subscribed in the find action (see here), which returns only a subscription, that i can only unsubscribe.

How I can handle this?
Maybe it's better to return the observable and the subscription from find, that i can handle this with another subscription?

My current solution is a bit hacky, I'm waiting 100-1000ms with setTimeout...

...
const PROJECTS_PER_PAGE = 12
const getPage = (page, store) => store.dispatch('projects/find', {
  qid: 'projects-page',
  query: {
    $limit: PROJECTS_PER_PAGE,
    $skip: ((page ? parseInt(page) : 1) - 1) * PROJECTS_PER_PAGE,
    $sort: {
      createdAt: -1
    }
  }
})
...
...
  async asyncData (ctx) {
    const { route, store } = ctx
    const { query } = route
    let page = parseInt(query.page)

    if (!page || page < 1) {
      page = 1
    }

    await getPage(page, store)

    return {
      page
    }
  }
...
// DIRTY APPROACH
  async asyncData (ctx) {
    const { route, store } = ctx
    const { query } = route
    let page = parseInt(query.page)

    if (!page || page < 1) {
      page = 1
    }

    return new Promise(async (resolve, reject) => {
      try {
        await getPage(page, store)
      } catch (err) {
        defaultExceptionHandler(err)
      }

      if (isServer) {
        setTimeout(() => resolve({
          page
        }), 1000)
      } else {
        resolve({
          page
        })
      }
    })
  }

Support compound idFields

I'm getting the same error as #61 , but I'm not sure if it's for the same reason?

I have a postgres database, using sequelize in the backend, and obviously feathers-vuex in the frontend :)

In other tables, I am using a single key (id) for PK, but in the table below I have a composite PK. Here is the SQL:
CONSTRAINT u_translations_pk PRIMARY KEY (project_id, key_id, project_language_id, version),

Adding a new value to the database is done in this method:

updateTranslation(keyId, langId, newValue){
      let data = {text: newValue}
      let params = {}

      this.findTranslation({
        query: {
          project_id: this.projectId,
          key_id: keyId,
          project_language_id: langId,
          version: 1
        }
      })
      .then(result => {
        if(result.total === 1){
          //this.patchTranslation([])
        }else if(result.total === 0){
          console.log('this.projectId: ', this.projectId)
          this.createTranslation({ project_id: this.projectId, key_id: keyId, project_language_id: langId, version: 1, text: newValue })
          .then(result => {
            console.log('success!')
            console.log('createTranslation result: ', result)
          })
        }
      })
    }

createTranslation():

...mapActions('u-translations', {
      findTranslation: 'find',
      createTranslation: 'create',
      patchTranslation: 'patch'
    }),

store:

service('u-translations', {
      idField: 'id' //What to set this to?
    }),

Just like #61, the data is added to the database , and the returned promise throws the same error.

However, it does not appear that my data is sent as an array, like in the above mentioned issue. The problem is probably because of the composite primary key. I have tried setting the idField in the store to different combinations, but the ones I have tried does not seem to help.

Any idea what might cause this, and how I can solve it?

Regards,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.