vue-form-generator
vue-form-generator copied to clipboard
concept issue: defining functions for field properties
Great stuff!
However there seems to be an issue with the concept of defining functions for fields properties and validators as standard JSON does not allow / support to generate JSON containing javascript functions like the following:
{
type: "select",
label: "Type",
model: "type",
values: [
{ id: "personal", name: "Personal" },
{ id: "business", name: "Business" }
]
},{
type: "text",
label: "Company name",
model: "company.name",
visible: function(model) {
return model && model.type == "business";
}
}
The workaround from #149 does not work in version 3.
Is there any know way to solve this??
What I did was create a schema parser, which was able to map strings to methods.
For example “bind:someMethod”, would change the value from the string “bind:someMethod” and switch it over to a reference to that function. I’ve posted an example of this a couple of times in other issues, a quick search should turn them up... unfortunately I don’t have the time to find them at the moment.
I also handled this in a similar fashion. Although a bit more work but very flexible.
I have a parser that finds any key with the _calc
extension and converts the value to an evaluated function and added as a getter. This way it works with all keys anywhere in the schema.
eg
visible_calc = "model.sAllowed"
// or
values_calc = "model.myArrayOfValues"
// or
styleClasses_calc = "model.isOverdue ? 'warning' : 'information' "
My technique replaces the raw key with the getter function
To clarify, I look for “bind:” prefix in the schema value and then lookup and attach to that, whether it be a property or a function.
ok, understand the concept but am struggling with the details (due to my lack of deeper knowledge...).
Tried to adopt the code I found in #601 but can't make it work.
I want to control the visibility of a field based on the selected value of another field.
I understand, the approach would be
{
"visible" : "bind:myToggleFunction"
}
and than parse the bind:myToggleFunction
using
`_.set(object, key, bindValue(param));``
Where / how would I define myToggleFunction
to make it work?
Could you provide a working example (could be best practice as part of the documentation)?
For a future version a totally different approach to control form properties could be similar to https://github.com/ncform/ncform#dx-expression
anyone?
Sorry for delay, must have missed this.
VFG schemes are dynamic, if you update the schema VFG will update as well.
You can listen for VFG change events, watchers on the model, etc, and then update the schema visibility property.
My approach with “bind” allows for the schema to be defined remotely and use code I exposed to the component controlling VFG... you can define “myToggleFunction” anywhere the schema parser that wires up the actual binding has access to.
In my case, I did something similar to VFG validation class and attach a number of utility functions there... then my schema parser just looks for matches there.
ok, not really understanding what am doing the following works for me to toggle the visibility of a field depending on the value of another field w/o using the function syntax (which would force me to generate invalid json)
in app.js
var self = this;
axios
.get(requestUrl)
.then(function (response) {
self.schema = response.data.data.schema;
// https://github.com/vue-generators/vue-form-generator/issues/601
// bind a field property to code
let functionValue = (code, self) => {
return () => {
let fn = new Function('self', code)
return fn(self);
};
};
// bind a field property to `path` (can be a function)
let bindValue = (path) => {
return () => {
return _.get(self, path);
};
};
// returns true if `path` exists, else false
let hasValue = (path) => {
return () => {
return _.has(self, path);
};
}
let recurse = (obj) => {
_.forIn(obj, (value, key, object) => {
if (_.isString(value) && value.includes(':')) {
let parts = value.split(':', 2);
let op = parts[0];
let param = null;
if (parts.length > 1) {
param = parts[1];
}
switch (op) {
case 'function':
_.set(object, key, functionValue(param, self));
break;
case 'bind':
_.set(object, key, bindValue(param));
break;
case 'has':
_.set(object, key, hasValue(param));
break;
case 'ValidateJs':
// ValidateJs is a custom validator object
_.set(object, key, ValidateJs[param]);
break;
}
}
// go deep
if (_.isArray(value) || _.isObject(value)) {
_.set(object, key, recurse(value));
}
});
return obj;
};
self.schema = recurse(self.schema);
})
and in my schema generated through laravel:
'visible' => 'function: return self.model.myValue == 3',
would be great to get your view on this!
thanks again
I’m not a big fan of evaluating a function like that... what I did was created the functions in my code, and just passed Paramus to them from the Json schema.
A quick look ... seems your code should work though. I haven’t touched VFG in a few months though, so don’t have a project handy to test on at the moment (switched jobs back in March).