Giter Site home page Giter Site logo

eldomagan / vuex-orm-localforage Goto Github PK

View Code? Open in Web Editor NEW
58.0 5.0 9.0 887 KB

Vuex ORM persistence plugin to sync the store against IndexedDB using localforage

License: MIT License

JavaScript 100.00%
vue vuex vuex-plugin vuex-orm vuex-orm-plugin indexeddb localforage

vuex-orm-localforage's Introduction

JavaScript Style Guide License

Vuex ORM Plugin: LocalForage

VuexORMLocalforage is a plugin for the amazing VuexORM that let you sync your Vuex Store with an IndexedDB database using LocalForage.

Installation

Add the package to your dependencies

yarn add vuex-orm-localforage

Or

npm install --save vuex-orm-localforage

Then you can setup the plugin

import VuexORM from '@vuex-orm/core'
import VuexORMLocalForage from 'vuex-orm-localforage'

const database = new VuexORM.Database()

VuexORM.use(VuexORMLocalForage, {
  database
})

// ...

export default () => new Vuex.Store({
  namespaced: true,
  plugins: [VuexORM.install(database)]
})

See https://vuex-orm.github.io/vuex-orm/guide/prologue/getting-started.html#create-modules on how to setup the database

Actions

This plugin add some vuex actions to load and persist data in an IndexedDB

Action Description
$fetch Load data from the IndexedDB store associated to a model and persist them in the Vuex Store
$get Load data by id from the IndexedDB store associated and persist it to Vuex Store
$create Like VuexORM insertOrUpdate, but also persist data to IndexedDB
$update Update records using VuexORM update or insertOrUpdate then persist changes to IndexedDB
$replace Like VuexORM create, but also replace all data from IndexedDB
$delete Like VuexORM delete, but also remove data from IndexedDB
$deleteAll Like VuexORM deleteAll, but also delete all data from IndexedDB

Example Usage

<template>
  <div>
    <input type="text" v-model="todo">
    <input type="button" @click="addTodo">

    <ul>
      <li v-for="todo in todos" :key="todo.id">{{ todo.title }}</li>
    </ul>
  </div>
</template>

<script>
  import Todo from './store/models/Todo'

  export default {
    data () {
      return {
        todo: ''
      }
    },

    computed: {
      todos () {
        return Todo.query().all()
      }
    },

    async mounted () {
      // Load todos from IndexedDB
      await Todo.$fetch()
    },

    methods: {
      addTodo () {
        if (this.todo) {
          // Insert the todo in VuexORM Store and also persist it to IndexedDB
          Todo.$create({
            title: this.todo
          })
        }
      }
    }
  }
</script>

Configuration Options

These are options you can pass when calling VuexORM.use()

{
  // The VuexORM Database instance
  database,

  /**
   * LocalForage config options
   *
   * @see https://github.com/localForage/localForage#configuration
   */
  localforage: {
    name: 'vuex', // Name is required
    ...
  },

  /**
   * You can override names of actions introduced by this plugin
   */
  actions: {
    $get: '$get',
    $fetch: '$fetch',
    $create: '$create',
    $update: '$update',
    $replace: '$replace',
    $delete: '$delete',
    $deleteAll: '$deleteAll'
  }
}

You can also override localforage config per model

class Post extends Model {
  static localforage = {
    driver: localforage.WEBSQL,
    storeName: 'my_posts'
  }
}

Using with other VuexORM Plugin

There may be a conflict when using this plugin along with other VuexORM plugins as they are following the same API (aka they introduced the same actions: $fetch, $create...)

Just override actions names like that

VuexORM.use(VuexORMLocalForage, {
  database,
  actions: {
    $get: '$getFromLocal',
    $fetch: '$fetchFromLocal',
    $create: '$createLocally',
    $update: '$updateLocally',
    $replace: '$replaceLocally',
    $delete: '$deleteFromLocal',
    $deleteAll: '$deleteAllFromLocal'
  }
})

Then

Post.$fetchFromLocal() // instead of Post.$fetch()
...

vuex-orm-localforage's People

Contributors

dependabot[bot] avatar eldomagan avatar nagamodle avatar sinanmtl avatar zerothe2nd 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

Watchers

 avatar  avatar  avatar  avatar  avatar

vuex-orm-localforage's Issues

[Storybook] Issue when storybook hot reloaded

Strange thing happening when I change and save store in story book. Not all data fetched from local store.
What I do:

  1. Fetch data from remote:
export const prepareDetailsPageData = async () => {
  await DetailsPageModel.fetchFromLocal()
  console.log('> prepareDetailsPageData:', DetailsPageModel.exists())
  if (!DetailsPageModel.exists()) {
    const detailsPageUrl = 'some_url'
    const data = await DetailsPageModel.api().fetch(detailsPageUrl)
    await DetailsPageModel.createLocally({ data })
  }
}

where data is the response and DetailsPageModel looks like

export default class DetailsPageModel extends Model {
  static entity = Models.PAGE_DETAILS
  static fields () {
    return {
      $type: this.string(null),
      content: this.hasOne(DetailsPageContentModel, 'to_parent', '$type'),
      menu: this.attr(null),
      list: this.hasMany(ContentDetailsListItemModel, 'to_parent', '$id'),
      creationDate: this.string(null),
      telemetry: this.attr(null),
    }
  }

  static apiConfig = {
    actions: {
      async fetch (url) {
        const result = await this.get(`${url}`, { save: true })
        return result.response
      }
    }
  }
}

It works and looks like data stored in localstorage
Screenshot 2020-04-07 at 20 43 03

And all registered correctly since data can be retrieved in a first run, store connected to storybook comonent:

export const detailsPage = () => ({
  components: { DetailsPage },
  template: `<details-page v-if="isReady"/>`,
  computed: {
    isReady: () => DetailsPageModel.exists(),
  },
  beforeUpdate: async () => {
    Navigator.init()
  },
  beforeCreate: async () => {
    await prepareDetailsPageData()
    console.log("> Storybook > DetailsPage : beforeCreate:", DetailsPageModel.query().first())
  },
  store
})

And when code in store updated, hot reloaded performed, then this:

await DetailsPageModel.fetchFromLocal()
console.log('> prepareDetailsPageData:', DetailsPageModel.exists())

show > prepareDetailsPageData: true
However the DetailsPageModel.query().first() does not return dependencies as it was before hot-reload
Screenshot 2020-04-07 at 20 56 24
All dependencies are null.

Any guesses how to fix it?

Unclear documentation

It's unclear from the readme what the database import should be. Does this need to be a localforage instance, localforage itself, or what is it exactly supposed to be?

Cannot convert undefined or null to object

Subject is a common error when you forget to wrap your payload in a data:{} object.

looks like you might need to fix the sample
Todo.$create({
title: this.todo
})
to read:
Todo.$create({
data:{title: this.todo }
})
yeah?

Extra Methods return indexed data array with missing model context

Hi,

The extra methods: prefixed with a $ sign, do work.
There is only one issue that bothers me.

When the extra methods resolve, and everything is as it should supposed to be, the result is a array of records without context.

The way vuex-orm returns the result is in an multidimentional assoc array with the key being the models entity name.
Vuex-orm method like: update returns multiple records, but grouped by there model entity name.

The methods (in this lib) like: $update return an flattend indexed array with records. There is no way to know what typeof record it is when looping though them.

For example: when you want to store a Contact with a or multiple relation(s) to a Address model.

Is there some special reason the outputs are different? Did nobody noticed this type of behavior?

In my humble opinion the outputs/resolved returns should be inline with each other. Mainly because this is only a plugin that adds an extra abbility and should not define or alter outputs.

congrats

Hi, first of all thank you for your excellent plugin! I'm using it and it works perfectly. I hope that you will continue to maintain this project.

how to include vuex-orm-localforage into vuex-orm-examples?

I am wondering how to include vuex-orm-localforage into the vuex-orm-examples demo app.

I tried to include the following code from the readme

import VuexORMLocalForage from 'vuex-orm-localforage'

const database = new VuexORM.Database()

VuexORM.use(VuexORMLocalForage, {
  database
})

into src/store/index.js so it now looks like:

import Vue from 'vue'
import Vuex from 'vuex'
import VuexORM from '@vuex-orm/core'
import VuexORMLocalForage from 'vuex-orm-localforage'
import database from '@/database'

Vue.use(Vuex)

VuexORM.use(VuexORMLocalForage, {
  database
})

const store = new Vuex.Store({
  namespaced: true,
  plugins: [VuexORM.install(database)]
})

export default store

But I am not able to enter any user name nor todo. Maybe this approach was to naiv, but how can it be accomplished?

Custom options cannot applying

I want to change db name but IndexedDB name is showing as 'vuex'. Always applying default options.

My options:

VuexORM.use(VuexORMLocalForage, {
  database: Database,
  localforage: {
    name: 'mydb'
  }
})

Typescript support

Hey there,

thanks for the great plugin. Is typescript support planned for the plugin? I have difficulties using the static methods on my model which are injected by the plugin.

51:25 Property '$create' does not exist on type 'typeof Clip'. Did you mean 'insert'?
   51 |               this.Clip.$create({
       |                         ^
    52 |                 data: {
    53 |                   meta: {
    54 |                     name: file.name,
Version: typescript 3.9.7

Is there a way I can define those methods on my model to satisfy my typechecker and they will be merged afterwards?

vuex-orm-localforage breaks with @vuex-orm/core 0.34.1

Hi there!

I tried to implement your awesome package into my vue.js project.
The current version of your package breaks with @vuex-orm/core 0.34.1, so that vuex orm still working but data is not inserted into IndexedDB.

The error message that is emitted as follows:

Model.js?0f48:12 Uncaught (in promise) TypeError: Right-hand side of 'instanceof' is not an object at Function.isFieldAttribute (Model.js?0f48:12) at eval (Model.js?0f48:22) at Array.filter (<anonymous>) at Function.getPersistableFields (Model.js?0f48:22) at eval (Persist.js?3fa2:32) at Array.map (<anonymous>) at eval (Persist.js?3fa2:29)

package.json

{ "private": true, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint" }, "devDependencies": { "@vue/cli-plugin-babel": "^3.12.1", "@vue/cli-plugin-eslint": "^3.12.1", "@vue/cli-service": "^3.12.1", "@vue/eslint-config-standard": "^4.0.0", "@vuex-orm/core": "^0.34.1", "normalize.css": "^8.0.1", "postcss-css-variables": "^0.13.0", "postcss-import": "^12.0.1", "postcss-nested": "^4.2.1", "vue": "^2.6.10", "vue-template-compiler": "^2.6.10", "vuex": "^3.1.2" }, "dependencies": { "vuex-orm": "^0.15.0", "vuex-orm-localforage": "^0.2.3" } }

I've tested it with your example project.

Could you please fix it?

Best,

Carl

sharing with the plugin plugin-axios

I want to use vuex-orm-localforage plugin with plugin-axios plugin

Plugin-axios plugin has methods of the same name with plugin vuex-orm-localforage

eg:

1. plugin-axios:

Model Methods

import User from '../models/User';

/**
 * @uri `/users`
 */
User.$fetch();

2. vuex-orm-localforage

import User from '../models/User';


/*
 Load data from the IndexedDB store associated to a model and persist them in the Vuex Store
 */
User.$fetch();

For plugin plugin-axios сhanging method name in methodConf does not work

Uncaught TypeError using $update

When updating data with the following:

Model.$update(
  { where : 1 },
  data : {
    field: 'value'}
  )

I'm receiving the following error:
Uncaught (in promise) TypeError: result[entity].forEach is not a function

The error is referring to the result[entity].forEach( ... ) on line 18 of src/actions/Persist.js, and when executing a $update, entity in result[entity] contains the string value $id. The contents of result are is the model in question.

Repeating this through the debugger with a Model.$create, the contents of entity is the string value operations, and result is an object with key operations holding an array of values that should be saved.

The value is not updated in the database, nor in vuex itself when using $update, while $create works without errors or issues.

$delete (or remapped $deleteFromLocal) cause "Uncaught (in promise) TypeError: Cannot read property '$id' of null"

I'm in situation when I want to refresh local storage and load config again everytime to check how some properties of the model generated in afterCreate. Doing this:

await ConfigModel.$fetchFromLocal()
if (ConfigModel.exists()) await ConfigModel.$deleteFromLocal()

cause the error:

Action.js?e7b0:23 Uncaught (in promise) TypeError: Cannot read property '$id' of null
    at Function.getRecordKey (Action.js?e7b0:23)
    at eval (Destroy.js?ce07:17)
    at Array.map (<anonymous>)
    at eval (Destroy.js?ce07:16)

How to configure LocalForage?

How to configure LocalForage?
I want use WebSQL, and set config like this:

{
    driver      : localforage.WEBSQL
    name        : 'someApp',
    version     : 0.1.52,
    size        : 1234567,
    storeName   : 'foo',
    description : 'bar'
}

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.