kettanaito / react-advanced-form

Functional reactive forms. Multi-layer validation, custom styling, field grouping, reactive props, and much more.
https://redd.gitbook.io/react-advanced-form
MIT License
217 stars 24 forks source link

Expected fieldProp not correctly return correct value #392

Closed jetpack3331 closed 5 years ago

jetpack3331 commented 5 years ago

Environment

What

Current behavior

When trying write to the input value 45 with minValue and maxValue it incorrectly returns expected value from fieldProps

This is returned in onChange when i write 45

{
  "valid": false,
  "invalid": false,
  "validating": false,
  "validated": false,
  "validatedSync": false,
  "validatedAsync": false,
  "validSync": false,
  "validAsync": false,
  "errors": [
    "Some error"
  ],
  "fieldPath": [
    "fix_me_pls"
  ],
  "initialValue": "",
  "value": "45",
  "valuePropName": "value",
  "focused": true,
  "pristine": false,
  "touched": true,
  "required": false,
  "skip": false,
  "pendingAsyncValidation": null,
  "expected": false,
  "reactiveProps": {},
  "type": "number",
  "name": "fix_me_pls",
  "minValue": 10,
  "maxValue": 500,
  "placeholder": "Some placeholder",
  "disabled": false,
  "controlled": false
}

Expected behavior

When minValue == 10 and maxValue === 500 it should return on pressing value 4 false then on pressing 5 (together 45) it should return true

Why

I did console.log on this line: https://github.com/kettanaito/react-advanced-form/blob/7c2b609f93785f23b68efa8dc8b0e393d356d33c/src/utils/reduceWhile.js#L39

And on pressing one number it returns:

Object { expected: null }
Object { expected: null }
Object { expected: null }
Object { expected: false }

then on pressing 5 it returns:

Object { expected: null }
Object { expected: null }
Object { expected: null }
Object { expected: true }

How

handleCustomChange({ fieldProps }) {
    const { value, expected } = fieldProps

    /**
     * on pressing "4" to the input it returns 4 and true
     * on pressing "5" to the input it returns 45 and false
    */
    console.log(value, expected)
}

render() {
    const minValue = "10";
    const maxValue = "500";

    return (
        <Form>
            <Input
                type="number"
                name="fix_me_pls"
                minValue={ minValue }
                maxValue={ maxValue }
                placeholder="Some placeholder"
                onChange={ this.handleCustomChange }
            />
        </Form>
    )
}
kettanaito commented 5 years ago

Hi. Thanks for reporting an issue.

Could you please elaborate on which property in the field state do you expect to be set as true/false depending on the value?

Value updates must be working properly as the nextValue is taken from the event.target originating from DOM. This means:

What I think you expect is for valid/invalid to reflect the validity of a field based on the minValue/maxValue. In that case you need to declare such vlaidation rule. The library does no guessing in what your validation logic is supposed to be, and neither does HTML5 spec of ranged inputs (values out of range are forbidden to enter, if I'm not mistaken).

So, I suggest the following:

const validationRules = {
  type: {
    // Create a validation rule for [type="range"] custom type fields
    range: ({ value, fieldProps }) => {
      // Declare a correct predicate (untested code below)
      return value >= fieldProps.minValue && value <= fieldProps.maxValue
    }
  }
}

// fields/Range.js
const RangeInput = () => {}

export default createField({
  mapPropsToField: ({ fieldRecord, props: { minValue, maxValue }) => ({
    ...fieldRecord,

    // Set "fieldProps.type" to equal "range"
    type: 'range',

    // Propagate custom values into field state
    minValue,
    maxValue,
  })
})(RangeInput)

Don't forget to propagate validation rules. Read about applying validation in the docs.

This should get your started in implementing such range input.

Please let me know whether this suggestion helped.

jetpack3331 commented 5 years ago

Thx @kettanaito but i have a problem if i have onChange handler on the Input.

  1. I can't use the type="range"
  2. If you have example:
    <Field onChange={({ fieldProps }) => console.log(fieldProps.expected)} // return false if i enter 45

    there is a problem because validation rules passed but expected value is returned as false but here https://github.com/kettanaito/react-advanced-form/blob/7c2b609f93785f23b68efa8dc8b0e393d356d33c/src/utils/reduceWhile.js#L39

It looks like it should return true. So i assume that somewhere is error

kettanaito commented 5 years ago

Could you please set up a minimum reproduction sandbox and attach a link to it?

there is a problem because validation rules passed

This means you do have some validation rule declared. It would be crucial to include in the example too. I could try to debug it once I've got a scenario. Thanks.

jetpack3331 commented 5 years ago

@kettanaito also

Hi. Thanks for reporting an issue.

Could you please elaborate on which property in the field state do you expect to be set as true/false depending on the value?

Value updates must be working properly as the nextValue is taken from the event.target originating from DOM. This means:

* When you press "4", `fieldProps.value` equals `'4'`

* When you consequentially press 5, `fieldProps.value` equals `'45'`

What I think you expect is for valid/invalid to reflect the validity of a field based on the minValue/maxValue. In that case you need to declare such vlaidation rule. The library does no guessing in what your validation logic is supposed to be, and neither does HTML5 spec of ranged inputs (values out of range are forbidden to enter, if I'm not mistaken).

So, I suggest the following:

const validationRules = {
  type: {
    // Create a validation rule for [type="range"] custom type fields
    range: ({ value, fieldProps }) => {
      // Declare a correct predicate (untested code below)
      return value >= fieldProps.minValue && value <= fieldProps.maxValue
    }
  }
}

// fields/Range.js
const RangeInput = () => {}

export default createField({
  mapPropsToField: ({ fieldRecord, props: { minValue, maxValue }) => ({
    ...fieldRecord,

    // Set "fieldProps.type" to equal "range"
    type: 'range',

    // Propagate custom values into field state
    minValue,
    maxValue,
  })
})(RangeInput)

Don't forget to propagate validation rules. Read about applying validation in the docs.

This should get your started in implementing such range input.

Please let me know whether this suggestion helped.

Also this didn't helped.

I will have to prepare some minimum repo. Do you have some prepared where i can just edit stuff?

kettanaito commented 5 years ago

You can use any of the Codesandbox projects with react-advanced-form. I may suggest this one: Synchronous validation. Let me know the results. Thanks.

kettanaito commented 5 years ago

Let me know if the issue is still reproducible. Closing for now.