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

zn-js-form

v0.5.0

Published

A simple library to handle form rendering and validation in Node.js and JavaScript on web browsers.

Downloads

1

Readme

Zion's JavaScript Form

A simple library to handle form rendering and validation in Node.js and JavaScript on web browsers.

Paths in all documentation, even those in subfolders, are relative to the root of the repository. Shell commands are all run from the root of the repository.

Sections

References

  • Mustache.js: This templating library is used for rendering HTML for the form and its components.
  • Bootstrap 5.0 Forms: This library is not used, but the default rendering templates follows its examples.
  • JSDoc: Used for docblocks in source code.
  • Related repositories:
    • ZnPhp-Form: Simple form class to handle config, validation and rendering for fast deployment on a PHP site without any framework.
    • ZnZend Form: Form component of library for Zend Framework 2.

Requirements

  • Node.js >= 14.17.3 (includes npm 6.14.13).
  • Google Chrome >= 80.
  • ?. optional chaining and ?? nullish coalescing operator used in source code are only supported from Node.js 14 and Chrome 80 onwards.

Changelog

  • See CHANGELOG.md. Note that changes are only documented from v1.0.0 onwards.

Usage

  • Visit https://zionsg.github.io/zn-js-form/jsdoc to view the generated JSDoc documentation (saved in docs/jsdoc folder and served via GitHub Pages pointing to docs/index.html).

    • Also look at the test folder. The test.html is an example of how this library can be used in a webpage (showcases fieldsets and other types of fields), while *.test.js show how it can be used in Node.js.
  • For Node.js:

    • Run npm install zn-js-form to install the package.
    • Import the module, e.g. const ZnJsForm = require('zn-js-form');.
  • For JavaScript in web browser:

    • Download this repository into your project directory either by cloning it into a subfolder or using NPM to install it into node_modules subfolder.
    • Include the bundle script dist/bundle.js on the webpage, e.g. <script src="zn-js-form/dist/bundle.js"></script>.
  • Sample code (same for Node.js and JavaScript):

      let myForm = new ZnJsForm.Form({
          name: 'myform',
          action: 'https://example.com',
          attributes: {
              enctype: 'multipart/form-data',
              novalidate: '', // attribute set with no value if empty string
              required: null, // attribute not set if value is null
          },
      });
    
      myForm.fields.set('username', new ZnJsForm.Field({
          inputType: 'text',
          label: 'Username',
          note: 'This field is readonly.',
          noteClasses: ['note'],
          required: true, // in-built validation if this is true and field not disabled/readonly
          fieldClasses: ['field'],
      }));
    
      myForm.fields.set('pet', new ZnJsForm.Field({
          inputType: 'select',
          label: 'Pets',
          emptyOptionText: '--- Please choose a pet ---',
          options: {
              123: 'cat',
              456: 'dog',
          },
          fieldClasses: ['field'],
          // Optional field validation, does not override in-built validation for required field
          validateFunction: function (fieldName, fieldValue, formData) {
              // Return an array of error messages. Note that web forms return string values.
              return (fieldValue !== '123') ? ['You must choose a cat.'] : [];
          },
      }));
    
      // Modify field
      myForm.fields.get('username').config.readonly = true;
    
      // Validate dropdown to render errors
      myForm.fields.get('pet').validate('pet', '456', {});
    
      console.log(myForm.render()); // output can be set as innerHTML of some element in webpage
  • The above will produce:

      <form name="myform" method="POST" action="https://example.com"
          enctype="multipart/form-data" novalidate class="">
          <div class="field">
              <label for="username" class="">Username</label>
              <input name="username" type="text" value="" readonly required class="">
              <div class="note">This field is readonly.</div>
              <div class="errors"></div>
          </div>
    
          <div class="field">
              <label for="pet" class="">Pets</label>
              <select name="pet" class="">
                  <option value="" selected>--- Please choose a pet ---</option>
                  <option value="123">cat</option>
                  <option value="456">dog</option>
              </select>
              <div class="errors">
                  <ul>
                      <li>You must choose a cat.</li>
                  </ul>
              </div>
          </div>
      </form>
  • Form validation can be done using the validate() method, which returns null if the form is valid or an object containing an array of error messages for each field if the form is invalid. Note that a field may have more than 1 error, depending on the validateFunction passed via the field config. Values and errors are stored per field upon validation so that they will be populated if the form gets rendered after validation. Sample:

      // Code
      let errors = myForm.validate({
          username: '',
          pet: '456',
      });
      console.log(errors);
    
      // Output
      {
          username: [ 'This field is required.' ],
          pet: [ 'You must choose a cat.' ]
      }
  • Advanced field example. Render a field as dropdown in edit mode and render as a disabled input field if not in edit mode. The edit mode can be indicated via a boolean template variable, e.g. editMode, passed to render(). Sample code:

      myForm.config.inputTemplates['ifEditModeShowDropdownElseShowDisabledInput'] = `
          {{^editMode}}
              <input name="{{name}}" type="text" value="{{selectedOptionText}} (id:{{value}})"
                  {{{attributes}}} class="{{{classes}}}" disabled />
          {{/editMode}}
          {{#editMode}}
              <select name="{{name}}" {{{attributes}}} class="{{{classes}}}">
                  <option value="" {{^hasSelectedOption}}selected{{/hasSelectedOption}}>
                      {{emptyOptionText}}</option>
                  {{#options}}
                      <option value="{{optionValue}}"
                          {{#optionSelected}}selected{{/optionSelected}}>{{optionText}}</option>
                  {{/options}}
              </select>
          {{/editMode}}
      `;
    
      myForm.fields.set('advanced_field', new ZnJsForm.Field({
          inputType: 'ifEditModeShowDropdownElseShowDisabledInput',
          label: 'Advanced Field',
          value: 123,
          note: '(if editMode template variable passed to render() is true, show dropdown, else show disabled input)',
          noteClasses: ['note'],
          options: {
              123: 'Cycling',
              456: 'Running',
          },
      }));
    
      myForm.render({
          editMode: false,
      });

Installation

  • This section is meant for developers. Todo tasks are marked by @todo comments.
  • Clone this repository.
  • Run npm run install to install dependencies.
  • Other NPM scripts:
    • npm run build: Bundle the source code so that it can be used in a web browser. The output will be in dist/bundle.js.
    • npm run watch: Automatically bundle the code each time the source code is changed on the local machine.
    • npm run doc: Generate JSDoc documentation and save in docs/jsdoc folder.
    • npm run lint: Linting checks.
    • npm run test: Execute tests.
  • To publish to NPM registry as a public package:
    • Update the application version:
      • Update version key in package.json..
      • Update version in package-lock.json by running npm install --package-lock-only.
      • Update the bundle script by running npm run build.
    • This part only needs to be done once.
      • Login to https://www.npmjs.com
        • Go to "Access Tokens".
        • Click "Generate New Token".
        • Select "Publish".
        • Copy the token - it will not be displayed again.
      • Create a .npmrc file in the root of the cloned repository and add the line //registry.npmjs.org/:_authToken=YOUR-ACCESS-TOKEN, replacing the last part with your token.
      • Run npm login to login to your account on the local machine.
      • Remove "private": true from package.json if it exists.
    • Run npm publish --access public.
    • View the published package at https://www.npmjs.com/package/zn-js-form and ensure that the package is public.

Architecture

  • Entity relationships:
    • A form has 0 or more fieldsets, and has 1 or more fields.
    • A fieldset has a legend, and has 1 or more fields.
    • A field has a label and an input.
    • An input can be broadly categorized into these types: <input>, <textarea>, <select>, <progress>, <meter>.
    • Semantically, options are different from choices. A select/checbox/radio presents the user with a fixed list of options but the user makes a choice amongst them.
  • Conventions:
    • The variables defined in a method signature are called method parameters. The values passed to a method when calling it are called method arguments.
    • Note that for typical web form submissions, field values are always of string or array type (multiple values such as for multi-select checkbox groups).
      • A value of an empty string implies an empty value for a field, i.e. the user did not key in anything for the field.
      • Even if a user keys in a number, it will be submitted as a string.
      • Hence, a field would not have null/undefined/boolean values.
    • All constructors take in a single parameter of object type, which is the configuration.
    • All classes have a render() method which takes in an object containing additional template variables and returns a string.
  • Workflow:
    • User runs let myForm = new ZnJsForm.Form({});, either in Node.js or in JavaScript on a web browser.
    • Entrypoint of library, i.e. ZnJsForm, is src/index.js which exports an object of classes.
    • One of the exported classes is Form which is loaded from src/Form.js.
    • The new statement specifically calls the constructor defined by function Form(config) {}.