Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
203 views
in Technique[技术] by (71.8m points)

Can I pass metadata through Vue Formulate's schema API without affecting input attributes?

The goal:

  • generate form fields from JSON/CMS
  • have a param in the JSON that allows two fields to sit next to each other on a single line

The solution so far:

I’m using Vue Formulate's schema API to generate fields. In Vue Formulate's options, I can conditionally add a class to the outer container based on a parameter in the context.

classes: {
  outer(context, classes) {
    if (context.attrs.colspan === 1) {
      return classes.concat('col-span-1')
    }
    return classes.concat('col-span-2')
  },

I’m using Tailwind, which requires no classname concatenation and actually want the default to be col-span-2, so if you’re inclined to copy this, your logic may vary.

With a few classes applied to the FormulateForm, this works really well. No additional wrapper rows required thanks to CSS grid:

<FormulateForm
  v-model="values"
  class="sm:grid sm:grid-cols-2 sm:gap-2"
  :schema="schema"
/>

The schema now looks something like this:

[
  {
    type: 'text',
    name: 'first_name',
    label: 'First name',
    validation: 'required',
    required: true,
    colspan: 1,
  },

The problem/question

Vue Formulate’s schema API passes all attributes defined (other than some reserved names) down to the input element. In my case, that results in:

<div
  data-classification="text"
  data-type="text"
  class="formulate-input col-span-1"
  data-has-errors="true"
  >
  <div class="formulate-input-wrapper">
    <label
      for="formulate-global-1"
      class="formulate-input-label formulate-input-label--before"
    >
      First name
    </label>
    <div
      data-type="text"
      class="formulate-input-element formulate-input-element--text"
    >
      <input
        type="text"
        required="required"
        colspan="1" <--------------- hmm…
        id="formulate-global-1"
        name="first_name"
      >
    </div>
  </div>
</div>

I recognize that I can name my attribute data-colspan so that I’m not placing a td attribute on an input, but I think of colspan as metadata that I don’t want applied to the template. Is there a way to prevent this from being applied to the input—perhaps a reserved word in the schema API that allows an object of metadata to be accessed via context without getting applied to v-bind="$attrs"?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The vue-formulate team helped me out on this one. Very grateful. Much love.

There is a way to prevent it from landing on the input, and that's to use the reserved outer-class property in the schema:

[
  {
    type: 'text',
    name: 'first_name',
    label: 'First name',
    validation: 'required',
    required: true,
   'outer-class': ['col-span-1'],
  },

This means that I don't need to do this at all:

classes: {
  outer(context, classes) {
    if (context.attrs.colspan === 1) {
      return classes.concat('col-span-1')
    }
    return classes.concat('col-span-2')
  },

vue-formulate supports replacing or concatenating classes via props. I managed to overlook it because I didn't recognize that everything you pass into the schema API is ultimately the same as applying a prop of that name.

Classes can be applied to several other parts of the component as well—not just the outer/container. More information here:

https://vueformulate.com/guide/theming/customizing-classes/#changing-classes-with-props


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
...