blitzar icon indicating copy to clipboard operation
blitzar copied to clipboard

Functions in JSON

Open Bruno17 opened this issue 2 years ago • 9 comments

I'm storing form schemas as JSON in a db and fetch that schemas dynamically via ajax, when needed. In the advanced section of your docs you use functions as values. Storing Functions in JSON that way is not possible.

Do you know a way, how I could store this functions as string and convert them to functions after fetching or do you have another workaround for that issue?

Bruno17 avatar Feb 16 '22 11:02 Bruno17

I've found this and modified it to my needs, which seems then to work so far. https://stackoverflow.com/a/68833334 Not sure, if there is a better way.

Bruno17 avatar Feb 16 '22 14:02 Bruno17

@Bruno17 yeah. this is a limitation of JSON which is better solved outside of Blitzar 😅

Could you add something on this to the documentation?

We could add it somewhere on the advanced page: https://blitzar.cycraft.co/advanced/

there are edit on github links at the bottom of the documentation now! 🎉

mesqueeb avatar Mar 06 '22 07:03 mesqueeb

I think Blitzar schema syntax should be a valid JSON (as such can be stored in database). For example:

  • JSONForms Rules (equivalent to Blitzar's dynamic props): https://jsonforms.io/docs/uischema/rules/
  • FormKit Validation (equivalent to Blitzar's validation): https://formkit.com/essentials/generation

layanto avatar Apr 05 '22 07:04 layanto

@layanto I hear you, but any "valid JSON" schema that tries to represent javascript functions will just be something that a library comes up with and then provides the logic to convert this JSON code from and to JavaScript.

Coming up with an entire set of possible validation rules in just plain text to then apply some sort of validation system on top of Blitzar is a lot of work and I would ideally just go with the most popular solution that already provides this, and integrate that into Blitzar.

This would require a lot of research into libraries, what they provide exactly, how flexible they are for integration into Blitzar, how popular they are, if they have security issues or not, etc.etc. I don't think I'll have the time to do this TBH. 😅 I have this concept of "dynamic props" already working, so ideally we use this for validation and complex logic.

If you want to build an admin panel where your users can create and save their own forms, and provide some pre-made validation logic that they can apply to those forms, I think it's really easy to just define those rules as JS functions client side, and save them by some sort of ID in your user's database and then just replace them when you get their schema from the database again.

Other than this, I'm not able to think of anything actionable atm.

I'd love to hear your thoughts!

mesqueeb avatar Apr 05 '22 08:04 mesqueeb

I do love the flexibility of dynamic props for validation and logic to hide/show or enable/disable form elements.

I still wish there is an easy way to store the schema as string in database and restore the schema from database.

layanto avatar Apr 05 '22 09:04 layanto

How about using this library for dynamic props? Functions in dynamic props are expressed as string (as such can be stored as json) and at run time evaluated via expr-eval library. This limits the flexibility of dynamic props to functions supported by expr-eval but maybe still powerful enough for most use cases?

https://github.com/silentmatt/expr-eval

layanto avatar Apr 05 '22 10:04 layanto

my solution looks like that: https://github.com/Bruno17/blitzar-quasar-proto/blob/main/src/pages/Index.vue#L66

then I can store functions as string like that: https://github.com/Bruno17/blitzar-quasar-proto/blob/main/public/controllers/form#L55

Bruno17 avatar Apr 05 '22 10:04 Bruno17

@mesqueeb How about this?

If a dynamic prop (i.e. listed in the dynamicProps) is NOT of type string, then do the current behaviour. Else execute the string dynamic prop as follows:

(new Function("return " + dynamicprop)())(val, context)

Since the dynamic prop 'function' is stored as string, this can be converted to JSON and stored in database.

I have tested the following as string and appeared to work:

"(val) => Number(val) >= 18 ? null : 'You have to be over 18!'"
"val => val === 'purple' ? 'nice!' : 'choose a color'"
"(val, { formData }) => !formData.under18"
"function(val, { formData }) { return val != formData.password }"
"(value) => `value: ${value}`"

layanto avatar Apr 06 '22 00:04 layanto

@layanto i'm open to the idea. Are you willing to make a PR?

mesqueeb avatar Aug 24 '22 06:08 mesqueeb