Skip to content

Instantly share code, notes, and snippets.

@HelgeSverre
Last active July 30, 2020 17:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HelgeSverre/96c1beabcec47a21b4b93fa5555658ec to your computer and use it in GitHub Desktop.
Save HelgeSverre/96c1beabcec47a21b4b93fa5555658ec to your computer and use it in GitHub Desktop.
How to fix vue-moment locale issues and reactivity in Vue

Problem 1

If you are dynamically changing the locale of your vue application and setting the locale of moment js to that locale, your formatted dates will not be re-rendered, this is due to moments locale not being reactive (vue doesnt know that moment's internal state changed)

Solution

We need to create a custom renderless component that wraps the functionality we want, and whenever

<script>
export default {
  props: {
    value: {
      required: true,
      type: String
    },
    format: {
      required: true,
      type: String
    }
  },
  created() {
    this.$store.subscribe(mutation => {
      // If you use VUEX and you store the locale/language anywhere, listen to the mutation here and trigger forceUpdate
      if (mutation.type === "changeLanguage") {
        this.$forceUpdate();
      }
    });
  },
  render() {
    return this._v(this.$options.filters.moment(this.value, this.format));
  }
};
</script>

the _v() method is an internal vue thing that creates a text node, so you don't have to wrap your value in a div, span or anything like that.

Use it like this:

<Moment value="01-01-2020 12:00" format="from" />
<Moment value="01-01-2020 12:00" format="LLLL" />
<Moment value="01-01-2020 12:00" format="" />
<Moment :value="whateverDateYouHave" format="dddd DD. MMMM" />

Problem 2

No locales are included nor can be included (in any way i discoverd) when using vue-moment (https://www.npmjs.com/package/vue-moment).

Even if you import the locale files in your main.js file they will still not be "registered" with the moment instance you get from the Vue prototype.

Solution.

We have to get a bit dirty to work around this, basically copy this file and drop it into your project in a seperate file (moment.js or something): https://github.com/brockpetrie/vue-moment/blob/master/vue-moment.js

Then at the top of that newly created file import the locales you require:

import moment from "moment";

import "moment/locale/nb"; // Import whatever languages you need here
import "moment/locale/fr";


export default {
  install(Vue, options) {
    const moment = require("moment");

    Object.defineProperties(Vue.prototype, {
      $moment: {
        get() {
          return moment;
        }
      }
      
      // ... rest of the code ommitted for brevity

Then register that as a custom plugin in your main.js file like this:

import Vue from "vue";
import CustomMomentPlugin from "@/moment";
import App from "./App.vue";

Vue.use(CustomMomentPlugin);

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

Now your locales will be registered properly.

Vue.moment.locales(); // => ["nb", "fr", "en"]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment