npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

v-generic-form

v1.1.13

Published

- ~~Allow user to choose schema layout via slot~~ - ~~Optional passing of form data when not using slots~~ - Create Typescript validation function to provide better intellisense when defining schema - Individual passing of specific individual fields, e

Downloads

7

Readme

v-Generic-Form

TODO:

  • ~~Allow user to choose schema layout via slot~~
  • ~~Optional passing of form data when not using slots~~
  • Create Typescript validation function to provide better intellisense when defining schema
  • Individual passing of specific individual fields, e.g.
  • Add rules directive to children of generic form ( nice to have honestly )
  • Typescript rewrite overall
  • Allow global custom errors

Quickstart

Vue 2

yarn add v-generic-form-vue2

OR

npm i v-generic-form-vue2

import Vue from 'vue'
import vGenericForm from 'v-generic-form-vue2'
Vue.use(VGenericForm, {
    ...
})

Vue 3

yarn add v-generic-form

OR

npm i v-generic-form

import { createApp } from 'vue'
import vGenericForm from 'v-generic-form'

const el = document.getElementById('app');
const app = createApp();
app.use(vGenericForm, {
  ...
}).mount(el)

Basic usage

<template>
  <div>
    <v-generic-form :fields="fields" @submit="onSubmit" :onDataChange="onDataChange"  />
  </div>
</template>

<script>
export default {
  name: 'Form',
  computed: {
    fields() {
      return [
        {
          name: 'input',
          placeholder: 'input',
          label: 'input label',
          type: 'text',
        }
      ]
    }
  },
  methods: {
    onSubmit(data) {
      console.log(data)
    },
    onDataChange(data) {
      console.log(data)
    }
  }
};
</script>

Adding validation

vGenericForm uses validate.js behind the scenes for validation so refer to it for adding custom rules or finding all available validators.

Validation is as simple as passing a rules object to the field in your schema.

[
  {
    name: "input",
    defaultValue: 'some supported value',
    placeholder: "input",
    label: "input label",
    type: "text",
    rules: {
      required: true,
      exclusion: {
        within: ['Not Supported Value 1', 'Not Supported Value 2'],
        message: "^We don't support %{value} right now, sorry",
      },
    },
  },
];

Adding a custom validator

<script>
import validate from 'validate.js'
validate.validators.isTest = function (value, options, key, attributes) {
  console.log(value);
  console.log(`input`, attributes.atest) // same results as previous line
  console.log(options);
  console.log(key);
  console.log(attributes);
  const { message } = options
  if (value !== "test") {
    return message || 'must equal test'
  }
  // return null if success
  return null
};
export default {
  computed: {
    fields() {
      return [
        {
          name: "atest",
          placeholder: "input",
          rules: {
            isTest: {
              message: "This value does not equal test!",
            },
          },
          // disable showing input name in validation message
          fullMessages: false
        },
      ];
    },
  },
};

</script>

Using different variants

By default, vGenericForm comes with 2 inputs. Input, Select, RadioButton(coming soon), and Textarea. It will default to Input but to use a different variant, simply pass a variant as a string to the desired input you'd like to modify.

[{
  name: 'input',
  placeholder: 'input',
  label: 'input label',
  type: 'text',
  variant: 'Select',
  values: ['option1', 'option2']
}]

Using a external component with the form

<script>
import Custom from '@/components/custom'
export default {
  computed: {
    fields() {
      return [
        {
          name: "input",
          placeholder: "input",
          label: "input label",
          type: "text",
          component: Custom,
          rules: {
            required: true, // validation still works perfectly on these
          },
          customData: {
            customPropForCustomComponent: "123",
          },
        },
      ];
    },
  },
};

</script>


Custom.vue

<template>
  <div>
    <button @click="sendUpdatedValueToForm()">{{ value }}</button>
    {{ customData.customPropForCustomComponent }}
  </div>
</template>

<script>
export default {
  // default props available from generic form
  props: {
    value: {
      type: String,
      default: '',
    },
    inputType: {
      type: String,
      default: 'text',
    },
    name: {
      type: String,
      default: '',
    },
    values: {
      type Array,
      default: () => []
    },
    label: {
      type: String,
      default: '',
    },
    placeholder: {
      type: String,
      default: '',
    },
    errors: {
      type: [Array, String, Object],
      default: null,
    },
    customData: {
      type: Object,
      default: null,
    },
    getAllFields: {
      type: Array,
      default: () => {}
    },
  },
  data() {
    return {
      componentValue: "first value",
    };
  },
  methods: {
    sendUpdatedValueToForm() {
      this.componentValue = Math.random();
      $emit("setValue", {
        name,
        value: componentValue,
      });
    },
  },
};

</script>

Defining default components

import { createApp } from 'vue'
import MyInput from '@/components/myInput'
import vGenericForm from 'v-generic-form'

const el = document.getElementById('app');
const app = createApp();
app
  .use(vGenericForm, {
    components: {
      // define default inputs here
      MyInput, // you will be able to pass this as a variant now by passing variant: 'MyInput' to object scheme,
      submitText: 'Okay'
    },
  })
  .mount(el);

Styling

The generic form is structured like so:

div>
  <form
    :class="(options && options.formClass) || ''"
   >
     <div
        v-for="(field, i) in fields.filter(
          (f) => f.show === undefined || f.show !== false
        )"
        :key="i"
        :class="field.divClass"
    >

We can change the structure very easily by passing a options object

<v-generic-form :options="{
    formClass: 'flex justify-between'
}">

As you may imagine, you can control the widths of the divs each one of your fields are in by passing a divClass to your field schema:

[
  {
    name: "input",
    placeholder: "input",
    label: "input label",
    type: "text",
    divClass: "w-2/3",
    inputClasses: "bg-green-200", // you can also style the default inputs by passing this inputClasses key
  },
];

Changing submit

<v-generic-form @submit="onSubmit">
  <template v-slot:submit>
    <button type="submit">my custom submit button!</button>
  </template>
</v-generic-frorm>

Asynchronous validation

<template>
  <div>
    <v-generic-form ref="form" :fields="fields" @submit="onSubmit" :beforeSubmit="beforeSubmit" />
  </div>
</template>

<script>
import axios from 'axios'
export default {
  name: "Form",
  computed: {
    fields() {
      return [
        {
          name: "name",
          placeholder: "Your Name",
          label: "Name",
        },
        {
          name: "email",
          placeholder: "Your Email",
          label: "Email",
        },
      ];
    },
  },
  methods: {
    async beforeSubmit({email}) {
      const { data: { exists } } = await axios.post("https://myendpoint.com/checkEmails", { email });
      if (exists) {
        // prevent form from submitting by setting a custom error
        this.$refs.form.setCustomError({
          key: "email",
          value: "Email already exists.",
        });
      } else {
        // we can clear it if it doesn't exist
        this.$refs.form.setCustomError({
          key: "email",
          clear: true,
        });
      }
    },
  },
};

</script>

Defining your own layout

<template>
  <v-generic-form :schema="schema"  @submit="submit" ref="form">
    <template v-slot="{ errors, firstError, formData }">
        <generic-input v-model="formData.test1" />
        <span class="text-red-500">{{ firstError('test1') }}</span>
        <generic-input v-model="formData.test2" />
        <span class="text-red-500">{{ errors('test1') }}</span>
        <button class="custom-submit" type="submit">Submit</button>
    </template>
  </v-generic-form>
</template>

<script>
import GenericInput from "./GenericInput.vue";

export default {
  name: "CustomForm!",
  components: {
    GenericInput,
  },
  methods: {
    submit(data) {
      console.log(`data`, data);
    },
  },
  computed: {
    schema() {
      return {
        test1: {
          defaultValue: "test",
          rules: {
            required: true,
          },
        },
        test2: {
          rules: {
            required: true,
          },
        },
      };
    },
  },
};

</script>

<style scoped>
.custom-submit {
  background: blue;
  color: white;
  padding: 0.5rem 2rem;
  display: block;
  margin-top: 1rem;
  cursor: pointer;
}
</style>

Using your own formData object

<template>
  <v-generic-form :schema="schema"  @submit="submit" :customFormData="customFormData" ref="form">
    <template v-slot="{ errors, firstError, formData }">
        <generic-input v-model="formData.test1" />
        <span class="text-red-500">{{ firstError('test1') }}</span>
        <generic-input v-model="formData.test2" />
        <span class="text-red-500">{{ errors('test1') }}</span>
        <button class="custom-submit" type="submit">Submit</button>
    </template>
  </v-generic-form>
</template>

<script>
import GenericInput from "./GenericInput.vue";

export default {
  name: "CustomForm!",
  components: {
    GenericInput,
  },
  data() {
    return {
      customFormData: {
        test1: "",
        test2: "434",
      },
    };
  },
  methods: {
    submit(data) {
      console.log(`data`, data);
    },
  },
  computed: {
    schema() {
      return {
        test1: {
          defaultValue: "test",
          rules: {
            required: true,
          },
        },
        test2: {
          rules: {
            required: true,
          },
        },
      };
    },
  },
};
</script>