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

widjet-json-form

v1.2.1

Published

A widget to generate forms using a json object descriptor

Downloads

11

Readme

widjet-json-form Build Status codecov

A widget to generate forms using a json object descriptor

Install

npm install --save widjet-json-form

Usage

The json-form widget generates form fields in the target element by reading a json schema. Values can be specified for the form to populate the fields.

Two preferred ways are available to define the schema and values for a field:

Using Script Tags

Using script tags for schema and values offer the advantages of removing the characters escaping contraints of attributes and readability of indented code at the cost of a heavier markup and the need to have unique ids for every tags.

import widgets from 'widjet';
import 'widjet-json-form';

widgets('json-form', '[data-schema-source]', {on: 'load'});
<script id='schema' type='application/json'>
  {
    "title": "string",
    "content": "markdown",
    "publishedAt": "datetime"
  }
</script>
<script id='values' type='application/json'>
  {
    "title": "Here's a title",
    "content": "Then some content",
    "publishedAt": "2016-09-08T20:35:54.855Z"
  }
</script>
<div data-schema-source='schema'
     data-values-source='values'
     data-id='news-form'>
</div>

Using Data Attributes

Data attributes offers an easier setup for small forms that doesn't have a lot of settings or complex strings with special characters to escape. It's also more convenient when many forms are to be generated on a single page as it doesn't require to inject scripts with unique ids for each forms.

import widgets from 'widjet';
import 'widjet-json-form';

widgets('json-form', '[data-schema]', {on: 'load'});
<div data-schema='{"title": "string", "content": "markdown", "publishedAt": "datetime"}'
     data-values='{"title": "Here&quo;s a title", "content": "Then some content", "publishedAt": "2016-09-08T20:35:54.855Z"}'
     data-id='news-form'>
</div>

Form Schema

A form schema is an object whose keys represent the field names, and its values the field descriptors.

{
  "property": "type",

  "otherProperty": {
    "type": "type",
    "fieldSetting": "whatever"
  }
}

The simplest way to define a field is to create a pair "property": "type". In that case no other configuration will be available in the field template.

The other way is to define a pair "property": {object} where the object has a mandatory type key. Every other properties of that object will be passed to the field's template as its parameters, allowing for a finer setup of the field.

Here's an example of a more complete setup for a field of type integer:

{
  "integerField": {
    "type": "integer",
    "hint": "Hint for input of type `integer`. Hints support markdown.",
    "placeholder": "12345",
    "min": 0,
    "max": 1000,
    "step": 10,
    "default": 100,
    "required": true
  }
}

It's up to you to decide which parameters your field's input template will support. The only requirement is that the field config contains a type key.

For instance, here's what a Twig template for the field described above look like:

<label for='{{ id }}'>{{ attribute }}{% if not parameters.required %} <em> - Optional</em>{% endif %}</label>

{% if parameters.hint %}{% markdown %}{{ parameters.hint }}{% endmarkdown %}{% endif %}

<input type='number'
       id='{{ id }}'
       step='{{ parameters.step|default(1) }}'
       {% if parameters.min %}min='{{ parameters.min }}'{% endif %}
       {% if parameters.max %}max='{{ parameters.max }}'{% endif %}
       value='{{ value|default(parameters.default)|default }}'
       {% if parameters.placeholder %}placeholder="{{ parameters.placeholder }}"{% endif %}
       name='{{ name }}'
       {% if parameters.required %}required{% endif %}>
</input>

Templates

By default the widget will look for templates in the window.JST object, as it's one of the most common places to store javascript templates. All the templates are retrieved using a name such as json-form/<name>.

As with most JS templating engine, a template is expected to be a function that takes a parameters object and that returns a HTML string.

Note that the default field's renderer will look for a template according to the field's type. That means that if the type of the field is boolean, the field renderer will try to render the json-form/boolean with the parameters it received and then pass the result as the content parameter to the field template. Concretely, it means that you just have to create a template to allow a new type of input in the form without any other setup

The default template names being used by the widget are the following:

Name|Path|Description ---|---|--- form|json-form/form|The wrapper of the whole form.Parameters: content, id field|json-form/field|The wrapper for a form's field.Parameters: content, id, name, type, value, attribute, attributePath, parameters. object|json-form/object|If the field's type is object this template will be used as a wrapper for the whole sub-form instead of the field one.Parameters: content, id, name, type, value, attribute, attributePath, parameters. array|json-form/array|If the field's type is array this template will be used as a wrapper for all the items in the array instead of the field one.Parameters: content, id, name, type, value, attribute, attributePath, parameters. arrayItem|json-form/arrayItem|If the field's type is array, the sub-form for each item will be wrapped using this template.Parameters: content, id, name, type, value, attribute, attributePath, parameters. <type>|json-form/<type>|Each field types must have their own template.Parameters: id, name, type, value, attribute, attributePath, parameters.

Defining the templates in the window.JST object, or in another object, is up to you. The json-form widget doesn't provide any template to let you keep the full control of how forms are rendered.

Templates parameters

Name|Description ---|--- id|The id of the element.For a form template, the id is either the value provided in the data-id or an auto-incremented number id.For field-related templates, the id is generated automatically using the id of its parent form and the attribute path. By default the id for a property age of the second item of a users array in a form with id company would be company-users-1-age. This can be changed through the fieldId widget setting. type|The type of the field as defined in the schema. attribute|The name of the current attribute. attributePath|An array with every components that form the path to the attribute, starting from the schema root. As an example, for the property age of the second item of the users array, the attribute path is ['users', 1, 'age'] name|The input name, as generated by the fieldName function using the attribute path. By default the name for a property age of the second item of a users array would be users[1][age]. This can be changed through the fieldName widget setting. value|The value of the field, as provided in the data-values attribute. parameters|An object with the parameters of the field, as defined in the schema. content|Wrapper templates will receive the HTML content to include in that parameter.

Configuration

The widget accepts the following options:

Name|Type|Description ---|---|--- findTemplate|function|A function that takes the name of a template such as form or array and must returns a template function taking a parameters object and returning a HTML string. fieldId|function|A function that takes the id of the form and an attribute path and that must returns the string id for the field. fieldName|function|A function that takes an attribute path and that must returns the string name for its input. schemaSourceAttribute|string|The attribute to use when looking for the schema script source. Defaults to data-schema-source. The value of the attribute should always be the id of a script tag schemaAttribute|string|The attribute to use when looking for the schema on the target element. Defaults to data-schema. valueSourceAttribute|string|The attribute to use when looking for the values script source. Defaults to data-values-source. The value of the attribute should always be the id of a script tag valueAttribute|string|The attribute to use when looking for the values on the target element. Defaults to data-values. idAttribute|string|The attribute to use when looking for the form's id on the target element. Defaults to data-id. renderers|array|An array of custom renderers to be applied before the default ones. See more below about custom renderers.

The default renderers include renderers for object, array and the generic field renderer.

It's also possible to specify a template for a specific key without specifying a custom template finder function. The default findTemplate implementation will look for a property named <name>Template on the options object before looking in window.JST.

For instance if you just want to use a different template for the form while keeping using the defaults one for the other templates you can just do:

widgets('json-form', '[data-schema]', {
  on: 'load',
  formTemplate: ({content, id}) =>
    `<div class='form' id='${id}'>${content}</div>`,
});

Custom Renderers

A renderer is defined using two functions in an array. The first function is the predicate that defines whether the renderer applies to the passed-in type. The second function is a function returning function or a curried function that takes a renderObject function and the field's parameters and returns the field's HTML string.

The renderObject function that is passed to the render function is here so that you can write renderers that are able to include nested forms (as the default object and array renderers do).

When rendering a field, the render engine will loop through all the renderers and call their predicate function with the field's type as argument. The first renderer whose predicate function returns true will be used and its render function will then be called with the field's parameters object (containing the id, name, type, value, attribute, attributePath and parameters).

Using a Function Returning Function

const dummyRenderer = [
  type => type === 'boolean',
  renderObject => parameters =>
    `<input type="checkbox"
            value="1"
            name="${parameters.name}"
            id="${parameters.id}"
            ${parameters.value ? 'checked' : ''}>`,
];

widgets('json-form', '[data-schema]', {
  on: 'load',
  renderers: [dummyRenderer],
});

Using a Curried Function

const dummyRenderer = [
  type => type === 'boolean',
  curry2((renderObject, parameters) => {
    return `<input type="checkbox"
                   value="1"
                   name="${parameters.name}"
                   id="${parameters.id}"
                   ${parameters.value ? 'checked' : ''}>`;
  }),
];

widgets('json-form', '[data-schema]', {
  on: 'load',
  renderers: [dummyRenderer],
});