cofi

cofi

  • Docs
  • Form Demos
  • Components Demos
  • Layout Demos
  • Editor
  • GitHub

›React Form

Getting started

  • Introduction

Form Class

  • Installation
  • Overview
  • Arguments
  • Id
  • Data
  • Fields
  • Path
  • Component
  • Formatter & Parser
  • Dependencies
  • Required
  • Validators
  • Exclude Term
  • Disable Term
  • Require Term
  • Dependencies Change
  • Context
  • Dirty
  • Invalid
  • Errors
  • Processing
  • Pending Actions
  • Hooks
  • Term
  • Log
  • Error Codes
  • Actions
  • Definition Shorthand

Advanced Usages

  • Grid Usage
  • Form Persistency
  • Undo & Redo
  • Replay Actions
  • Track Actions
  • Server Validation
  • Entity Templates
  • Folder Structure

React Form

  • Installation
  • Overview
  • Form
  • Field
  • Components
  • Layout
  • Demos

Tools

  • Editor
  • DevTools

More Info

  • Test Cofi
  • Packages
  • Why Cofi?
  • Technologies
  • Videos
  • Channels

Contribute

  • Code of Conduct
  • Contributing Guide
  • Contributors

Form

Form component gets as props form model object and resources object that will list all its settings (such as validations, disable term, field dependencies and more) and lifecycle hooks (such as before and after actions, submit, form level validations and dto conversions). In addition, Form component exposes a context object that includes current form model, resources and actions (such as changeValue) to perform on the form. The context can be used within any child component of the Form component (not necessary direct child component).

Props

NameTypeDescription
modelrequired objectModel object that defines fields, validators and more as described in Form Class
resourcesobjectResources object that defines all the handlers that the form model defined as described in Form Class
settingsobjectSettings overrides object as described in Form Class
dataobjectPass data as a prop outside the model object - only when data might change outside the Form component during the app life. On init - Form will applies data to the model and pass the final model to the underline Form class instance, and when data prop reference changes only changeData action called on the underline form instance.
contextobjectPass context as a prop outside the model object - only when context might change outside the Form component during the app life. On init - Form will applies context to the model and pass the final model to the underline Form class instance, and when context prop reference changes only changeContext action called on the underline form instance.

Example

import { Form, Field } from '@cofi/react-form';
import SomeInputText from './my-components/Text.jsx';

const model = {
  id: 'user-form',
  fields: {
    firstName: {
      path: 'firstName',
      label: 'First Name',
      description: 'Enter user first name',
      component: {
        name: 'InputText',
      },
    },
    lastName: {
      path: 'lastName',
      label: 'Last Name',
      component: {
        name: 'InputText',
      },
    },
    data: {
      firstName: 'Roos',
      lastName: 'Geller',
    }
  },
};

const resources = {
  components: {
    InputText: { renderer: SomeInputText },
  }
};

<Form model={model} resources={resources}>
  <h2>User Details</h2>
  <Field id="firstName" />
  <Field id="lastName" />
</Form>

Context

Form provides a context object used by direct and non-direct children components.

Note: In @cofi/react-form - context refer to the data provided by the Form component object, which can be consumed by each underline component (i.e react's context feature). Whereas in @cofi/form context refers to the app data which is stored in the model to serve the form's lifecycle handlers.

Context object

Context object contains:

NameTypeDescription
modelobjectThe current model object. Can be used to pull data for an underline component. For instance, a save button component, should use form data to disable the button in some cases
resourcesobjectThe current resources object
actionsobjectactions object contains a set of function to be called in order to manipulate the from. Full actions docs can be found here
parentobjectparent form context object

For Example:

const reset = () => {
  context.actions.reset();
};

<Button disabled={context.model.invalid || context.model.processing || 
  !context.model.dirty} onClick={reset}>Reset</Button>

Context Consume

In order to use the Form context in child components, components first need to consume Form context.

Example using class component:

import React from 'react';
import { FormContext } from '@cofi/react-form';

class ErrorsSummary extends React.Component {
  static contextType = FormContext;

  render() {
    return (<div>
      <h4>Errors summary:</h4>
      {
          Object.values(this.context.model.fields).map((field, i) => (<ul key={i}>
            { field.errors.map((error, index) => <li key={index}>Error in {field.label}: {error.message}</li>) }
          </ul>))
      }
    </div>);
  }
}

Example using functional component:

import React, { useContext } from 'react';
import { FormContext } from '@cofi/react-form';

const ErrorsSummary = () => {
  const context = useContext(FormContext);

  return (<div>
    <h4>Errors summary:</h4>
    {
        Object.values(context.model.fields).map((field, i) => (<ul key={i}>
          { field.errors.map((error, index) => <li key={index}>Error in {field.label}: {error.message}</li>) }
        </ul>))
    }
  </div>);
};

Context Usage

Components declared inside a Form tag component can define contextType of form, and then use this.context to gain access to the form context.

Examples

  1. Cofi Field component - consumes the form context and interacts with it. It uses the this.context.model to get field's data, this.context.actions.changeValue and this.context.actions.changeState actions to notify the form about a change in the component.
  2. Your custom component. You can define another custom components to interact with the form like SaveButton

Example

import React from 'react';
import Button from '@mui/material/Button';
import { FormContext } from '@cofi/react-form';

export default class SaveButton extends React.Component {
  static contextType = FormContext;

  render() {
    return (<Button disabled={this.context.model.invalid} onClick={this.onSave}></Button>);
  }

  onSave = () => {
    // save data to the server
    serverCallToSaveData(this.context.model.data).then(() => {
      // reset the form to its initial state
      this.context.actions.reset();
    });
  }
}
  1. Pass to custom components any additional data (for example app data) through resources or model objects that are passed via context.

Example

const model = {
  // ...
  appData: {
    user: { /* ... */ },
    currency: 'USD',
  },
}

export default class Currency extends React.Component {
  static contextType = FormContext;

  render() {
    return (<Input
      type="number" 
      value={this.props.value} 
      onChange={this.onValueChange} 
      endAdornment={<Label value={this.context.model.appData.currency}/>}/>);
  }

  onValueChange = (e) => {
    this.props.onValueChange(e.target.value);
  }
}

Utils

createForm

Use createForm function, instead of defining multiple custom inner components using FormContext (like the above SaveButton). The function gets a form definition (model & resources) and returns an HOC which gets a single component. The component should define its context as the FormContext, and then the form's context will be available in the component.

Example

import React from 'react';
import { Field, FormContext, createForm } from '@cofi/react-form';
import Button from '@mui/material/Button';
import form from '../form'; // object of { model, resources }

class MyComponent extends React.Component {
  static contextType = FormContext;

  render() {
    return (<div>
      <h2>User Details</h2>
      <Field id="firstName" />
      <Field id="lastName" />
      <Button disabled={this.context.model.invalid} onClick={this.onSave}></Button>
    </div>);
  }

  onSave = () => {
    // save data to the server
    serverCallToSaveData(this.context.model.data).then(() => {
      // reset the form to its initial state
      this.context.actions.reset();
    });
  }
}

return createForm(form)(MyComponent);

withForm

Use withForm HOC, to auto inject form context as a form prop to a component.

Example

import React, { useCallback } from 'react';
import { Field, withForm, createForm } from '@cofi/react-form';
import Button from '@mui/material/Button';
import service from '../service';
import form from '../form'; // object of { model, resources }

const MyComponent = withForm(({ form }) => {
  const onSave = useCallback(async () => {
    // save data to the server
    await service.serverCallToSaveData(form.model.data);

    // reset the form to its initial state
    await form.actions.reset();
  }, [form]);

  return (<div>
      <h2>User Details</h2>
      <Field id="firstName" />
      <Field id="lastName" />
      <Button disabled={form.model.invalid} onClick={onSave}></Button>
    </div>);
});


return createForm(form)(MyComponent);
← OverviewField →
  • Props
  • Example
  • Context
    • Context object
    • Context Consume
    • Context Usage
  • Utils
    • createForm
    • withForm
cofi
Copyright © 2021 Verizon Media
DOCS
IntroductionForm ClassReact FormReact ComponentsReact Layout
DEMOS
React FormReact ComponentsReact Layout
CONTRIBUTING
Code Of ConductContributing GuideContributorsUsers
CHANNELS
StarGitHubStack OverflowMediumVideos