• Stars
    star
    96
  • Rank 351,245 (Top 7 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 5 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

The coolest and easiest way to manage your user's preferences on the client side with your preferred storage. Check out sample app here:

Vue Preferences

The coolest and easiest way to manage your user's preferences on the client side with your preferred storage.

Motivation

Many times happens that you want to handle some persistent state on your application but you find that doing an actual call to your back-end is like "killing a mosquito with a bazooka". For those scenarios, we decided to create the vue-preferences library.

With vue-preferences, you can keep some state of your app on the client side by using any storage strategy you find suitable, as a default we use window.localStorage under the hood. This way you ensure your UX keeps consistent while at the same time avoiding simple but annoying calls to your back-end. You can set some user preferences such as theme color, users' default, hidden elements (after user opted-in), table sorting, and many others you can imagine with great simplicity.

Table of content

Installation

If you prefer yarn:

$ yarn add vue-preferences --save

or with npm:

$ npm install vue-preferences --save

Usage

You can define your vue-preferences in many ways. You can create them one by one, many at once and also with or without default values. Let's see what this means!

But first, remember to install the plugin before using it with:

import VuePreferences from 'vue-preferences';

Vue.use(VuePreferences);

new Vue({
  render: h => h(App),
}).$mount('#app');

This only needs to be done once, in the main.js or index.js file of your app, where you mount the Vue app for the first time.

Declaring vue-preferences

Single preference at a time

Here you'll see how to create a single preference at a time.

Basically, you would do something like:

  import { preference } from 'vue-preferences'

  computed: {
    isDarkMode: preference('isDarkModeEnabled', { defaultValue: false, reactive: false })
  }

keep in mind that there is no need to pass an options object if you don't need it

  computed: {
    isDarkMode: preference('isDarkModeEnabled')
  }

This will basically map your computed property isDarkMode to the value you have stored in localStorage under the key isDarkModeEnabled. Here you are explicitly mapping the localStorage key isDarkModeEnabled (that we will be creating for you) with your isDarkMode computed property.

Multiple preferences at the same time

We have two possible ways to create multiple vue-preferences properties at a time: the Array way or the Object way.

The Array way

Suppose you want to create two properties translatedTo and isZoomed. In the Array way, you could achieve that by doing:

  import { mapPreferences } from 'vue-preferences'

  computed: {
    ...mapPreferences(["translatedTo", "isZoomed"])
  }

Does it sound natural to you?

If it does, it's because it's just like vuex! 🎉

For those who don't know what I'm talking about, I will explain:

  ...mapPreferences(["translatedTo", "isZoomed"])

is great because you can declare as many preferences as you need with just one single line and internally this is just the same as doing:

  translatedTo: preference('translatedTo'),
  isZoomed: preference('isZoomed')

Does it make more sense now? - Cool!

Hang on, but... Is there a way to pass my custom options to each preference if I declare them as an array?

- I'm sorry, you can't. You can't provide custom options to each preference, but we have good news! We also added support to the Object way, remember we had mentioned this before. Let's see how to use it.

The Object way

By using the Object way you are allowed to create both multiple preferences and also provide custom options to each preference (such as defaultValue) at the same time.

Let's see how to do it:

  computed: {
    ...mapPreferences({
      translatedTo: {
        defaultValue: 'spanish'
      },
      isZoomed: {
        defaultValue: false
      }
    })
  }

Programmatic usage

This might look pretty familiar to you if you are used to window.localStorage API. But it has some advantages to it, for example, you create the property and you only need to know the name once, after that you can just pass the preference as a variable and use it with get/set.

Retrieve data

If at some point you need to know what is in your preference property, you just need to call the get method and you will have it.

// suppose you defined the following preference for saving the site's locale
const locale = preference('locale', { defaultValue: 'en' });

// obtains the value stored in the storage (by default localStorage) under the key "locale" or returns default: "en"
console.log('Current locale is:', locale.get());

// prints "Current locale is: en"

Keep in mind that if you defined your preference without a default value, and you haven't called the API to set any it, then the result of calling get will be null.

Store data

If you didn't define the preference as a computed property and instead did it as a regular variable, then it might happen that you want to handle it by your own.

If that's the case, you don't have other alternative than using the API to set the new values (in fact you have another alternative: to change the storage values with its API, but why would you do that? 🤭)

How to do it?

// suppose the same property than in the previous example
const locale = preference('locale', { defaultValue: 'en' });

locale.set('es');

// obtains the value stored in the storage (by default localStorage) under the key "locale" or returns default: "en"
console.log('Current locale is:', locale.get());

// prints "Current locale is: es"

This time the result is es, not en.

Options

This are the options available for the properties you define, any option you define on a preference has precedence over any global option you have defined or any provided default.

Option Default Value Description
storage window.localStorage Allows you to set up where the properties will be saved. By default we use localStorage, but you can use for example sessionStorage or any kind of storage. If you provide an object that has the same getItem and setItem API that localStorage has, then you can use that as a storage.
defaultValue null Allows you to set up the preference with a custom default value. This allows you to ensure that even the first time the preference is read you will get something.
reactive true By default preferences are reactive. This means that if you use the property in your template/code you can expect it to be observed and trigger re-renders, just like normal computed properties while at the same time the values get persisted to localStorage (or your storage of choice). If you disable this behavior the property will not trigger re-renders/re-computation of dependant code
serializer JSON.stringify The default serializer is JSON.stringify, this allows you to save all kinds of objects. You could for example use a CSV serializer.
deserializer JSON.parse The default deserializer is JSON.parse, and if it cannot deserialize a value it will return the value raw from the storage.
namespace '' The default namespace is empty, which means that the properties will get saved and read from the storage with the name of the preference. For example of the preference name is firstName, it will get stored as firstName, but if you add the namespace userData, it will get saved as userData:firstName
ttl infinite The Time-to-Live of a preference, the time in seconds after the preference creation/update at which a preference - if found on the storage - will be ignored and destroyed when tried to be read.
expiration infinite A Date or function (returning a Date) at which the preference will be considered expired. This behaves like the ttl option.

🚀 In the future, we will be supporting other custom options that will add even more power to the preferences you set. Stay tuned and support!

Global library options

Options can be defined globally and will affect all the preferences in your project unless overridden by individual preferences.

Example of global options usage:

import VuePreferences from 'vue-preferences';

Vue.use(VuePreferences, {
  storage: window.sessionStorage,
  namespace: 'my-app'
});

Notes

⚡ Please note that the API for defining multiple preferences at the same time is different from the one for creating a single preference (preference vs ...mapPreferences) ⚡

Contributing

All contributions or issue reporting are welcomed. If you are submitting a bug issue please include information to help us debug it!

If you plan to contribute, please make sure you test the code. Any new feature or bug fix should have its own test case.

Credits