Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Required property is not set if field is conditionally required #1390

Open
sasmangulyan-vineti opened this issue May 31, 2019 · 10 comments
Open

Comments

@sasmangulyan-vineti
Copy link

Describe the bug
When making the specific field required based on some condition the required property is still false.

To Reproduce
Steps to reproduce the behavior:

  1. Schema contains something conditional
    { type: "object", properties: { b: { type: "boolean" }, c: { type: "string", minLength: 1 } }, if: { properties: { b: { enum: [false] } } }, then: { required: ["c"] } }
  2. When making the "b" from true to false (for example checking and unchecking the box), required property of ''c'' which has the renderer of MaterialInputControl will not be changed and will remain false.

Expected behavior
After a conditional action the required property of MaterialInputControl to become true.

Browser (please complete the following information):

  • Chrome 74.0.3729.157 (Official Build) (64-bit)
  • Firefox 66.0.5 (64-bit)

Used Setup (please complete the following information):

  • react
  • material
@eneufeld
Copy link
Member

eneufeld commented Jun 1, 2019

Thank you for your report.
I just double checked, the if/then/else is working fine.
We don't set the required property at all in the renderers.
I adapted the title because of this.

We happily would accept a contribution for this.

@eneufeld eneufeld changed the title Required is false when making specific field required based on condition Required property is not set if field is required Jun 1, 2019
@sdirix sdirix added this to the 2.4.0 milestone Aug 23, 2019
@sdirix sdirix modified the milestones: 2.4.0, 2.5.0 Mar 12, 2020
@sdirix sdirix modified the milestones: 2.5.0, Backlog Feb 2, 2021
@stevenmckinnon
Copy link

stevenmckinnon commented Feb 17, 2021

Hey @eneufeld @sdirix, I see this has been moved to the backlog, are there no plans to fix this soon? Having it in would be a big win for me 👍🏻

@sdirix
Copy link
Member

sdirix commented Feb 17, 2021

@stevenmckinnon In general I think setting the required prop as suggested by you in #1695 is a good idea and we should implement it in one of the next versions (i.e. next), however it's not on our priority shortlist. You're welcome to open a PR to fix the issue, and we'll definitely have a look at that.

The requested feature here relates to if/then/else and will be much harder to support. As the use case is rather niche we have no plans to support this in the near future. If you'd like to contribute this feature we should discuss how the optional required can be detected and evaluated efficiently.

In case you need a solution for right now you can always just write your own custom renderers which set the required prop appropriately.

You might also be interested in our support packages which includes prioritization and development of requested features.

@sdirix sdirix modified the milestones: next, Backlog Feb 17, 2021
@stevenmckinnon
Copy link

Good to know, thanks @sdirix!

@nmaier95
Copy link
Contributor

nmaier95 commented Jul 21, 2022

Hey there, we stumbled upon the exact same issue of properties becoming required via some conditions. Whether that is directly in the "root" schema or in some nested anyOf|oneOf|allOf section. And unfortunately the renderers property control.required do not get updated if the conditions are met.
I think it is a rather common use case and not that much of a niche. Imo it is common to e.g. toggle additional form fields via a checkbox which then become required.

I highly appreciate this feature being supported.

To find out whether a component shall become required or not, if it just got mounted because of some layout condition which is now met, we came up with the following workaround:

mounted() {
    const validate = this.$validate(this.ajv, this.jsonforms.core.data, this.jsonforms.core.schema);
    this.isRequired = validate.errors.some(({ keyword, params }) => {
        return keyword === 'required' && params.missingProperty === this.control.path;
    });
}

@sdirix
Copy link
Member

sdirix commented Jul 24, 2022

Hi @nmaier95,

I don't see this feature implemented generically soon. We can't really reuse AJV as in the example code as then isRequired is only true when the parameter is missing. However it should also be true when it's there and there is no validation error.

We would need to evaluate the if conditions of AJV schemas for if/then/else cases manually. In bad cases the structure for this could be defined completely in parallel to the "normal" schema. Also for oneOf and anyOf it's completely unclear how a UI should behave.

If you need something like this right now then you probably have some very specific structures you need to see supported. For now I would like to suggest to implement the support for them on your own.

Of course we're open for a generic solution but it should be something without too much of a runtime penalty for this "small" feature.

@sdirix sdirix changed the title Required property is not set if field is required Required property is not set if field is conditionally required Nov 8, 2022
@wojtek1150
Copy link

Hey there, we stumbled upon the exact same issue of properties becoming required via some conditions. Whether that is directly in the "root" schema or in some nested anyOf|oneOf|allOf section. And unfortunately the renderers property control.required do not get updated if the conditions are met. I think it is a rather common use case and not that much of a niche. Imo it is common to e.g. toggle additional form fields via a checkbox which then become required.

I highly appreciate this feature being supported.

To find out whether a component shall become required or not, if it just got mounted because of some layout condition which is now met, we came up with the following workaround:

mounted() {
    const validate = this.$validate(this.ajv, this.jsonforms.core.data, this.jsonforms.core.schema);
    this.isRequired = validate.errors.some(({ keyword, params }) => {
        return keyword === 'required' && params.missingProperty === this.control.path;
    });
}

This won't work. When you fill field property the required property will be set to false since there will be no more errors.

IMO the problem is with isRequired function in core/renderers file:

const isRequired = (
  schema: JsonSchema,
  schemaPath: string,
  rootSchema: JsonSchema
): boolean => {
  const pathSegments = schemaPath.split('/');
  const lastSegment = pathSegments[pathSegments.length - 1];
  // Skip "properties", "items" etc. to resolve the parent
  const nextHigherSchemaSegments = pathSegments.slice(
    0,
    pathSegments.length - 2
  );
  const nextHigherSchemaPath = nextHigherSchemaSegments.join('/');
  const nextHigherSchema = Resolve.schema(
    schema,
    nextHigherSchemaPath,
    rootSchema
  );

  return (
    nextHigherSchema !== undefined &&
    nextHigherSchema.required !== undefined &&
    nextHigherSchema.required.indexOf(lastSegment) !== -1
  );
};

It just search for up/down schema. Not checked at all allOf anyOf or flat if statement in schema

@melvinkcx
Copy link

melvinkcx commented Dec 9, 2024

We just stumble upon this. I think this deserves more attention. The use cases of allOf, if-then-else with required should be pretty common. I appreciate it if we can support this in the future.

@sdirix
Copy link
Member

sdirix commented Dec 10, 2024

Hi @melvinkcx, supporting this use case in a built-in manner is far in the future, maybe it will never be added. The main reason is that this requires a conceptual change in JSON Forms from leveraging Ajv for JSON Schema validation to re-implementing all of JSON Schema validation ourselves within JSON Forms.

Note that, even if this was implemented, then there would be room for interpretations, e.g. if an array of oneOf or anyOf contain conditional requires, is a field then required or not.

However what we would like to accomplish much sooner is a more generic customization option to plug-in own functionalities like a "required" determinator. Then users could implement, copy and reuse a determinator which at least partially solves this problem, as there are some cases which seem clearly defined (like your mentioned allOf with if/then/else).

See PR #2228 for a community contribution which handles some of the dynamic required use cases. We will not merge it in this form, however you can copy and leverage the code in your custom renderers to solve the dynamic required use case for your scenarios / interpretations.

If you would like to have the option of plugging in own determinators: We would happily accept a contribution to make this an easy customization, to not require adopters to rebind all/most of the existing renderers. If you, or someone else, is interested in this, please leave us a message here or in the forums to discuss how this should be implemented.

@sdirix sdirix removed the est-5 label Dec 10, 2024
@melvinkcx
Copy link

Hi @sdirix, thank you for your clarification. I agree that it'd be a huge undertaking.

I don't have enough knowledge of the inner workings of JSONForms to propose anything, but here's a workaround we use.

Since we use ui-schema conditions (effect = HIDE) alongside with allOf/if-then to hide fields when they are not required. In the renderers, we simply skip validation when the field is not visible. I reckon it's not the best solution, but it works for us.

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

No branches or pull requests

7 participants