gcanti / tcomb-validation

Validation library based on type combinators
MIT License
400 stars 23 forks source link

Question about validation options #32

Closed benmonro closed 9 years ago

benmonro commented 9 years ago

I'm using tcomb-form which of course uses tcomb-validation. I have a custom type which I've defined like this:

minLength(length) {
        let type = t.subtype(t.Str, s => s.length >= length, 'minlength');
        type.getValidationErrorMessage = function (value, path, context) {
            console.log('minLength', context);

            if (!type.is(value)) {
                var label = context.fields[path].label;
                return `${label} must be at least ${length} characters long. '${value}' is too short.`
            }
        }

        return type;
    }

The question I'm wondering about is with regards to the context passed into the validate() method. What is the intent of this context object? I noticed in the tcomb-form that it's passing in an object with {path:this.props.ctx.path, context:this.props.context} which seems a bit strange to me because now my form basically looks like this:

<Form options={this.state.options} context={this.state.options} />

Our requirement is to display the label associated w/ the field in the error message, not the path (they often differ in our schema). The reason that feels strange to me is that I'm already giving the form a reference to this.state.options... am I misusing this property?

weitenghuang commented 9 years ago

I'll 2nd @benmonro 's question, and also like to ask why not getValidationOptions() returns the form's option ?

    return {
      path: this.props.ctx.path,
      context: this.props.context || this.props.ctx.context,
      option: this.props.ctx.options
    };
gcanti commented 9 years ago

What is the intent of this context object?

From the README

validate(value, type, [options]) -> ValidationResult

Relevant: https://github.com/gcanti/tcomb-validation/issues/27

th0r commented 9 years ago

@gcanti I think @benmonro want tcomb-form to automatically pass form's options as context to getValidationErrorMessage.

@benmonro But how would you pass extra info there then? For example, current user's locale to translate error messages?

gcanti commented 9 years ago

wants tcomb-form to automatically pass form's options as context to getValidationErrorMessage

Yep, I'm thinking about a solution without breaking changes...

gcanti commented 9 years ago

without breaking changes

One option is merging context with options:

var Type = t.struct({
  name: t.String
});

t.String.getValidationErrorMessage = function (value, path, context) {
  console.log(context); // => {locale: 'it-IT', options: {label: 'My label'}}
};

var options = {
  fields: {
    name: {
      label: 'My label'
    }
  }
};

var App = React.createClass({

  onSubmit(evt) {
    evt.preventDefault();
    var value = this.refs.form.getValue();
    if (value) {
      console.log(value);
    }
  },

  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <t.form.Form
          ref="form"
          type={Type}
          options={options}
          context={{locale: 'it-IT'}}
        />
        <div className="form-group">
          <button type="submit" className="btn btn-primary">Save</button>
        </div>
      </form>
    );
  }

});
weitenghuang commented 9 years ago

@gcanti , i'd like the idea of merging context with options. Which is also what I ask about getValidationOptions()

th0r commented 9 years ago

@gcanti Maybe pass the whole form component instance then? In this case it will be possible to call some of it's helper methods, for example form.getOptions() etc.

gcanti commented 9 years ago

@th0r I agree, probably it's the best bet

gcanti commented 9 years ago

Closing in favour of https://github.com/gcanti/tcomb-form/issues/222