Skip to content

Conversation

Fronix
Copy link
Contributor

@Fronix Fronix commented Aug 26, 2025

Reasons for making this change

Fixed #4721 that broke multiselect fields onchange by duplicating the path with slice()

This fixes #4733

Checklist

  • I'm updating documentation
  • I'm adding or updating code
    • I've added and/or updated tests. I've run npx nx run-many --target=build --exclude=@rjsf/docs && npm run test:update to update snapshots, if needed.
    • I've updated docs if needed
    • I've updated the changelog with a description of the PR
  • I'm adding a new feature
    • I've updated the playground with an example use of the feature

@Fronix Fronix changed the title fix: path duplication fix #4733 path duplication Aug 26, 2025
@codeliner
Copy link

I stumbled across the same issue today. @Fronix I think your fix could cause unwanted side effects. When I have an object with a property "prop" which again is an object with a property "prop", your fix would make it impossible to change the value for "prop.prop". At least that's my understanding of the method.

While debugging the issue, I identified the ArrayField.onSelectChange method to be problematic:

onChange(value, [name], undefined, idSchema && idSchema.$id);

If you look at other methods of ArrayField, you can see that an empty path array is provided to onChange with a comment that the appropriate path is added by onChange:

// Copy index will pass the empty `path` array to the onChange which adds the appropriate path

I'd say onSelectChange needs to do the same (pass an empty path array to onChange). However, I don't know if this would break other use cases ...

@Fronix
Copy link
Contributor Author

Fronix commented Aug 26, 2025

@codeliner

That is true, I didn't think of the case of prop.prop. One quick way I tested (and worked) is this
https://github.com/rjsf-team/react-jsonschema-form/blob/357306523d1420e510a85ff76cdc84e9d584b638/packages/core/src/components/fields/ArrayField.tsx#L419C1-L424C5

Changing to this

  /** Callback handler used to change the value for a checkbox */
  onSelectChange = (value: any) => {
    const { onChange, idSchema } = this.props;
    // To ensure it's possible to change prop.prop.... by extracting the correct path from the idSchema.$id
    const path = idSchema && idSchema.$id ? idSchema.$id.split('_').slice(1) : [];
    onChange(value, path, undefined, idSchema && idSchema.$id);
  };

and then keeping this would allow for nested properties, with the same name, to work

      if (!changePath.length || changePath[0] !== name) {
        changePath.unshift(name);
      }

I could also just be very unfamiliar with the inner workings, and there might be a much better way to do it but without knowing the real path of the properties, it feels impossible to build the path as you go and then using unshift without breaking non nested objects.

Edit: There can also be an argument to not support prop.prop.prop ... behaviour and throw an error if it occurs. But again, we probably need one of the maintainers to chime in here

const changePath = Array.isArray(path) ? path.slice() : [];
changePath.unshift(name);
// Ensure we are not duplicating the path
if (!changePath.length || changePath[0] !== name) {
Copy link
Member

@heath-freenome heath-freenome Aug 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there is similar code in ArrayField might I consider making a similar change there? AND there is one problem with this fix...if there were nested properties with the same name, this would cause problems with incorrect nesting.

Can you provide a codesandbox example where you are seeing this problem so that we can better understand why this failed for you.

I.e.

{
  "type": "object",
  "properties": {
    "foo": {
      "type": "object",
      "properties": {
        "foo": {
          "type": "string",
        }
      }
    }
  }
}

import set from 'lodash/set';
import unset from 'lodash/unset';
import Markdown from 'markdown-to-jsx';
import { Component } from 'react';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move this back to the top? We prefer react imports to be first

@heath-freenome
Copy link
Member

@Fronix Thanks for trying... I just did some debugging myself and made the much simpler fix #4737

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multiselect onChange not changing values

3 participants