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

Exception when using a DateTime from Luxon.js as form value #3508

Closed
2 of 5 tasks
ropez opened this issue Sep 30, 2021 · 6 comments
Closed
2 of 5 tasks

Exception when using a DateTime from Luxon.js as form value #3508

ropez opened this issue Sep 30, 2021 · 6 comments
Labels
✨ enhancement a "nice to have" feature

Comments

@ropez
Copy link

ropez commented Sep 30, 2021

What happened?

We are using Luxon DateTime for our custom date picker component. Up until v4.1 this worked fine, but now it's causing an exception.

It turns out that the exception is caused by using the package klona to deep copy the data. We actually need this functionality, because we have nested data structures, which doesn't work well without this deep copy functionality. However, it fails for certain objects, which actually doesn't need to be copied, as they are immutable, and correspond to a single input field. There should be some mechanism to mark a field value as such, and avoid it being copied.

The issue is reported in the klona repository as well, with a suggestion to how it might be possible to opt out of copying certain immutable objects.
lukeed/klona#33

Reproduction steps

  1. Use a custom field component that uses DateTime as v-model value
  2. Call useForm with initialValues, or resetForm with values containing a DateTime object
  3. Exception is thrown

Version

Vue.js 3.x and vee-validate 4.x

What browsers are you seeing the problem on?

  • Firefox
  • Chrome
  • Safari
  • Microsoft Edge

Relevant log output

luxon.js?1315:6176 Uncaught TypeError: Cannot read properties of undefined (reading 'zone')
    at new DateTime (luxon.js?1315:6176)
    at klona (index.mjs?ba1d:8)
    at klona (index.mjs?ba1d:25)
    at eval (main.ts?cd49:30)

Demo link

Code of Conduct

@ropez
Copy link
Author

ropez commented Sep 30, 2021

We're looking into using the following patch for now (patching vee-validate, but code originating from klona):

diff --git a/node_modules/vee-validate/dist/vee-validate.esm.js b/node_modules/vee-validate/dist/vee-validate.esm.js
index 0faa908..ff86035 100644
--- a/node_modules/vee-validate/dist/vee-validate.esm.js
+++ b/node_modules/vee-validate/dist/vee-validate.esm.js
@@ -680,6 +680,9 @@ function klona(x) {
 
 	if (str === '[object Object]') {
 		if (x.constructor !== Object && typeof x.constructor === 'function') {
+            if (x.constructor.name === 'DateTime') {
+                return x;
+            }
 			tmp = new x.constructor();
 			for (k in x) {
 				if (tmp.hasOwnProperty(k) && tmp[k] !== x[k]) {

@logaretm
Copy link
Owner

logaretm commented Sep 30, 2021

I can switch to klona/full if thats going to solve it without too much increase in bundle size. But please provide a minimal reproduction so I can verify this.

@logaretm logaretm added 🤔 needs reproduction This issue requires a demo ✨ enhancement a "nice to have" feature labels Sep 30, 2021
@ropez
Copy link
Author

ropez commented Sep 30, 2021

This is more or less what we have. In the example, the DateField component is just a dummy, but it crashes before rendering it, so I just had to create something that should at least display the date as string, if it works:

https://codesandbox.io/s/vee-validate-luxon-u84t8

@lukeed
Copy link

lukeed commented Sep 30, 2021

Here is a minimal reproduction, which @ropez included in the linked klona issue. Can confirm that klona/full is the only mode that accommodates the luxon class.

const { klona } = require('klona/full');
const { DateTime } = require('luxon');

const input = {
  date: DateTime.fromISO('2021-10-01')
}

let output = klona(input);
console.log({ output });

This mode is 500b, so while it is (percentage wise) significantly larger than klona/lite, it's still faster and smaller than an equally capable alternative like lodash.

If vee-validate is meant to directly handle any model data, then klona/full is probably the best choice since it is able to handle a much wider range of data types.

@logaretm logaretm removed the 🤔 needs reproduction This issue requires a demo label Sep 30, 2021
@logaretm
Copy link
Owner

logaretm commented Sep 30, 2021

@ropez Thank you for the reproduction, the fix will be published later today.

@lukeed Thanks! I agree that vee-validate should handle any model data and even with klona/full the target gzip size is very reasonable (~120bytes diff), thanks for klona!

@ropez
Copy link
Author

ropez commented Oct 4, 2021

Thanks for addressing this issue.

However, TBH, we're probably still going to patch it. When we have a DateTime instance in our system, we want to be sure that it was created by the DateTime constructor (which btw is private, and only accessible through factory methods), not a "fake" one generated by copying attributes. It might work now, but there's no guarantee that it will work with future versions.

I can think of all kinds of scenarios were it would break. This is just a silly example:

const NULL_OBJECT = Object.freeze({});

class Thing {
  constructor(object) {
    this._object = object ?? NULL_OBJECT;
  }

  isNull() {
    return this._object === NULL_OBJECT;
  }
}

const data = { thing: new Thing() };
const copy = klona(data);

console.log(data.thing.isNull()); // true
console.log(copy.thing.isNull()); // false

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ enhancement a "nice to have" feature
Projects
None yet
Development

No branches or pull requests

3 participants