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

@molgenis/molgenis-ui-form

v5.9.4

Published

Library for generating HTML web forms

Downloads

49

Readme

molgenis-ui-form

codecov Known Vulnerabilities Commitizen friendly

Library for generating HTML web forms

Changelog

Details changes for each release generated in the CHANGELOG.md. You can view the changes on GitHub as well (https://github.com/molgenis/molgenis-ui-form/releases)

Usage

Install

# Add library using yarn.
yarn add @molgenis/molgenis-ui-form

Use

<template>
  <form-component
    id="example-form"
    :formFields="formFields"
    :initialFormData="formData"
    :formState="formState"
    :options="options"
    @valueChange="onValueChanged"
    @addOptionRequest="handleAddOptionRequest"
  >
  </form-component>
</template>

<script>
// Import form component
import { FormComponent } from '@molgenis/molgenis-ui-form'

// Import EntityToFormMapper
import { EntityToFormMapper } from '@molgenis/molgenis-ui-form'

// Import all form component styles
import '../node_modules/@molgenis/molgenis-ui-form/dist/static/css/molgenis-ui-form.css'

export default {
  name: 'ExampleComponent',
  data() {
    return {
      formFields: [],
      formData: {},
      formState: {},
      options: {
        showEyeButton: true
      }
    }
  },
  methods: {
    handleAddOptionRequest(addNewItemFunction) {
      // Handle the request to add a new item here
      const item = {
        id: 'new_item',
        label: 'New Item',
        value: 'new_item'
      }

      addNewItemFunction(item)
    },

    onValueChanged(formData) {
      // Do something with the updated formData
      console.log(formData)
    }
  },
  created() {
    // Generate a form from a MOLGENIS v2 API response
    // Or create fields based on the specs (Form specifications)
    const form = EntityToFormMapper.generateForm(metadata, items[0])
    this.formFields = form.formFields
    this.formData = form.formData
  },
  components: {
    FormComponent
  }
}
</script>

Note: Whatever you pass to the FormComponent as formData object, the FormComponent makes a local copy with Object.assign({}, formData).

If you want to react to data input, use the @valueChanged event.

valueChanged event

When data in the form is changed, the form fires a valueChanged event. This event exposes two arguments, formData and isFormValid.

formData is a key value object, where the field ID is the key, and the data filled in by the user is the value. isFormValid is a boolean telling you if there are any invalid fields in the form.

An example handler is shown below

methods: {
  onValueChanged (formData) {
    console.log(formData) // all the data currently in the form
  }
}
addOptionRequest event

To allow the user to add new options to a select list the handleAddOptionRequest should be a function with the following properties:

  • completedFunction a callback function that should be called passing the option to be added.
  • event the original event triggering the request.
  • data object with form field state data.

The option object passed to the completedFunction should at least have the following fields

  • id unique identifier
  • label the label shown to the user
  • value the form value

Options

The FormComponent object can be configured via an options property. If no options object is supplied the defaults are used.

| Option name | Default | Description | | ------------------ | ------- | ---------------------------------------------------------------------------------------- | | showEyeButton | True | Toggle the visibility of the Eye button. | | allowAddingOptions | False | When set to true users are show a interface item to add options to a (multi)select. | | inputDebounceTime | 500 | Time (in milliseconds) between input updates needs to pass before update event is fired. |

Form specifications

Example on how to create fields and data objects for using the forms.

const fields = [
  {
    type: 'text',
    id: 'example-text-field',
    label: 'Example text field',
    description: 'This field shows how to create a form field from scratch',
    required: (formData) => true,
    disabled: false,
    readOnly: false,
    visible: (formData) => true,
    validate: (formData) => true
  }
]

const data = {
  'example-text-field': 'example value'
}

Type support

We support most HTML input types like number, text, and email. Below is a list of supported types.

| type | renders | | ------------- | ----------------------------------------------------------------------------------------------------------------------------- | | radios | A list of radio buttons | | single-select | A Vue select dropdown which supports asynchronous and synchronous option lists | | multi-select | A Vue Multiselect dropdown which supports asynchronous and synchronous option lists | | number | A HTML5 number input | | integer | A HTML5 number input, with step size set to 1 and may not include a fraction and must lie between --2147483648 and 2147483647 | | long | A HTML5 number input, Long may not include a fraction and should fit into javascript number type. | | decimal | A HTML5 number input, may include a fraction | | text-area | A textarea HTML element | | date | A Vue Flatpickr Date component | | date-time | A Vue Flatpickr Date component with 'enableTime = true' | | checkboxes | A list of checkboxes | | text | A HTML5 text input | | hyperlink | A HTML5 text, only valid uri is allowed | | email | A HTML5 text email | | password | A HTML5 password input | | file | A HTML5 file input | | field-group | A type that is used to nest other inputs |

Option field example

Fields that render lists of options like radio buttons, checkboxes, and select dropdowns have an additional option parameter. This option parameter should always contain a function returning a promise.

This makes it usable for both synchronous and asynchronous rendering of option lists.

const fields = [
  {
    type: 'field-group',
    id: 'example-field-group',
    label: 'Example field group',
    description: 'This field shows how to create a group of fields',
    required: (formData) => true,
    disabled: false,
    readOnly: false,
    visible: (formData) => true,
    validate: (formData) => true,
    options: () => {
      const options = [
        {
          id: '1',
          label: 'Option 1',
          value: '1'
        },
        {
          id: '2',
          label: 'Option 2',
          value: '2'
        }
      ]

      return Promise.resolve(options)
    },
    isAddOptionAllowed: () => Promise.resolve(true)
  }
]

The isAddOptionAllowed function indicated if the user should be allowed to add options

Field group example

A field group can be used to group a set of fields. You can specify a list of fields under a field-group via the children parameter.

const fields = [
  {
    type: 'field-group',
    id: 'example-field-group',
    label: 'Example field group',
    description: 'This field shows how to create a group of fields',
    required: (formData) => true,
    disabled: false,
    readOnly: false,
    visible: (formData) => true,
    validate: (formData) => true,
    children: [
      {
        type: 'text',
        id: 'example-field-group',
        label: 'Example text field',
        description: 'This field shows how to create a form field from scratch',
        required: (formData) => true,
        disabled: false,
        readOnly: false,
        visible: (formData) => true,
        validate: (formData) => true
      }
    ]
  }
]

// Note that the field group itself does not have data
const data = {
  'example-text-field': 'example value'
}

Range

A number fields valid input range can be restricted by supplying a range object The range object can have a min property, a max property or both. for example

{
  id: 'example-number-with-range',
  type: 'integer' | 'long',
  range: {
    min: 0,
    max: 13
  }
}

Required, visible, and validate

As you might have noticed in the above examples, required, visible, and validate are functions returning a boolean. The reason for this is that you might want to validate a field based on the input of another field.

Or show / hide a field once another field has a certain value.

const fields = [
  {
    type: 'text',
    id: 'example-text-field',
    label: 'Example text field',
    description: 'This field controls the visibility of example-number-field',
    required: (formData) => true,
    disabled: false,
    readOnly: false,
    visible: (formData) => true,
    validate: (formData) => true
  },
  {
    type: 'integer',
    id: 'example-integer-field',
    label: 'Example integer field',
    description:
      'This field is shown if "example-text-field" contains the text "show"',
    required: (formData) => true,
    disabled: false,
    readOnly: false,
    visible: (formData) => {
      return formData['example-text-field'] === 'show'
    },
    validate: (formData) => true
  }
]

Unique field value validation

Fields of type string, number, integer, long, decimal or radio may include a function that validated value uniqueness. The function should return a promise that resolves to a boolean indicating if the value is unique in some context.

Example:

unique: (proposedValue, [context]) => {
  return new Promise((resolve, reject) => {
    api.get('some-api-call-that-checks-proposed-value').then((result) => {
      resolve(result)
    })
  })
}

Validation message localization

Validation messages may be localized via the use of the @molgenis/molgenis-i18n-js plugin.

Usage:

Vue.use(i18n, {
  lng: 'en',
  fallbackLng: 'en',
  namespace: ['some-namespace', ui-form],
  callback () {
    /* eslint-disable no-new */
    new Vue({
      el: '#form-demo',
      template: '<FormDemo/>',
      components: { FormDemo }
    })
  }
})

If no 'ui-form' namespace is set on the supplied Vue instance the default (English) messages are used.

message keys and defaults

| Key | Default message | Additional Info | | ---------------------------------- | ------------------------------ | -------------------------------------- | | ui-form:form_required_field | 'This field is required' | | | ui-form:form_validation_failed | 'Validation failed' | | | ui-form:form_not_a_valid_number | 'Not a valid number' | | | ui-form:form_not_a_valid_hyperlink | 'Not a valid Hyperlink' | | | ui-form:form_not_a_valid_email | 'Not a valid email' | | | ui-form:form_not_within_range | 'Value is outside of range' | min, max is added as: ' ($min - $max)' | | ui-form:form_below_min_value | 'Value is below allowed value' | min value is added as: ' $min' | | ui-form:form_above_max_value | 'Value is above allowed value | max value is added as: ' $max' |

Entity mapper options

The EntityToFormMapper.generateForm function takes a optional options param. The options param is a object that can contain the following properties:

  • booleanLabels Optional Object used to set labels for boolean type fields, can be use in combination with i18n plugin to translate boolean labels.
  • showNonVisibleAttributes Optional boolean if set to true maps non visible attributes to visible field, defaults to false
  • mapperMode Optional string (valid modes are UPDATE and CREATE) if set to CREATE readonly attributes map to writable fields, defaults to CREATE

Invalid validation expression handling

Erroneous validation expressions in the visibleExpression and nullableExpression metadata fields will fallback to the respective visible and nillable values. A broken validationExpression will fall back to being true.

Description fields

The description will automatically make URL's clickable.

You can create a (read more) button by using an enter in the description field, which will display the remaining text after the enter.

You are able to create a information tooltip by using the following tag inside of the description field {i}My information icon tooltip{/i}

Break lines with {br} for example a description like this: {br}• list item 1{br}• list item 2{br}• list item 3{br}

Will render a list like this: • List item 1 • List item 2 • List item 3

Development

The general guidelines and setup of the development environment are described here.

Build setup

# install dependencies
yarn install

# serve with hot reload at localhost:8080
yarn run dev

# build for production with minification
yarn run build

# build for production and view the bundle analyzer report
yarn run build --report

# run unit tests
yarn run unit

# run continuous unit tests
yarn run unitwatch

# run e2e tests
yarn run e2e

# run all tests
yarn test

How to commit

We use conventional commits to generate changelogs and release notes. Please check: https://www.conventionalcommits.org/

Example

git commit file.ext -m "fix(file.ext): fixes something"

How to publish

Each time a PR is merged a release will be done to NPM. The CHANGELOG.md and GitHub release will be ammended.

The version of the package is based upon convential commits. Check: http://commitizen.github.io/cz-cli/.

Tests

To develop tests please acknowledge the following guidelines.

End-to-End test

Please make sure you add the name of the specific test in the test. This is needed to see the test-name in Saucelabs. Example

browser.options.desiredCapabilities.name = 'Example testname'

Integration with vue-form

We use the vue-form library for validation.

The component tree mingles elements from vue-form and molgenis-ui-form like this:

<FormComponent :formState :initialFormData>
  <VueForm :state="formState">
    <FormFieldComponent :formState :formData :field>
      <TypedFieldComponent v-model="formData[field.id]">
        <Validate :state :debounce>
          <input v-model="localValue">
          <FormFieldMessages>

The TypedFieldComponent creates a localValue data element and binds it to a type-specific input inside a Validate component. The TypedFieldComponent fires @Input events whenever localValue changes. These @Input events are bound to formData[field.id]

Event handling

vue-form debounces the validation until input ceases. The FormFieldComponent listens for formState[field.id].$pending to become false to make sure that validation is done and the fieldState is up to date. Then it emits a @dataChange event to the FormComponent and the FormComponent emits @valueChange.