Skip to content

concept issue: defining functions for field properties #604

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

Open
cord opened this issue Mar 26, 2019 · 8 comments
Open

concept issue: defining functions for field properties #604

cord opened this issue Mar 26, 2019 · 8 comments

Comments

@cord
Copy link

cord commented Mar 26, 2019

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??

@zoul0813
Copy link
Member

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.

@DelfsEngineering
Copy link

DelfsEngineering commented Mar 26, 2019

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

@zoul0813
Copy link
Member

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.

@cord
Copy link
Author

cord commented Mar 27, 2019

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

@cord
Copy link
Author

cord commented May 28, 2019

anyone?

@zoul0813
Copy link
Member

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.

@cord
Copy link
Author

cord commented May 29, 2019

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

@zoul0813
Copy link
Member

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).

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

No branches or pull requests

3 participants