Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatibility with Vue 3 #166

Closed
maxmaccari opened this issue Sep 19, 2020 · 37 comments
Closed

Compatibility with Vue 3 #166

maxmaccari opened this issue Sep 19, 2020 · 37 comments
Assignees
Labels
feature New feature or request
Milestone

Comments

@maxmaccari
Copy link

Yesterday the final version Vue 3 was launched. But vue-currency-input is not compatible.

So I had to write some code in one personal project that redefines the plugin, component, and directive to be allowed to be used with Vue 3.

Plugin

In the old version, the $ci is defined in Vue.prototype.$ci. The new version we should define this in instance.config.globalProperties.$ci to inject the $ci variables in the instance and make this available globally. And use the redefined directive and component too.

The new plugin was defined in this way:

import {parse, getValue, setValue} from 'vue-currency-input'
import component from './component'
import directive from './directive'

export default {
  install(instance, globalOptions) {
    instance.directive('currency', directive)
    instance.component('currency-input', component)

    instance.config.globalProperties.$ci = {
      parse,
      getValue,
      setValue,
      globalOptions,
    }
  },
}

Directive

In the old version, the directive hooks are bind and componentUpdated. In the new version, the directive hooks were renamed to beforeMount and updated. So we can only rename these hooks and everything will work properly, or just wrap the old directive functions in the new directive like this:

import { CurrencyDirective } from 'vue-currency-input'

export default {
  beforeMount () {
    CurrencyDirective.bind(...arguments)
  },

  updated () {
    CurrencyDirective.componentUpdated(...arguments)
  }
}

Component

The component requires most of the changes.

In the old version, the h function is injected in the render function as the first param. In the new version, we should import the h function from the vue package, using import { h } from 'vue'. The way that the events are defined is different too. And we don't have the directive property anymore.

return h('input', {
  onChange: () => {
    this.$emit('change', getValue(this.$el))
  },
  onInput: () => {
    const numberValue = getValue(this.$el)
      if (this.modelValue !== numberValue) {
        this.$emit('update:modelValue', numberValue)
      }
  }
})

We doesn't have the directives property, so we have to initialize the NumberInput in the mounted hook, like:

this.$el.$ci = new NumberInput(this.$el, this.options, {
  onChange: () => {},
  onInput: () => {}
})

And as the props and events for v-model was changed. We should use the modelValue instead value, and emit 'update:modelValue' instead 'input'.

The final version of the file is this:

import {
  getValue, setValue, CurrencyInput
} from 'vue-currency-input'
import { NumberInput } from 'vue-currency-input/src/numberInput'
import { h } from 'vue'
import directive from './directive'

export default {
  extends: CurrencyInput,
  render() {
    return h('input', {
      onChange: () => {
        this.$emit('change', getValue(this.$el))
      },
      onInput: () => {
        const numberValue = getValue(this.$el)
          if (this.modelValue !== numberValue) {
            this.$emit('update:modelValue', numberValue)
          }
      }
    })
  },
  directives: {
    currency: directive
  },
  props: {
    modelValue: {
      type: Number,
      default: null
    }
  },
  mounted() {
    this.$el.$ci = new NumberInput(this.$el, this.options, {
      onChange: () => {},
      onInput: () => {}
    })

    this.setValue(this.modelValue)
  },
  methods: {
    setValue(value) {
      if (!this?.$el?.$ci) return;

      setValue(this, value)
    }
  }
}

Final Words

I think making the project compatible with Vue 3 is important, but we have these breaking changes. It would be great if we could have the Vue 3 compatible version of this library.

I hope that what I showed here helps us to have the compatible version, or helps anyone who wants to use this library with Vue 3.

@dm4t2
Copy link
Owner

dm4t2 commented Sep 19, 2020

Hi @maxmaccari, thank you for summing up 👍

I have also followed the progress of Vue 3 with great interest and just want to let everyone know that I'm currently working on a compatible version. A beta version will be released shortly.

@dm4t2 dm4t2 self-assigned this Sep 19, 2020
@dm4t2 dm4t2 added the feature New feature or request label Sep 19, 2020
@dm4t2 dm4t2 pinned this issue Sep 23, 2020
@dm4t2
Copy link
Owner

dm4t2 commented Oct 10, 2020

I just published a pre-release 2.0.0-beta.0 compatible with Vue 3 🎉

Any feedback is appreciated.

@dm4t2 dm4t2 added this to the Release 2.0 milestone Dec 6, 2020
@dm4t2
Copy link
Owner

dm4t2 commented Dec 26, 2020

Another pre-release 2.0.0-beta.1 is available for testing.

@dm4t2
Copy link
Owner

dm4t2 commented Jan 2, 2021

Another pre-release 2.0.0-beta.2 is available for testing.

@Sun3
Copy link

Sun3 commented Jan 3, 2021

I noticed if the v-model has a value, when the page loads the currency-input does not show the value but shows blank value instead.

<currency-input
    v-model="state.amount" 
    :options="{ currency: 'USD', distractionFree: false, useGrouping: true, precision: { min: 0, max: 2 } }"
/>

@dm4t2
Copy link
Owner

dm4t2 commented Jan 3, 2021

@Sun3: I can not reproduce your issue.

This Vue 3 example works as expected: https://codesandbox.io/s/vue-currency-input-vue-3-example-5l51f

@Sun3
Copy link

Sun3 commented Jan 4, 2021

I think I know what might be happening. When you set the original value (in my case is 0) and once the data is received from the server, the currency control is not updated with the new value.

I added the mounted() to your sample code sandbox:

  data() {
    return {
      value: 1234,
    };
  },
  mounted() {
    this.value = 450000
  }

and the original value of value: 1234 is shown in the currency control but in the <p>{{ value }}</p> it shows the 450000.

I can try to create a sample project without using my server logic (Firestore in my case) to receive the data. I am also using Typescript with Composition API and reactive, but I do not think this is an issue.

@dm4t2
Copy link
Owner

dm4t2 commented Jan 4, 2021

@Sun3 Using setValue within a watcher might solve your issue: https://vue-currency-input-next.netlify.app/guide/#reacting-on-external-props-changes.

Please note that the return type of useCurrencyInput is currently outdated. I will fix this in the next release.

@Sun3
Copy link

Sun3 commented Jan 4, 2021

@dm4t2 Yep, I previously tried the watcher version, but same results. By the way I really do like you currency control.

@Sun3
Copy link

Sun3 commented Jan 4, 2021

@dm4t2 I was testing further and I noticed that the watch setValue is not being called in the CurrencyInput control. Not sure if I am doing something wrong.

watch(() => props.value, (value) => {
  setValue(value)
  console.log('setValue: ', value)
})

This is my CurrencyInput control code:

<template>
  <input
    ref="inputRef" 
    :value="formattedValue"
  >
</template>

<script>
import { watch } from 'vue'
import useCurrencyInput from 'vue-currency-input'

export default {
  name: 'CurrencyInput',
  props: {
    modelValue: Number,
    options: Object
  },
  setup (props) {
    const currencyOptions = { currency: 'USD', distractionFree: false, useGrouping: true, precision: { min: 0, max: 2 } }
    const { inputRef, formattedValue, setOptions, setValue } = useCurrencyInput(props.options)
    watch(() => props.options, (options) => {
      console.log('setOptions: ', options)
      setOptions(options)
    })
    watch(() => props.value, (value) => {
      setValue(value)
      console.log('setValue: ', value)
    })

    return { inputRef, formattedValue }
  }
}
</script>

The entry form uses the CurrencyInput control in this manner:

<CurrencyInput
  v-model.number="state.details.Hold.valueAmount"
  :options="{
    currency: 'USD',
    distractionFree: false,
    useGrouping: true,
    precision: { min: 0, max: 2 },
  }"
/>  

@dm4t2
Copy link
Owner

dm4t2 commented Jan 4, 2021

There's an error in docs for the Vue 3 example 🤔

Should be:

watch(() => props.modelValue, (value) => {
  setValue(value)
})

@Sun3
Copy link

Sun3 commented Jan 5, 2021

@dm4t2 Yep, that works perfectly.

Thank you so much, I really appreciate it.

@Sun3
Copy link

Sun3 commented Jan 12, 2021

Is there a way to hide the Currency Symbol with the Vue 3 2.0.0-beta.2? I some scenarios where I need to show the currency symbol and other cases it needs to format the numbers but without the symbol (on the same entry page).

Thanks.

@dm4t2
Copy link
Owner

dm4t2 commented Jan 13, 2021

Is there a way to hide the Currency Symbol with the Vue 3 2.0.0-beta.2? I some scenarios where I need to show the currency symbol and other cases it needs to format the numbers but without the symbol (on the same entry page).

@Sun3 No, see #177 (comment)

@dm4t2
Copy link
Owner

dm4t2 commented Jan 22, 2021

Another pre-release 2.0.0-beta.3 is available for testing.

@Sun3
Copy link

Sun3 commented Jan 25, 2021

I tested 2.0.0-beta.3 and so far working great.

@Luigidefra
Copy link

How can i initialize currency-input on vue3? Documentation is for vue2 version

@dm4t2
Copy link
Owner

dm4t2 commented Feb 16, 2021

@Luigidefra You can find the docs here: https://vue-currency-input-next.netlify.app

@Sun3
Copy link

Sun3 commented Mar 8, 2021

I am running into an issue with using npm install vue-currency-input@next (vue-currency-input@2.0.0-rc.1) when using the latest version of vue@3.0.7.

Error while resolving:

Found: vue@3.0.7
node_modules/vue
  vue@"^3.0.7" from the root project
  peer vue@"^2.6 || ^3.0.0" from vue-currency-input@2.0.0-rc.1
  node_modules/vue-currency-input
    vue-currency-input@"2.0.0-rc.1" from the root project

Could not resolve dependency:
peer vue@">= 2.5 < 3" from @vue/composition-api@1.0.0-rc.3
node_modules/@vue/composition-api
  peer @vue/composition-api@"^1.0.0-rc.1" from vue-currency-input@2.0.0-rc.1
  node_modules/vue-currency-input
    vue-currency-input@"2.0.0-rc.1" from the root project

Fix the upstream dependency conflict, or retry
this command with --force, or --legacy-peer-deps
to accept an incorrect (and potentially broken) dependency resolution.

By running
vue --version
@vue/cli 4.5.11

npm --version
7.6.0

Thank you.

@Sun3
Copy link

Sun3 commented Mar 8, 2021

ps: I just uninstalled the following from my computer and reinstalled and it looks like its working again. Does anyone else have this issue that happened to them buy running the latest version of vue '''npm install vue@next```

Uninstall Vue
npm uninstall -g @vue/cli

Uninstall npm
npm uninstall npm -g

Uninstall node
Windows Control Panel

Reinstalled
node.js
'''npm install vue@next npm install -g @vue/cli```

I will give an update if the issue happens again.

@ysinsane
Copy link

ysinsane commented Mar 18, 2021

I am running into an issue with using npm install vue-currency-input@next (vue-currency-input@2.0.0-rc.1) when using the latest version of vue@3.0.7.

Error while resolving:

Found: vue@3.0.7
node_modules/vue
  vue@"^3.0.7" from the root project
  peer vue@"^2.6 || ^3.0.0" from vue-currency-input@2.0.0-rc.1
  node_modules/vue-currency-input
    vue-currency-input@"2.0.0-rc.1" from the root project

Could not resolve dependency:
peer vue@">= 2.5 < 3" from @vue/composition-api@1.0.0-rc.3
node_modules/@vue/composition-api
  peer @vue/composition-api@"^1.0.0-rc.1" from vue-currency-input@2.0.0-rc.1
  node_modules/vue-currency-input
    vue-currency-input@"2.0.0-rc.1" from the root project

Fix the upstream dependency conflict, or retry
this command with --force, or --legacy-peer-deps
to accept an incorrect (and potentially broken) dependency resolution.

By running
vue --version
@vue/cli 4.5.11

npm --version
7.6.0

Thank you.

I have the same trouble too. It seems to be a peerDependency problem. It seems @vue/composition-api@"^1.0.0-rc.1" should not be peerDependency but dependency instead...
I use yarn, it overcome this problem by its powerful mechanism.

@Sun3
Copy link

Sun3 commented Mar 18, 2021

I am still having the same issue, I received a notice for the new npm update to version 7.6.3 and as soon as I updated I am receiving the same errors:

npm update
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: propertyfliporhold@1.8.0
npm ERR! Found: vue@3.0.7
npm ERR! node_modules/vue
npm ERR!   vue@"^3.0.7" from the root project
npm ERR!   peer vue@"^2.6 || ^3.0.0" from vue-currency-input@2.0.0-rc.1
npm ERR!   node_modules/vue-currency-input
npm ERR!     vue-currency-input@"^2.0.0-rc.1" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer vue@">= 2.5 < 3" from @vue/composition-api@1.0.0-rc.5
npm ERR! node_modules/@vue/composition-api
npm ERR!   peer @vue/composition-api@"^1.0.0-rc.1" from vue-currency-input@2.0.0-rc.1
npm ERR!   node_modules/vue-currency-input
npm ERR!     vue-currency-input@"^2.0.0-rc.1" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See C:\Users\marco\AppData\Local\npm-cache\eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR! 2021-03-18T20_35_11_119Z-debug.log

Any thoughts on how to solve this issue with npm?
Thanks.

@dm4t2
Copy link
Owner

dm4t2 commented Mar 18, 2021

@Sun3 @ysinsane npm 7 should work now in 2.0.0-rc.2 🎉

See also vueuse/vue-demi#37

@Sun3
Copy link

Sun3 commented Mar 18, 2021

Thank you, that worked great.

@itsChris
Copy link

itsChris commented Mar 20, 2021

Screenshot 2021-03-20 121505
Screenshot 2021-03-20 121525

Created an empty (well, helloworld) vue 3 project.

npm --version
6.14.11

vue --version
@vue/cli 4.5.12

vue create vue-currency-input-test
-> Default (Vue 3 Preview) ([Vue 3] babel, eslint)

-> compiled, runs -> hello world in browser using npn run serve

then:
npm install vue-currency-input@next

added: to main.js:

import { createApp } from 'vue'
import App from './App.vue'
**import VueCurrencyInput from 'vue-currency-input'**

**const pluginOptions = {
    /* see config reference */
    globalOptions: { currency: 'USD' }
}**

createApp(App)
    **.use(VueCurrencyInput, pluginOptions)**
    .mount('#app')

compiles, but in browser result in following javascript exception:

  | useCurrencyInput | @ | vue-currency-input.esm.js?d413:397
-- | -- | -- | --
  | use | @ | runtime-core.esm-bundler.js?5c40:2976
  | eval | @ | main.js?56d7:10
  | ./src/main.js | @ | app.js:1148
  | __webpack_require__ | @ | app.js:849
  | fn | @ | app.js:151
  | 1 | @ | app.js:1161
  | __webpack_require__ | @ | app.js:849
  | checkDeferredModules | @ | app.js:46
  | (anonymous) | @ | app.js:925
  | (anonymous) | @ | app.js:928

reproduced on another PC, same result.

@dm4t2
Copy link
Owner

dm4t2 commented Mar 20, 2021

@itsChris The plugin installation has been dropped in v2. See https://github.com/dm4t2/vue-currency-input/releases/tag/2.0.0-beta.0

@Sun3
Copy link

Sun3 commented Apr 2, 2021

I just upgraded to npm version 7.80 and I am receiving the following errors that were not there with the previous version of npm. I believe if a number is NaN it now causes the error. (it was not a problem before)

Error:

Uncaught (in promise) RangeError: minimumFractionDigits value is out of range.
    at Number.toLocaleString (<anonymous>)
    at NumberFormat.format (vue-currency-input.esm.js?d413:66)
    at NumberInput.applyFixedFractionFormat (vue-currency-input.esm.js?d413:235)
    at NumberInput.setValue (vue-currency-input.esm.js?d413:250)
    at eval (vue-currency-input.esm.js?d413:441)
    at callWithErrorHandling (runtime-core.esm-bundler.js?5c40:154)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?5c40:163)
    at Array.hook.__weh.hook.__weh (runtime-core.esm-bundler.js?5c40:1953)
    at flushPostFlushCbs (runtime-core.esm-bundler.js?5c40:355)
    at flushJobs (runtime-core.esm-bundler.js?5c40:391)

The file vue-currency-input.esm.js at line 66 is causing the error when a number is NaN
Error: Uncaught (in promise) RangeError: minimumFractionDigits value is out of range.
This line is causing the error: return number.toLocaleString(this.locale, {

  format (number, options = {
    minimumFractionDigits: this.minimumFractionDigits,
    maximumFractionDigits: this.maximumFractionDigits
  }) {
    if (number == null) {
      return ''
    } else {
      return number.toLocaleString(this.locale, {  // Error Here number = NaN
        style: 'currency',
        currency: this.currency,
        ...options
      })
    }
  }

Full Error from console:

vue-currency-input.esm.js?d413:66 Uncaught (in promise) RangeError: minimumFractionDigits value is out of range.
    at Number.toLocaleString (<anonymous>)
    at NumberFormat.format (vue-currency-input.esm.js?d413:66)
    at NumberInput.applyFixedFractionFormat (vue-currency-input.esm.js?d413:235)
    at NumberInput.setValue (vue-currency-input.esm.js?d413:250)
    at eval (vue-currency-input.esm.js?d413:441)
    at callWithErrorHandling (runtime-core.esm-bundler.js?5c40:154)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?5c40:163)
    at Array.hook.__weh.hook.__weh (runtime-core.esm-bundler.js?5c40:1953)
    at flushPostFlushCbs (runtime-core.esm-bundler.js?5c40:355)
    at flushJobs (runtime-core.esm-bundler.js?5c40:391)

Any thoughts?
Thank you.

@Sun3
Copy link

Sun3 commented Apr 2, 2021

ps: I created a new record to test that has number values of 0 and above and I am receiving the same error.

@dm4t2
Copy link
Owner

dm4t2 commented Apr 2, 2021

@Sun3 Do you use 2.0.0-rc.4 with a precision range? Please note the breaking change.

@Sun3
Copy link

Sun3 commented Apr 2, 2021

I am using 2.0.0-rc.2 but I just tested with 2.0.0-rc.4 with the same results. Not really sure what happened since it was all working last night, but today I received a notice to update my npm.

@Sun3
Copy link

Sun3 commented Apr 2, 2021

@dm4t2 Does this mean with the precision range removal, you now specify the number of decimals without the option of not showing it if the user does not type in a decimal? This is a huge feature for my project. If the user types in decimal we show it but if they don't we do not show it.

Example 1 User types in 14,000 and it shows as 14,000
Example 2 User types in 14,000.1 and it shows as 14,000.1

Would it still work the same as above?
Thank you.

ps: I am testing with 2.0.0-rc.4 and just removed the precision range and the error is gone.

@dm4t2
Copy link
Owner

dm4t2 commented Apr 2, 2021

Decimal digits will now be hidden for integer numbers by default, see #203.

@Sun3
Copy link

Sun3 commented Apr 2, 2021

That's great, thank you so much.

@dm4t2
Copy link
Owner

dm4t2 commented Apr 3, 2021

I will close this for now. Please open new issues if there are bugs or you have feedback regarding v2. Thanks!

@dm4t2 dm4t2 closed this as completed Apr 3, 2021
@dexcell
Copy link

dexcell commented Apr 26, 2021

Why cannot remove currency from input on vue3 version?

tried to pass currency: null as an option but component shows error.

@dm4t2
Copy link
Owner

dm4t2 commented Apr 27, 2021

@dexcell: There will be an option to hide the currency symbol in the next v2 release candidate, see #209.

@Sun3: Might be also interesting for you 😉

@dm4t2 dm4t2 unpinned this issue Jun 13, 2021
@Sun3
Copy link

Sun3 commented Oct 8, 2021

Decimal digits will now be hidden for integer numbers by default, see #203.

I am going to create a new ticket but I just wanted to note it here too.

I was trying to make it work, but it seems there is no way to have a user enter 125,000 or 125,000.44 and declare the precision. You either need to enter precision: 0 or precision: 2.

In my case I really need to make the { min: 0, max: 2 } work like it used to.

Is there any way to allow the user to enter a currency and only if the user types in the . (period), then use the precision?

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants