Redux-form problems --> normalize events and value property for input components

UI Components for React
Post Reply
rodriguezc
Posts: 5
Joined: 03 Jul 2012, 11:28
Location: Switzerland

05 Jul 2018, 08:32

Hi,

I had some problems with the integration of PrimeReact and Redux Form.

Redux form injects events like onChange on input components in order to synchronize the form state with the input and doing other stuffs like validation. It's like a two-way data binding.

Here is the spec of redux form:
https://github.com/erikras/redux-form/b ... mponent.md
https://github.com/erikras/redux-form/b ... i/Field.md

It is specified that in order to work properly, the custom component needs at least to implement "value" and "onChange" in a standard way.
input.onChange(eventOrValue) : Function
A function to call when the form field is changed. It expects to either receive the React SyntheticEvent or the new value of the field.
Some react input components:
- don't implements onChange (like Chips, Editor )
-don't have a "value" property (like Checkbox)
-don't send a "standard" event object (often the value of the object is in e.value property)

I made a quick and dirty HOC in order to fix all prime react input problems that I found with redux form :

Code: Select all


import React from 'react';

const resolveClassName = (field) => {
    if (field.meta.touched && field.meta.error) {
        return 'ui-state-error';
    }
    return '';
};


const removeElementInArray = (array, elementsToRemove) => (array.filter(item => elementsToRemove.indexOf(item) < 0));

const onChangeEvent = (e, field) => {
    if (!e.target) {
        if (e.htmlValue != undefined) {
            e.target = { value: e.htmlValue };
        }
        else if (e.checked != undefined) {
            e.target = { value: e.checked };
        }
        else if (e.value != undefined) {
            e.target = { value: e.value };
        }
    }

    field.input.onChange(e.target ? e.target.value : null);
};

const ultimaReduxFormField = ComposedComponent => (field) => {
    const inputType = ComposedComponent.name;
    const attributesToAdd = {};
    if (inputType.indexOf('Chips') > -1) {
        attributesToAdd.onAdd = e => field.input.onChange(field.input.value.concat(e.value));
        attributesToAdd.onRemove = e => field.input.onChange(removeElementInArray(field.input.value, e.value));
    }
    if (inputType === 'Checkbox' || inputType === 'InputSwitch') {
        attributesToAdd.checked = field.input.value;
    }

    const isCheckbox = inputType === 'Checkbox';
    const isCalendar = inputType === 'Calendar';
    const isEditor = inputType === 'Editor';
    const isTriStateCheckbox = inputType === 'TriStateCheckbox';
    const isToggleButton = inputType === 'ToggleButton';


    if (isTriStateCheckbox) {
        if (field.input.value === '') {
            field.input.value = null;
        }
    }


    if (isToggleButton) {
        return (
            <span>
                <span className="md-inputfield">
                    <span className="ui-inputwrapper-filled" />   
                    <label>{field.label}</label>
                </span>
                <ComposedComponent
                    {...field}
                    onChange={e => onChangeEvent(e, field)}
                    checked={field.input.value}
                />
                {field.meta.touched && field.meta.error &&
                    <span className="md-inputfield">
                        <div className="ui-message ui-messages-error ui-corner-all">
                            {field.meta.error}
                        </div>
                    </span>
                }
            </span>
        );
    } else if (isCheckbox) {
        return (
            <div>
                <ComposedComponent
                    {...field}
                    onChange={e => onChangeEvent(e, field)}
                    checked={field.input.value}
                />
                <label htmlFor={field.inputId} style={{ cursor: 'pointer' }}>
                    {field.label}
                </label>
            </div>
        );
    } else if (isCalendar) {
        return (
            <span>
                <span className="md-inputfield">
                    <span className="ui-inputwrapper-filled" />  
                    <label>{field.label}</label>
                </span>
                <ComposedComponent
                    className={resolveClassName(field)}
                    value={field.input.value}
                    {...field}
                    onChange={e => onChangeEvent(e, field)}
                    {...attributesToAdd}
                />
                {field.meta.touched && field.meta.error &&
                    <span className="md-inputfield">
                        <div className="ui-message ui-messages-error ui-corner-all">
                            {field.meta.error}
                        </div>
                    </span>
                }
            </span>
        );

    } else if (isEditor) {
        return (
            <span>
                <span className="md-inputfield">
                    <span className="ui-inputwrapper-filled" /> 
                    <label>{field.label}</label>
                </span>
                <ComposedComponent
                    className={resolveClassName(field)}
                    value={field.input.value}
                    {...field}
                    onTextChange={e => onChangeEvent(e, field)}
                    {...attributesToAdd}
                />
                {field.meta.touched && field.meta.error &&
                    <span className="md-inputfield">
                        <div className="ui-message ui-messages-error ui-corner-all">
                            {field.meta.error}
                        </div>
                    </span>
                }
            </span>
        );

    }
    return (
        <span>
            <span className="md-inputfield">
                <span className="ui-inputwrapper-filled" />
                <label>{field.label}</label>
            </span>
            <ComposedComponent
                className={resolveClassName(field)}
                {...field.input}
                {...field}
                onChange={e => onChangeEvent(e, field)}
                {...attributesToAdd}
            />
            {field.meta.touched && field.meta.error &&
                <span className="md-inputfield">
                    <div className="ui-message ui-messages-error ui-corner-all">
                        {field.meta.error}
                    </div>
                </span>
            }
        </span>
    );
};


export default ultimaReduxFormField;

If you make a global rewrite of prime react, it could be great to take it in account ;)

Thanks!

Diego Morais
Posts: 3
Joined: 07 Jan 2011, 19:00

25 Jan 2019, 19:08

Hi, any new on this issue? Have you received any feedback?

Same issue here.

NuveenRATechTeam
Posts: 2
Joined: 07 Apr 2020, 21:53

20 Apr 2020, 23:10

Why don't all of the controls return the same React SyntheticEvent?

I've tried using the above HOC fix and it's not working for me. I'm not using Redux, just the React hooks. I found the below snippit (https://upmostly.com/tutorials/using-cu ... lify-forms), but the Calendar component errors our on "event.persist()" because it's not a proper Synthetic event. Anyone have any ideas?

Code: Select all

import React, { useState } from 'react';

const useEditForm = (callback) => {
    const [formInputs, setInputs] = useState({});
    const handleSubmit = (event) => {
      if (event) {
        event.preventDefault();
      }
      callback();
    }
    const handleInputChange = (event) => {
      event.persist();
      setInputs(inputs => ({...inputs, [event.target.name]: event.target.value}));
    }
    return {
      handleSubmit,
      handleInputChange,
      formInputs
    };
  }
  export default useEditForm;
--- EDIT ---
I figured it out enough. First, I didn't have "name" attributes on the elements. Second, I just put an "if" check around the event.persist() call for those non-standard PrimeReact components.

Code: Select all

      if(event.persist){
        event.persist();
      }

chrishj
Posts: 229
Joined: 11 Jul 2011, 21:58
Location: England, Lancashire
Contact:

27 Apr 2020, 17:21

Is there a roadmap to make these controls compatible to redux-form.Field?
PrimeReact: 9.6.0
NextJs: 13.4.12
Theme Apollo v9.0
Database pg 8.8.0
react-hook-form: 7.38.0

Post Reply

Return to “PrimeReact”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 4 guests