Open tiloc opened 4 years ago
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
const
properties when generating a default ui schema, so it won't show up in the UI in that case.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
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 :smile:) 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.
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>);
});
@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" }
@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 😃
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
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:
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):
Additional context I am trying to use JSON Forms to generate valid FHIR healthcare resource output.