1.1.0 • Published 3 years ago

@cfl/table-forms v1.1.0

Weekly downloads
-
License
SEE LICENSE IN LI...
Repository
-
Last release
3 years ago

Table Forms JavaScript

This package provides the necessary components to render forms from the True North Web Forms Connector.

The JavaScript comes in two flavours:

  • a library that defines a function that renders the form, intended for use standalone on an existing web site
  • a module that provides React components, which can be used to add the web form to an existing React app

Versioning and compatibility

This package is compatible with True North Web Forms Connector 1.47.0.

If there is no newer version of this package, later versions of the Connector may safely be assumed to be compatible. If there is a newer version of this package, consult that version's README.md for further information.

JSON data compatible with this package will start with:

{
  "$schema": "https://schemas.corefiling.com/tnc/0.5.0/webforms.schema.json",

Rendering a form using JavaScript

This section describes how to add a form to an existing web page.

Make dist/bundle.js and dist/bundle.css available at some convenient URL (there are non-minified versions of the bundles named bundle.dev.js and bundle.dev.css that may be useful during debugging). In this example let’s assume https://cdn.example.com/table-forms/bundle.js.

In the head of the HTML document add a link to the stylesheet:

<link rel="stylesheet" href="https://cdn.example.com/table-forms/bundle.css" />

In the body of the HTML document include the outer element of the form and submit button:

<div id="form-placeholder">Loading …</div>

At the end of the document, reference the JavaScript assets for React and for this project:

<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script crossorigin src="https://cdn.example.com/table-forms/bundle.js"></script>

There are various ways to make the JSON artefacts describing the table and form state available. For example it might be fetched client-side using XMLHttpRequest or fetch APIs. Another approach suitable to server-side rendered pages is to retrieved the JSON server-side and embed it as script element(s):

<script type="application/json" id="tableSpec">
    { … JSON data … }
</script>

And at the end the glue code that replaces the contents of the placeholder element with the form and supplies a routine for dealing with submission.

<script>
    const spec = JSON.parse(document.getElementById('tableSpec').innerText);
    const context = { … };

    tableForm.tableForm({
        taxonomy: spec.taxonomy,
        tables: spec.tables,
        values: values, // Optional: Values tha replace the defaults (e.g., from partially filled in form).
        context: context,  // Optional
        element: document.getElementById('form-placeholder'),
        onSubmit: handleSubmit,
        onSave: handleSave, // Optional: Function for saving partially filled in form.
    });

    function handleSubmit(submission) {
        return fetch('/path/to/submissions', {
            method: 'POST',
            body: JSON.stringify(submission),
            …
        });
    }
</script>

The context object supplies aspects of the facts that are not part of the form itself, and looks like this:

{
    entity: { scheme: 'http://standards.iso.org/iso/17442', identifier: 'TEST0WEB0FORMS000082' },
    currency: 'USD',
    period: { start: '2021-01-01', end: '2021-12-31' },
    decimals: 'INF',  // Or a number of decimal places
}

Replacing only part of a form

This section describes how to handle the situation where the form element needs to include application-specific elements.

The JavaScript is largely similar except there needs to be a table-placeholder element somewhere in the form, and the glue code is different.

<form onsubmit="handleSubmit" id="the-form">
    …
    <div id="table-placeholder-1">Loading …</div>
    …
    <input type="submit">
</form>

A table from the spec is added with code like this:

tableForm.tableFormItems({
    element: document.getElementById('table-form-placeholder-' + i),
    table: spec.tables[i], // One of the tables from the spec.
    values: values.tables[i], // Optional: Values tha replace the defaults (e.g., from partially filled in form).
    name: 't' + i, // Optional: Names this table uniquely within the scope of the form.
});

The JSON object to submit to the backend is extracted from the form data using the function tableForm.submissionFromForm:

function handleSubmit(e) {
    e.preventDefault();

    const submission = tableForm.submissionFromForm(namedTables, document.getElementByuId('the-form'), spec.taxonomy, context);
    … send to backend …
}

The parameters are:

ParameterDescription
namedTablesAn array of objects with keys name and table, corresponding to earlier call(s) to tableForm.tableFormItems.
formElementHTMLFormElement instance that the table forms are part of. If this call is being made in the submit event handler of the form, this will be e.target.
taxonomyInformation about the taxonomy, obtained from the web-form-data spec.
contextInformation required to turn the values in to facts, described above.

The context can be acquired from some external source or could conceivably be made part of the form.

Using the component in a React app

If the customer web app is written in React it can use the components directly. Start with installing it:

yarn add --dev @cfl/table-forms  # or npm install …

Now, having acquired the JSON through some method or other, instantiate the TableForm component:

import { TableForm } from '@cfl/table-forms';

<TableForm
    taxonomy={spec.taxonomy}
    context={…}
    table={spec.tables}
    defaultValues={values.tables}
    className="… optional CSS classes …"
    style={… optional CSS directives …}
    onSubmit={submission => …}
    onSave={submission => …}
    onCancel={() => …}
/>

This generates the form with Submit button. Save and Cancel buttons are added if the corresponding event handler is supplied.

For more fine-grained control of the layout of the form, there is the TableFormItems component. This is used nested within a form element. It will normally be used as a controlled component, with values and onChange properties:

<TableFormItems {...spec.tables[i]} name={`table${i}`} values={values} onChange={newValues => setValues(newValues)} />

To use it uncontrolled, instead optionally supply defaultValues:

<TableFormItems {...spec.tables[i]} name={`table${i}`} defaultValues={spec.values.tables[i]} />

This displays the form, but with its state held within the DOM elements, extracting the user data will require using submissionFromForm.