Extending

Creating a skin

The inputs and auxiliary elements are created using a set of components. The mapping can be set all together by overriding the skin.

You can take a look at skin.js and components/index.js from any skin to have a glimpse.

There’s an entry in the skin object for every field type. The value of the entry is an object with two attributes like in this example:

string: {
  component: Input,
  props: {
    inputComponent: 'input'
  }
},

component

The React component used to render the whole HTML for the input, including label and any other wrappers. For the Bootstrap skin the Input component is used to do the common tasks:

string: {
  component: Input
}

The component is also in charge of the field connection with redux form store (the Field component).

props

The props value can be an object or a function depending on the flexibility needed.

Object

Props merged to component’s default:

props: {
  inputComponent: 'input',
  type: 'number'
}

Function

Function that takes the component’s intended props and returns component’s final props:

props: props => {
  return {
    ...props,
    inputComponent: Radio,
    children: mapRadioOptions(props)
  }
}

Overriding

You can override (or add) specific types or the whole set.

setSkin(skin)

Sets the whole skin at once.

Arguments:
  • skin (object) – Whole skin description
addSkinType(typeName, rendering)

Sets the rendering for a specific schema type.

Arguments:
  • typeName (string) – Type name as it appears in the schema specification.
  • rendering (skinTypeMap) – Object with the rendering specification.

Skin component

Every input component expects at least these props:

Prop Type Use
children element Passed to inputComponent
name string ReduxForm field name
fieldSchema object Schema specification for the field
schemaTypeName string (required) Name of the schema that contains the field
inputComponent element Component used to render the input
type string Passed to inputComponent
typeValidator function Validator for the type. See “Override or add type validation”

There are also other props passed depending on current implementation of renderInput, the function in charge of choosing the component and render it.

typeValidator is needed to avoid an error when validating field’s type. If unsure provide value => false.

Form component

The form component is different in the sense that it’s not rendered after a type. Instead, every form renders a form component in case the UI library requires special form wrapping.

InputWrap

It’s a common component used to create all the input structure, including wrappers. You can use it to avoid boilerplate. The final input component used (taken from inputComponent prop) will be a decorated Field.

Prop Type Use
children node (optional) You can use InputWrap to… wrap.
name string Field name
inputWrapper element Wrapper for the input. See below for props.
inputComponent element Component receiving the input. See below for props.
config object Form configuration
elementOnly boolean (optional) Asks the wrapper to not decorate the input
inline boolean (optional) Passed to wrapper
type string (optional) Passed to input
schemaTypeName string Name of the schema as created
onKeyDown function (optional) Passed to input
onKeyPress function (optional) Passed to input
labelOverride string (optional) Passed as label to wrapper instead of
meta object ReduxForm’s meta

The props passed to the wrapper component (inputWrapper)

Prop Type Use
label string Text use as label
required boolean Field is marked as required
horizontal boolean Taken from config
inline boolean Taken from InputWrap props
errorMessage string To print in red
warningMessage string To print in orange
elementOnly boolean Skip wrappings

The props for the input component are different depending if the inputComponent is a string, like 'input' or a React component.

Common input props

Prop Type Use
type string From InputWrap
onKeyDown function From InputWrap
onKeyPress function From InputWrap
autoComplete string Always 'off'
placeholder string From InputWrap

Native component (ie. 'input')

For a component like that only ReduxForm input object is passed.

Class component (ie. MySlider)

Extra props are passed:

Prop # Type # Use input # object # From decorated Field meta # object # From decorated Field config # object # From InputWrap from Autoform autoFocus` # boolean # From ``InputWrap schemaTypeName` # string # From ``Schema

Rendering

To feed InputWrap with the needed props, two functions can be used:

renderInputs(params)

Renders the inputs to make the schema work.

Arguments:
  • params (object) –
  • params.schema (Schema) – Schema instance
  • params.config (object) – Rendering configuration
  • params.config.arrayMode (string) – ‘panels’ or ‘table’
  • params.config.horizontal (boolean) – Labels above inputs
  • params.rest (object) – Props passed to each input
Returns:

array – React elements with the form and inputs.

renderInput(params)

Renders a single field.

Arguments:
  • params (object) –
  • params.field (string) – Name of the field
  • params.fieldSchema (object) – Schema specification for the field
  • params.parent (string) – Prefix of the field name
  • params.schemaTypeName (string) – Name of the schema (first argument while instantiating a schema)
  • params.config (object) – Form configuration
  • params.rest (object) – props passed to the component

Write your own validators

Suppose you have a field schema and you want to add a custom validator:

const vehicles = new Schema('vehicles', {
  numberOfWheels: {
    type: 'number',
    isEven: true
  }
})

To add the validation, use

addValidator(validationName, validation)

Adds a test creator to the testFactory table, that way you can use your own custom validations.

Arguments:
  • validationName (string) – The validation name for the test being created.
  • validation (validatorConstructor) – Function that takes the entry and creates a validator to be used later.

That is, validation is a function that returns a function. Outer one creates the validator and the inner one is the validator itself.

The validator returns true when validation doesn’t pass. It can also return a translatable object or a direct message.

To implement the isEven test using ES6 arrow functions:

import { addValidator } from 'redux-form-auto'

addValidator('isEven', entry =>
  value => {
    const expected = entry.isEven ? 0 : 1

    return isNaN(value) || value % 2 != expected
  }
)

Because the validator takes advantage of the closure from the constructor, it’s useful to write both in that cascade manner.

You can construct translatable objects using translatable(). See Translatable objects

Override or add type validation

To avoid type errors as false positives you can change its behaviour in two ways:

  • Adding typeValidator in the component definition when you create it.
  • Calling addSpecialTypeValidator specifying the field and the validation.

The validator has the same signature as others validators: Will receive the field’s value and returns false for “valid”.

addSpecialTypeValidator(type, validator)

Adds a special type validation

Arguments:
  • type (string) – Type validated
  • validator (function) – value => true_to_fail validator