Fields resolution
To determine which field to use to display your JSON schema,
the form uses resolver
function.
Let’s take a look at the basic
resolver implementation
(@sjsf/form/resolvers/basic
):
import { getSimpleSchemaType, isFixedItems, type Validator,} from "@/core/index.js";
import type { FormInternalContext } from "../context/index.js";import type { ResolveFieldType } from "../fields.js";
export function resolver<V extends Validator>( _: FormInternalContext<V>): ResolveFieldType { return ({ schema }) => { if (schema.oneOf !== undefined) { return "oneOfField"; } if (schema.anyOf !== undefined) { return "anyOfField"; } const type = getSimpleSchemaType(schema); if (type === "array") { return isFixedItems(schema) ? "tupleField" : "arrayField"; } return `${type}Field`; };}
As you can see resolver
just selects the field according to the schema type.
This approach is simple and straightforward, but in some cases it can lead to additional work. Suppose you have the following scheme:
const schema: Schema = { enum: ["foo", "bar", "baz"]}
For this scheme, the basic
resolver will select stringField
,
and stringField
will display the textWidget
widget by default
although you probably wanted to see select or radio widgets.
To achieve this you need to specify in the UI scheme the field:
const uiSchema: UiSchema = { "ui:components": { // The `selectWidget` will now be displayed by default stringField: "enumField", // You can also replace `selectWidget` with `radioWidget` // selectWidget: "radioWidget" }}
Or you can modify resolver
so that enumField
is always used
when a scheme with enum
is detected:
return ({ schema }) => { if (schema.enum !== undefined) { return "enumField" } ...}
It is recommended that you copy the basic
resolver code into your project and
modify it to suit your needs.
As an example (or temporary solution) you can use the compat
resolver
(@sjsf/form/resolvers/compat
) that reproduces resolution logic from v1:
import { getSimpleSchemaType, isFileSchema, isFixedItems, type Validator,} from "@/core/index.js";
import { type FormInternalContext, isFilesArray, isMultiSelect, isSelect, retrieveUiOption,} from "../context/index.js";import type { ResolveFieldType } from "../fields.js";
import "../extra-fields/enum.js";import "../extra-fields/multi-enum.js";import "../extra-fields/file.js";import "../extra-fields/files.js";
export function resolver<V extends Validator>( ctx: FormInternalContext<V>): ResolveFieldType { return (config) => { const { schema } = config; if (isSelect(ctx, schema)) { return "enumField"; } if (schema.oneOf !== undefined) { return "oneOfField"; } if (schema.anyOf !== undefined) { return "anyOfField"; } const type = getSimpleSchemaType(schema); if (type === "array") { if (isMultiSelect(ctx, schema)) { return "multiEnumField"; } if (isFixedItems(schema)) { return "tupleField"; } if ( isFilesArray(ctx, schema) && retrieveUiOption(ctx, config, "orderable") !== true ) { return "filesField"; } return "arrayField"; } if (isFileSchema(schema)) { return "fileField"; } return `${type}Field`; };}