andyhu92 / react-bootstrap4-form-validation

Simple React Components for form validation. Based on HTML5 Constraint validation API and Bootstrap4 style.
https://andyhu92.github.io/react-bootstrap4-form-validation/
MIT License
15 stars 4 forks source link

pattern DOM-property based on regex works very strange #2

Closed abakumov-v closed 6 years ago

abakumov-v commented 6 years ago

Hello!

I have component OperationAmountInput:

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Label, Input } from 'reactstrap'
import { ValidationForm, TextInput, SelectGroup, Checkbox, Radio, BaseFormControl } from 'react-bootstrap4-form-validation'
import { max20DigitsWithPrecision2Regex } from 'constants/regex'

const operationAmountValueErrorMessage = 'Проверьте, корректно ли указана сумма дохода - правильно: "1200", "500.15", "430,20" (после запятой/точки - максимум 2 символа)'
const operationAmountRequiredErrorMessage = 'Укажите сумму операции'

class OperationAmountInput extends Component {
    constructor(props) {
        super(props);
    }

    handleChangeOperationAmount = (e) => {
        const { onChange } = this.props
        if (onChange)
            onChange(e.target.value)
    }

    render() {
        const { id, selectedValue } = this.props
        const title = `${operationAmountRequiredErrorMessage}. После ввода - ${operationAmountValueErrorMessage.toLowerCase()}`
        return (
            <div>
                <Label for={id} hidden>Укажите сумму операции</Label>
                <TextInput type='text' name='text' id={id} placeholder='Сумма операции'
                    value={selectedValue}
                    onChange={this.handleChangeOperationAmount}
                    required
                    pattern={max20DigitsWithPrecision2Regex}
                    //pattern="^[0-9]{0,20}((\,|\.)\d{0,2})?$"
                    errorMessage={{
                        required: operationAmountRequiredErrorMessage,
                        pattern: operationAmountValueErrorMessage,
                    }}
                />
            </div>
        );
    }
}

OperationAmountInput.propTypes = {
    id: PropTypes.string,
    selectedValue: PropTypes.string,

    onChange: PropTypes.func,
};

export default OperationAmountInput;

The TextInput has pattern property which is taken from the file regex.jswith next code:

export const max20DigitsWithPrecision2Regex = "^[0-9]{0,20}((\,|\.)\d{0,2})?$"
export const emailRegex = "^([^@]+)@([\\w\\-\\.]+)\\.(\\w{2,4})$"

When I'm try input invalid values I'm get next results: 1) input "s" - field is valid, but this value is actually wrong: image 2) input "s2" - field is invalid - this it right: image 3) input "123" - field is valid - this is right: image 4) input "123.0" - field is invalid - but this is actually right: image

You can check my regex this: https://regex101.com/r/CYTvuR/1

What I'm doing wrong?

P.S. If I do this:

<TextInput type='text' name='text' id={id} placeholder='Сумма операции'
    value={selectedValue}
    onChange={this.handleChangeOperationAmount}
    required    
    pattern="^[0-9]{0,20}((\,|\.)\d{0,2})?$"
    errorMessage={{
      required: operationAmountRequiredErrorMessage,
      pattern: operationAmountValueErrorMessage,
     }}
/>

then I'm getting error in browser console:

Pattern attribute value ^[0-9]{0,20}((\,|\.)\d{0,2})?$ is not a valid regular expression: Uncaught SyntaxError: Invalid regular expression: /^[0-9]{0,20}((\,|\.)\d{0,2})?$/: Invalid escape
andyhu92 commented 6 years ago

Hello again! Let's solve this issue first: Pattern attribute value ^[0-9]{0,20}((\,|\.)\d{0,2})?$ is not a valid regular expression: Uncaught SyntaxError: Invalid regular expression: /^[0-9]{0,20}((\,|\.)\d{0,2})?$/: Invalid escape.

When you directly putting regex string like pattern="^[0-9]{0,20}((\,|\.)\d{0,2})?$", according to this SO answer, you can use ^[0-9]{0,20}((,|\.)\d{0,2})?$ or simply use [0-9]{0,20}((,|\.)\d{0,2})? as your pattern. Notice I removed the \ before , to resolve the issue, see details in the SO answer.

And when you set regex like this pattern={max20DigitsWithPrecision2Regex}, the JSX renderer removed all slashes because \ is an escape character in strings, and if you inspect the input element, the pattern become pattern="^[0-9]{0,20}((,|.)d{0,2})?$", notice all slashes got removed. So you have to escape \ in your regex and changed to something like "^[0-9]{0,20}((,|\\.)\\d{0,2})?$"

In summary, if you want to reuse the same regex string, escape all slashes, or if you just want to use it once, checked that SO answer make sure you don't have any unnecesarry escaped characters.

abakumov-v commented 6 years ago

@andyhu92 thanks for explanation!