Home

Awesome

react-input-message

A small, completely unopinionated way, to display messages next to inputs based on events. Helpful for displaying input validation messages.

There is a frustrating trend in javascript form validation solutions that couple the view concerns of a form (hiding/showing of messages) with some specific data layer model, or abstraction. This often means that in order to use a form validator you also need to use a specific js schema validator, or are tied into using a specific validation library. react-input-message strives to provide just a solution to quickly and easily annotating form controls without requiring that you use a specific validation or data schema library.

Install

npm i -S react-input-message

Depends on the Promise global object Most browsers and versions of node already support this but for lder browsers please provide a polyfill

Use

You render your inputs as you normally would, except that you wrap them inside a MessageTrigger component which will watch its child input for events.

render(){
  var messages = {
    name: ['name is required']
  }

  return (
    <MessageContainer
      messages={messages}
      onValidationNeeded={handleValidationRequest}
    >
      <form>
        <div>
          <label>Name</label>
          {/* the `events` prop tells the MessageContainer what
            * events to trigger a `onValidationNeeded` handler for */}
          <MessageTrigger for='name' events={[ 'onChange', 'onBlur']}>
            <input type='text'
              value={this.state.name}
              onChange={handleChange}
            />
          </MessageTrigger>

          {/* A `Message` Component will display field specific
            * messages (as provided by the `messages` prop) */}
          <Message for='name'/>
        </div>

         {/* This `MessageTrigger` will trigger a `onValidationNeeded` event for the entire
           * container, or just a specific group. Notice the lack of a `for` prop. */}
        <MessageTrigger events={['onClick']}>
          <button type='button'>Check</button>
        </MessageTrigger>
      </form>
    </MessageContainer>
  )

react-input-message exports 3 simple components and a utility class:

MessageContainer

Props

onValidationNeeded({ fields: array<string>, type: string, args: ?any })

A handler that fires for each MessageTrigger component with a for prop

messages: object

A hash of unique names (for prop values) and either a string, or an array of strings.

passthrough: bool

Allow a nested Container to receive the messages of a parent container.

mapNames(names : array<string>) -> array<string>

A mapping operation on the inner container names, to the outer container.

mapMessages(messages: object) -> object

A mapping operation on the outer container messages, to the inner container messages.

MessageTrigger

A MessageTrigger is a component that listens to its child for events and triggers a validation event in the containing MessageContainer. Generally this will be an input component.

for: string | array<string

A unique name or array of names. The for prop uniquely identifies what onValidationNeeded is being triggered for. for values should map to possible messages keys

group: string | array<string | '@all'

An arbitrary group name that allows inputs to be triggered together. If a for prop is specified then the group prop identifies the trigger as a member of that group. If the for prop is excluded then the group prop identifies which group to trigger validation for, use the special value '@all' to trigger validation for every known name.

inject(child: ReactElement, messages: object) -> object

A function that is passed the child, active boolean. returns an object of props to add to the child.

function inject(child, isActive){
  return {
    className: classnames(child.props.className, {
      'message-error': isActive
    })
  }
}

<MessageTrigger inject={inject}/>

events: string | array<string> default: 'onChange'

An array of prop handlers that the MessageTrigger will list on, and trigger a onValidationNeeded event in the Container

Leaving the for prop undefined is a good way to create buttons that can trigger validation for a group (or the entire container), but will not be the subject of a validation itself.

Message

Displays the actual messages for a field, the default implementation just concats the messages together with , but you can easily create custom Message components with the connectToMessageContainer() helper

connectToMessageContainer(componentClass, options: object) -> MessageListener

A higher order component that wraps the passed in componentClass and injects container statue as props:

Options {
  methods: array<string>, // methods to passthrough
  resolveNames: (
    props:object,
    container: messageContainerContext
  ) -> array<string>,

  mapMessages: (
    messages: object,
    names: array<string>,
    props:object,
    container: messageContainerContext
  ) -> object,
}

new Validator(validationFn: (name: string, context: ?any) -> bool)

A very simple basic form validator class, to help manage input error state, use is completely optional. It is designed to nicely hook up to the MessageContainer component without being tightly coupled to it.

validate(names: array<string>, ...context: ?any) -> Promise<bool>

Returns a promise that resolves with the valid state of the field. You can validate multiple fields by passing an array. You can also pass in a context object which will be passed to the validationFn

validator.isValid(names: array<string>) -> bool

Checks if a name is currently in an error state

errors(names: array<string>) -> object

Returns a hash of errors for a set of names; you can pass this object directly to a MessageContainer messages prop

let model = { name: '' }

// you instantiate the object with a function that determines if a field is valid or not
let validator = new Validator(function(fieldName, context){
  let isValid = !!context.model[fieldName]

  if (isValid === false)
    return [ fieldName + ': is required!']
})

validator.validate('fieldName', { model: model })
  .then(function(isValid){
    //do something
  })

validator.isValid('fieldName')