0

I'm working a form widget where the form is generated by schema that's retrieved from my api. The form library I'm using has built-in validators (vue-form-generator) that are referenced directly via the library. For example:

"schema": {
  "fields": [{
    "type": "input",
    "inputType": "email",
    "label": "E-mail",
    "model": "email",
    "placeholder": "Email",
    "validator": "VueFormGenerator.validators.email",
    "required": true
  },{
    "type": "submit"
  }]
}

And here's my code:

<template>
  <div id="app" v-if="loaded">
    <vue-form-generator :schema="schema" :model="model" :options="formOptions"></vue-form-generator>
  </div>
</template>

<script>
  /* eslint no-eval: 0 */

  import Vue from 'vue'
  import VueFormGenerator from 'vue-form-generator/dist/vfg-core.js'
  import 'vue-form-generator/dist/vfg-core.css'

  Vue.use(VueFormGenerator)

  export default {
    name: 'app',

    data: function () {
      return {
        loaded: false,
        model: null,
        schema: null,
        formOptions: null
      }
    },

    created: function () {
      return fetch('http://localhost:3000/forms')
        .then((response) => response.json())
        .then((json) => {
          // evaluate the validator
          json.schema.fields.map((field) => {
            if (field.validator) {
              field.validator = eval(field.validator)
            }
            return field
          })

          // assign the schema and model
          this.model = json.model
          this.schema = json.schema
          this.formOptions = json.formOptions

          // indicate that the schema has bee loaded
          this.loaded = true
        })
        .catch((ex) => {
          console.log('parsing failed', ex)
        })
    }
  }
</script>

My thought was that I could use eval() to evaluate the name of the validator and have it translate to a real function. However, I get the following error:

parsing failed ReferenceError: VueFormGenerator is not defined
    at eval (eval at <anonymous> (eval at <anonymous> (http://localhost:8080/app.js:797:1)), <anonymous>:1:1)
    at eval (eval at <anonymous> (http://localhost:8080/app.js:797:1), <anonymous>:35:29)
    at Array.map (native)
    at eval (eval at <anonymous> (http://localhost:8080/app.js:797:1), <anonymous>:33:26)
    at <anonymous>

Is there a way to do this or is it a better option to create a translation locally to map validator names to actual functions?

Thanks!

4
  • eval is going to return undefined so assigning it to something wouldn't do anything anyway. It's throwing an error because it's evaluating the string VueFormGenerator.validators.email and there's nothing called VueFormGenerator in scope. I don't know how to do what you want but that's what's going wrong. Commented May 30, 2017 at 21:29
  • Hmm...what scope is it actually referencing when called? Commented May 30, 2017 at 21:46
  • Oh I somehow missed the import statement! Never mind, seems like it should have been closed over. Commented May 30, 2017 at 22:26
  • You could try a couple things, like checking (logging) the value of VueFormGenerator.validators.email after the Vue.use line. If that works, check the value of eval('...') at the same place. If any of them does not work, it will not work in a more complicated context (like export-import) either. If they work, you could try the ugly workaround of importing directly in your 'created' function. Other, unrelated thoughts: what happens if you re-export VueFormGenerator yourself? Commented May 30, 2017 at 22:46

1 Answer 1

1

You could try using reduce:

      json.schema.fields.map((field) => {
        if (field.validator) {
          // get every key after VueFormGenerator
          const keys = field.validator.split('.').slice(1)
          // use reduce to get back the deepest prop
          field.validator = keys.reduce((obj, key) => obj[key], VueFormGenerator)
        }
        return field
      })
Sign up to request clarification or add additional context in comments.

1 Comment

Great solution! You ultimately pointed me in a much simpler direction, which I can't believe I didn't think of earlier. Instead of referencing the full validator name in the schema, I just use the type (email, string, etc) and then call VueFormGenerator.validators[type]. Duh! Regardless, a good exercise in trying to better understand eval better. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.