Search code examples
reactjsoffice-ui-fabric

How to adjust valid input check method for SpinButton?


I'm using Office UI Fabric and have a SpinButton implemented. There is some kind of automatic validation that prevents me from using anything apart from numbers as an input. The problem is, I cannot even use the subtract sign. How can I change that?

I tried implementing my own onValidate() method, to cancel out the default one, and even though it's called, it doesn't stop the SpinButton input from being deleted when different from numbers

onValidate={() => console.log('Validate meeee')}

The whole SpinButton looks like this (it's mixed with JS):

static getNumericBox(formField: EntityFormField, onChange: EntityFormControlOnChangeType): JSX.Element {
        let rangeFrom: number = -999999;
        let rangeTo: number = 999999;

        const controlParams = EntityFormHelpers.getNumericControlParams(formField.controlType);

        if (controlParams) {
            rangeFrom = controlParams.rangeFrom;
            rangeTo = controlParams.rangeTo;
        }

        return (
            <React.Fragment key={formField.fieldName}>
                <SpinButton
                    key={formField.fieldName}
                    className={'NumericBox ' + this.getValidationClassName(formField)}
                    label={formField.displayName}
                    labelPosition={Position.top}
                    componentRef={(component: any) => {
                        if (component) {
                            const inputElement = component._input.current;
                            const labelElement = inputElement.parentElement.previousSibling.firstChild;

                            if (formField.validation.isRequired && !formField.displayOnly) {
                                labelElement.setAttribute('required', '');
                            }

                            inputElement.value = formField.value;


                            inputElement.onkeydown = (event: any) => {
                                if (event.target.value.toString().length > rangeTo.toString().length + 1 && event.target.value.toString().length > rangeFrom.toString().length + 1) {
                                    event.preventDefault();
                                    event.stopPropagation();
                                }
                            };


                            inputElement.onkeyup = (event: any) => {
                                let numberValue = Number(event.target.value);
                                if (!numberValue) {
                                    numberValue = formField.validation.isRequired ? Number(0) : null;
                                }
                                onChange(formField.fieldName, numberValue);
                            };
                        }
                    }}

                    onValidate={() => console.log('Validate meeee')}

                    onIncrement={(value: string) => {
                        if (Number(value) + 1 > rangeTo) {
                            formField.value = value;
                        } else {
                            value = String(+value + 1);
                            onChange(formField.fieldName, value);
                            formField.value = value;
                        }
                    }}



                    onDecrement={(value: string) => {
                        if (Number(value) - 1 < rangeFrom) {
                            formField.value = value;
                        } else {
                            value = String(+value - 1);
                            onChange(formField.fieldName, value);
                            formField.value = value;
                        }
                    }}                    

                    value={formField.value}
                    min={rangeFrom}
                    max={rangeTo}
                    step={1}
                    onBlur={(event: any) => {
                        const numberValue = Number(event.target.value);
                        if (numberValue) {
                            if (numberValue < rangeFrom) {
                                onChange(formField.fieldName, rangeFrom);
                            }
                            else if (numberValue > rangeTo) {
                                onChange(formField.fieldName, rangeTo);
                            }
                        }
                    }}
                    disabled={formField.displayOnly}
                />
                {this.getDescriptionControl(formField)}
            </React.Fragment>);
    }

Solution

  • Problem is in the onkeyup methods. Everything kept overwriting as soon as a single key was pressed. A bit of fiddling around fixed the whole thing.

    In case anyone is interested, here's the final and working state:

    static getNumericBox(formField: EntityFormField, onChange: EntityFormControlOnChangeType): JSX.Element {
            let rangeFrom: number = -999999;
            let rangeTo: number = 999999;
    
            const controlParams = EntityFormHelpers.getNumericControlParams(formField.controlType);
    
            if (controlParams) {
                rangeFrom = controlParams.rangeFrom;
                rangeTo = controlParams.rangeTo;
            }
    
            return (
                <React.Fragment key={formField.fieldName}>
                    <SpinButton
                        key={formField.fieldName}
                        className={'NumericBox ' + this.getValidationClassName(formField)}
                        label={formField.displayName}
                        labelPosition={Position.top}
                        componentRef={(component: any) => {
                            if (component) {
                                const inputElement = component._input.current;
                                const labelElement = inputElement.parentElement.previousSibling.firstChild;
    
                                if (formField.validation.isRequired && !formField.displayOnly) {
                                    labelElement.setAttribute('required', '');
                                }
    
                                inputElement.value = formField.value;
    
    
                                inputElement.onkeydown = (event: any) => {
                                    if (event.target.value.toString().length > rangeTo.toString().length + 1 && event.target.value.toString().length > rangeFrom.toString().length + 1) {
                                        event.preventDefault();
                                        event.stopPropagation();
                                    }
                                };
    
                                inputElement.onkeyup = (event: any) => {
                                    const isValidKeyCode =
                                        event.which === KeyCodes.up ||
                                        event.which === KeyCodes.down ||
                                        event.which === KeyCodes.left ||
                                        event.which === KeyCodes.right ||
                                        event.which === KeyCodes.backspace ||
                                        event.which === KeyCodes.del ||
                                        event.which === KeyCodes.a && event.ctrlKey ||
                                        event.which === KeyCodes.x && event.ctrlKey ||
                                        event.which === KeyCodes.c && event.ctrlKey ||
                                        event.which === KeyCodes.v && event.ctrlKey ||
                                        event.which === KeyCodes.subtract ||
                                        event.which === KeyCodes.dash;
    
                                    const isValidNumberKeyCode = (
                                        (event.which >= KeyCodes.zero && event.which <= KeyCodes.nine) ||
                                        (event.which >= KeyCodes.zero_numpad && event.which <= KeyCodes.nine_numpad)
                                    );
    
                                    if (!isValidKeyCode && !isValidNumberKeyCode) {
                                        onChange(formField.fieldName, null);
                                    } else if (event.target.value === "-") {
                                        return;
                                    } else {
                                        let numberValue = parseInt(event.target.value);
                                        if (!numberValue && numberValue !== 0) {
                                            numberValue = formField.validation.isRequired ? +"0" : null;
                                        }
                                        onChange(formField.fieldName, numberValue);
                                    }
    
                                };
                            }
                        }}
    
                        onIncrement={(value: string) => {
                            if (Number(value) + 1 > rangeTo) {
                                formField.value = value;
                            } else {
                                value = String(+value + 1);
                                onChange(formField.fieldName, value);
                                formField.value = value;
                            }
                        }}
    
    
    
                        onDecrement={(value: string) => {
                            if (Number(value) - 1 < rangeFrom) {
                                formField.value = value;
                            } else {
                                value = String(+value - 1);
                                onChange(formField.fieldName, value);
                                formField.value = value;
                            }
                        }}                    
    
                        value={formField.value}
                        min={rangeFrom}
                        max={rangeTo}
                        step={1}
                        onBlur={(event: any) => {
                            const numberValue = Number(event.target.value);
                            if (numberValue) {
                                if (numberValue < rangeFrom) {
                                    onChange(formField.fieldName, rangeFrom);
                                }
                                else if (numberValue > rangeTo) {
                                    onChange(formField.fieldName, rangeTo);
                                }
                            }
                        }}
                        disabled={formField.displayOnly}
                    />
                    {this.getDescriptionControl(formField)}
                </React.Fragment>);
        }