# Lookup Plugin

Whenever you find yourself working with a schema that has already been generated or created with a specific structure that does not comply to the requirements of SchemaForm, it becomes a necessary step to parse it to modify the structure.

In order to make this task easier, FormVueLate provides a core plugin called @formvuelate/plugin-lookup.

# Installation

To install the plugin, simply add it to your package.json via terminal.

yarn add @formvuelate/plugin-lookup

// OR

npm i @formvuelate/plugin-lookup

# Usage

To use the plugin, first import both the plugin itself, and the SchemaFormFactory to your application.

import { SchemaFormFactory } from 'formvuelate'
import LookupPlugin from '@formvuelate/plugin-lookup'

Now that we have both imported, we can create our plugin-enabled SchemaForm component by using the SchemaFormFactory

const SchemaFormWithPlugin = SchemaFormFactory([
  LookupPlugin({
    // plugin configuration here
  })
])

Now that we have created our new component, we can pass it to our instance's components object, and use it as we normally would in our template.

<template>
  <div id="app">
    <SchemaFormWithPlugin
      :schema="mySchema"
    />
  </div>
</template>

<script>
export default {
  components: {
    SchemaFormWithPlugin
  },
  setup () {
    [...]
  }
}
</script>

# Configuration

LookupPlugin takes one parameter, an object, as it's source of configuration. Let's look at the properties that we can use in this object.

# mapComponents

If your schema does not provide component names as your Vue application needs them, mapComponents is a property of the configuration object that can allow you to rename or remap these values with ease.

Consider the following example schema.

{
  "firstName": {
    "component": "string",
    "label": "First name"
  },
   "favoriteThingAboutVue": {
    "component": "array",
    "label": "Favorite thing about Vue",
    "required": true,
    "options": [
      "Ease of use",
      "Documentation",
      "Community"
    ]
  },
}

In this case, the component definition is not FormText, or FormSelect, or whichever other components we may be using in our application. So we need to map them.

Let's add this mapping into our configuration object.

LookupPlugin({
  mapComponents: {
    string: 'FormText',
    array: 'FormSelect'
  }
})

LookupPlugin will now look inside your schema and parse all the component definitions into their respective components. So string will become FormText and array will become a FormSelect component.

# mapProps

If your schema needs to parse additional props for your own component's needs, mapProps provides an easy way of parsing any property in your component's object definition to something else.

For example, in some cases the schema might define your component property with something else, let's use type in the following example:

{
  "firstName": {
    "type": "FormText",
    "info": "First name"
  }
}

We need to map type into component, since that is the property that SchemaForm expects to find for the component to render into the form. Read more about component requirements

const SchemaFormWithPlugin = SchemaFormFactory([
  LookupPlugin({
    mapProps: {
      type: 'component'
    }
  })
])

If we also needed to map info to label because our component is expecting a label property and our schema defines it as info, by using mapProps in our configuration we can ask the plugin to do both at the same time.

const SchemaFormWithPlugin = SchemaFormFactory([
  LookupPlugin({
    mapProps: {
      type: 'component',
      info: 'label'
    }
  })
])

Now our schema will correctly pass the label property into our FormText example component. The schema will also correctly reflect a component property with the value of FormText.

The mapProps property can also receive a function to handle advanced property parsing logic.

If a function is provided, the plugin will run the function before parsing each element to retrieve the mapping of properties. The function will inject the current element as the first parameter.

Consider the following schema and example.

{
  "firstName": {
    "type": "FormText",
    "label": "First name",
    "important": true
  },
  "lastName": {
    "field": "FormText",
    "label": "Last name",
    "important": true
  }
}

The first field declares a type property that holds the component that it should render.

The second field declares a field property that holds the component that it should render.

In this case, we need more per-field control in how the properties are mapped.

const SchemaFormWithPlugin = SchemaFormFactory([
  LookupPlugin({
    mapProps: (el) => {
      // This function will be called for each element in the schema
      // "el" is the current element being parsed

      // Map important to required only for the field with label 'First name'
      if (el.label === 'First name') {
        return {
          type: 'component',
          important: 'required'
        }
      }

      // For any other element
      return {
        field: 'component'
      }
    }
  })
])

# Deleting specific properties

If you ever find yourself needing to delete a certain property from your schema, the LookupPlugin's mapProps allows you to do it as well.

Consider the following schema:

{
  "firstName": {
    "type": "FormText",
    "label": "First name",
    "important": true
  },
  "lastName": {
    "field": "FormText",
    "label": "Last name",
    "important": true
  }
}

If we needed to delete the important property from ALL components, we can use the object syntax by setting the property to the boolean false.

LookupPlugin({
  mapProps: {
    important: false
  }
})

If we need more control, to only delete on certain conditions, the function syntax can also be used.

LookupPlugin({
  mapProps: (el) => {
    if (el.label === 'First name') {
      // Delete the important prop from the elements with label 'First name'
      return {
        important: false
      }
    }

    // Ignore any other components
    return {}
  }
})

# Preserving the original property 2.1.0

There may be some cases where you want to preserve the original property that is being mapped by LookupPlugin, since by default this original property is deleted from the object.

In these cases, you can set the preserveMappedProps property of the configuration object and LookupPlugin will no longer delete it from your schema.

WARNING

Properties that are being deleted by setting the property value to false will STILL be deleted.

Consider the following example schema:

{
  "firstName": {
    "type": "FormText",
    "label": "First name",
    "important": true
  },
  "lastName": {
    "field": "FormText",
    "label": "Last name",
    "important": true
  }
}

We now can apply our preserveMappedProps to keep the type property intact.

LookupPlugin({
  mapProps: {
    type: 'component'
  },
  preserveMappedProps: true
})

The schema will now include both the mapped component property, plus the original type:

{
  "firstName": {
    "type": "FormText",
    "component": "FormText",
    "label": "First name",
    "important": true
  },
  "lastName": {
    "field": "FormText",
    "component": "FormText",
    "label": "Last name",
    "important": true
  }
}

# Nested Schema Caveats

# lookupSubSchemas 3.6.0

When dealing with schemas that have sub-schemas like the following:

{
  "firstName": {
    "component": "string",
    "info": "First Name"
  },
  "work": {
    "component": "SchemaForm",
    "schema": {
      "address": {
        "type": "string",
        "label": "Work address"
      },
      "details": {
        "component": "SchemaForm",
        "schema": {
          "position": {
            "type": "string",
            "label": "Work email"
          }
        }
      }
    }
  }
}

We have to do a little extra work to allow the lookup plugin to remap the sub-schema SchemaForm components.

First, import the lookupSubSchemas composition function from the plugin-lookup package.

import LookupPlugin, { lookupSubSchemas } from '@formvuelate/plugin-lookup'

Next, create your schema form with plugins as you normally would.

const SchemaFormWithPlugins = SchemaFormFactory([
  LookupPlugin({
    mapComponents: {
      Text: BaseInput
    }
  })
])

Finally, in your setup function and before the useSchemaForm call, call the lookupSubSchemas function that we just imported and pass in as a parameter the plugin-enhanced SchemaForm component returned by SchemaFormFactory.

setup () {
  const model = ref({})

  lookupSubSchemas(SchemaFormWithPlugins)
  useSchemaForm(model)

  const schema = shallowRef(MY_SCHEMA)

  return {
    schema
  }
}