akirahin
akirahin

Reputation: 25

Updated Value of custom Input in React-Admin not getting submitted in edit form

I am trying to build an Edit form in React-Admin with a custom input field called 'UserRolesSelect' which displays a list of roles from an separate roles endpoint with the roles of the current user as selected. However, while making the edit request the values of the custom input are not updated in the form data. I have provided sample responses from both the above mentioned endpoints.

// sample response for getting user details by ID
const user = {
id:1,
name:'User1',
email:'[email protected]',
created_at:2020-04-01T10:43:36.000000Z,
roles:[{id:1,name:'User'}]
};

// sample response of getting roles list
const roles = [
{id: 1,
name: 'user'},
{id: 2,
name: 'admin'}
]


const UserRolesSelect = ({ source, record }) => {
    const [selectedRoles, setRoles] = useState([]);

    useEffect(() => {
        const userRoles = record.roles.map(role => role.id);
        setRoles(userRoles);
    }, []);

    const { data, loading: rolesLoading, error: rolesError } = useQuery({
        type: 'getList',
        resource: 'roles',
    });

    if (rolesLoading) return <Loading />;
    if (rolesError) return <Error />;
    if (!data) return null;

    const rolesList = data.map(role => <MenuItem key={role.id} value={role.id} selected={selectedRoles}>
        {role.name}
    </MenuItem>);

    const handleChangeMultiple = event => {
        const { value: role } = event.target;
        const value = [...role];
        setRoles(value);
    };

    return <Select
        value={selectedRoles}
        onChange={handleChangeMultiple}
        multiple
    >
        {rolesList}
    </Select>
};

const UserEdit = props => {
    return <Edit {...props}>
            <SimpleForm >
                <TextInput source="name" />
                <TextInput source="email" />
                <UserRolesSelect source="roles"/>
            </SimpleForm>
        </Edit>
};

Upvotes: 1

Views: 8545

Answers (2)

Kia Kaha
Kia Kaha

Reputation: 1801

Had the exact same situation - takes a little time to start thinking in react-admin style but then it looks beautiful. I suggest the following strategy:

Inside your user object save an array of the roles id's. (Optionally on the server I attach an array with the role's objects as well for convenience)

const user = {
  id:1,
  name:'User1',
  email:'[email protected]',
  created_at:2020-04-01T10:43:36.000000Z,
  roles:[{id:1,name:'User'}, {id:2,name:'Manager'}],
  rolesIds:[1, 2]
};

Then what you should use is the following combination:

 <ReferenceArrayInput label="Roles" reference={"roles"} source="rolesIds">
         <SelectArrayInput optionText={roleRender} />                    
 </ReferenceArrayInput> 

...
    const roleRender = role => role.name;

In this way you are gathering the set of choices from the roles endpoint and mark as already selected what is in your object's array rolesIds.

Upvotes: 0

Fran&#231;ois Zaninotto
Fran&#231;ois Zaninotto

Reputation: 7355

Your custom element updates its internal state but doesn't communicate the changes to the outside world. To change the form values, you must either use the <Field> component, or the useField() hook - both are coming from react-final-form, which is the Form framework used internally by react-admin.

For your example, that would give something like:

const UserRolesSelect = ({ source }) => {
    const { input, meta } = useField(source);
    // the current value is in input.value
    // the callback to change the value is in input.onChange
    ...
};

The react-admin documentation has a section explaining in details how to write your custom forms, I suggest you start by reading it.

https://marmelab.com/react-admin/Inputs.html#writing-your-own-input-component

Also, it seems you are trying to recreate a feature that already exists in react-admin. See the documentation for ReferenceArrayInput.

https://marmelab.com/react-admin/Inputs.html#referencearrayinput

Upvotes: 3

Related Questions