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

[question] Support for const? #1587

Open
tiloc opened this issue May 29, 2020 · 5 comments
Open

[question] Support for const? #1587

tiloc opened this issue May 29, 2020 · 5 comments

Comments

@tiloc
Copy link

tiloc commented May 29, 2020

Describe the bug
I am not sure if this is a feature request or a bug. I am trying to pass constant strings from the schema into the JSON output of the form. According to the JSON Schema spec this should be possible by using the "const" keyword. Unfortunately, I cannot get this to work with JSON Forms.

To Reproduce
Steps to reproduce the behavior:

  1. Create a schema with the const keyword
  2. Use it with the "seed" app
  3. The element is ignored, i.e. not shown in the form nor output to the JSON data

Expected behavior
The constant data is passed through from the schema into the output.

Browser (please complete the following information):
Chrome

Used Setup (please complete the following information):

  • Seed app from github repository

Additional context
I am trying to use JSON Forms to generate valid FHIR healthcare resource output.

@sdirix
Copy link
Member

sdirix commented May 29, 2020

Hi! Thanks for this report. const values were always a little bit out of scope for us as it doesn't really make sense to show an UI for them, however I can understand that you need them in some way in your data at some point.

Current state

  • We ignore const properties when generating a default ui schema, so it won't show up in the UI in that case.
  • When you hand in your own ui schema and point a control to the const property we'll render an enum where the single entry is the const value. The user still has to select that enum value as undefined is always another option.

Automatic generation within JSON Forms

  • You could customize your Ajv instance to generate default values when validating. For this to work the default property has to be specified in the JSON schema. The code could look like this: In the schema you define the default

      "myConst": {
        "const": "myvalue",
        "default": "myvalue"
      }

    then you customize your Ajv instance and hand it over to JSON Forms.

    import { createAjv } from '@jsonforms/core';
    const myAjv = createAjv({ useDefaults: true });
    // ....
      <JsonForms
          schema={schema}
          // etc.
          ajv={myAjv}
      />

    To note: In the Redux-less version of JSON Forms you'll get notified about the change in the data once the user does their very first change to any input. So if your form is already prefilled with only valid data (except the missing const) you might miss it. I think we should look into changing that in the future, but this is how it works at the moment.
    Alternatively you could just execute a single validation run before you give the data to JSON Forms (or after you got it back) and generate the default value this way.

  • If adding defaults to the JSON schema and/or Ajv customization is not the way you want to go but you want to still solve the problem within JSON Forms you could go with a custom renderer.

    However in your case the custom renderer could immediately set the desired value in the data once it's called and then either don't render anything when you want to hide the const or could for example render a disabled text field or label. I think that's an adequate solution, the only thing which is a bit "unclean" with this approach is to change data simply by rendering an UI.

    You can check the React seed to see how a custom renderer can be implemented and/or check this tutorial.

Let me know whether one of the approaches works for you. If you (or someone else 😄) would like to contribute something for this use case: I think a const renderer (which is a bit nicer than an enum dropdown with a single entry) which allows to set/unset the value and optionally automatically sets the value (could be made configurable via the ui schema) would be something worthwhile.

In the meantime we could maybe change the default ui schema generation to also include a control for these const properties.

@jnothman
Copy link

A case where default is insufficient is where the form requests an array of heterogeneous objects and one wants to label each element by its type:

{
  "type": "array",
  "items": {
    "oneOf": [
      {
        "type": "object",
        "required": ["@type", "name"],
        "properties": {
          "@type": {
            "type": "string",
            "const": "Person"
          },
          "name": {
            "type": "string",
            "title": "Person's name"
          },
          "gender": {
            "type": "string",
            "enum": ["male", "female", "other", "not disclosed"]
          }
        }
      },
      {
        "type": "object",
        "required": ["@type", "name"],
        "properties": {
          "@type": {
            "type": "string",
            "const": "Organisation"
          },
          "name": {
            "type": "string",
            "title": "Org's name"
          }
        }
      }
    ]
  }
}

If one adds defaults and the user selects Organization and enters "name" only, then ajv will fill in "Person" as the default.

This seems to work for me:

import React from 'react';
import { withJsonFormsControlProps } from '@jsonforms/react';

export const ConstRenderer = withJsonFormsControlProps(({schema, handleChange, path}) => {
  React.useEffect(() => {
	handleChange(path, schema['const'])
  }, [schema, path]);
  return (<React.Fragment></React.Fragment>);
});

@dgerbe
Copy link

dgerbe commented Sep 16, 2022

@sdirix What if you're use-case is for the user to type in the const value? As a simple example, say you wanted the user to type "Confirm". This may not be a great UX design, but I have seen it.

My real use-case is I want to create a confirmation field where the user should enter the same value as entered in the previous field.

I tried to accomplish this with the schema below, but it creates a enum drop-down like you described in your previous comment.

{ "required": [ "username", "password", "confirmPassword" ], "properties": { "username": { "minLength": 3, "type": "string" }, "password": { "minLength": 6, "type": "string" }, "confirmPassword": { "const": { "$data": "1/password" }, "type": "string" } }, "type": "object" }

Source

@bastianwegge
Copy link

@jnothman thanks a thousand times, this solution helped us save a lot of time rewriting the array renderers.

@sdirix +1 for array types. Maybe there's a different solution to this, as different types of array items seem to be somewhat frequent.

Thanks for jsonforms in any case 😃

@sdirix
Copy link
Member

sdirix commented Apr 28, 2024

We recently improved some of the const use cases: Whenever we create a new object in JSON Forms, we will look for default declarations and set them immediately. So when you are using const combined with a default set to the same value, JSON Forms will set your const automatically.

Note this only happens on user interactions in which the user triggers the creation of a new object. It's very useful for these "@type" use cases in which a const is used to identify the type of the object.

This is available since 3.2.0

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

5 participants