sanity-io / sanity

Sanity Studio – Rapidly configure content workspaces powered by structured content
https://www.sanity.io
MIT License
5.28k stars 427 forks source link

Collecting use cases for async conditional fields #2706

Open ricokahler opened 3 years ago

ricokahler commented 3 years ago

In case you didn't see it, we've released conditional fields!

…however, the current implementation does not support an async hidden calback. This issue exists to collect use cases for async conditional fields so we can provide an alternative mechanism.

Context: why are async conditional fields difficult to implement?

There are a few challenges with making this API async:

  1. Layout critical — This feature has more implications than similar ones (e.g. custom validation) because the layout of the form is dependent on the results of your hidden callback. We want to ensure consistency between the form fields shown and the logic in your hidden callbacks. If we were to naively allow async, we could easily get into situations where multiple mutually exclusive fields are shown at the same time.
    This contrasts with the validation API (which does allow async). With the validation API, it's much easier to defer and debounce validation results because the layout is not dependent on validation and we can disable the Publish button until all validation has finished running.

  2. Reactivity — Sometimes is async is not enough. If you're pulling a value asynchronously, you'd probably also like to make this hidden logic re-run when that value changes.

  3. How often the function will be called — Because the condition function takes in the document as an argument, and because we want immediate consistency, it will be called every time the document is updated. You may want to call an API to get a result and this may result in many networks requests.

TL;DR let's come up with something else!

What are your use cases for async conditional fields?

This issue is to track use cases for conditional fields to see if we can come up with something else that preserves the current simplicity and performance while still doing the job of async conditional fields.

khendrikse commented 3 years ago

Wondering for this use case: A document has 2 fields:

  1. a reference (or array of references) to another document. That other document might have a field like type
  2. a field that we want to be conditionally hidden if (any of) the reference(s) (field 1) has a specific type
DanielGJohnsen commented 3 years ago

My use case: I have a list of documents that I would like filtered by using desk-tool/structure-builder. So I have this

.child(
    S.documentTypeList('category')
        .title('POIs by Category')
        .child((categoryId) =>
            S.documentList()
                .title('POIs')
                .filter(`_type == "poi" && $categoryId in categories[]._ref`)
                .params({ categoryId })
              )
        ),

The problem: I would like to conditionally render fields based on the list of categories on the poi, however since the category is a reference, it is impossible for me to utilize the hidden property on a field.

mickaelmarchal commented 2 years ago

All the same for me : hidden and readOnly should have a way to access the values of referenced documents.

For example, I would need to show a "EU VAT number" field only for Providers that belong to Countries of the European Union.

I have a custom validation rule to make sure that the VAT field is filled/empty (depending on the country), but it would be much more user friendly if I can just hide the field completely.

{
  name: 'country',
  title: 'Country',
  type: 'document',
  fields: [
    {
      name: 'isoCode',
      title: 'Country code',
      type: 'string',
      validation: (Rule) => Rule.required(),
    },
    {
      name: 'isInEu',
      title: 'Country is in EU',
      type: 'boolean',
    },
    // ...more fields here
  ]
}

{
  name: 'provider',
  title: 'Provider',
  type: 'document',
  fields: [
   {
      name: 'country',
      title: 'Country',
      type: 'reference',
      to: [{ type: 'country' }],
      validation: (Rule) => Rule.required(),
    },
    {
      name: 'euVatNumber',
      title: 'EU VAT number',
      type: 'string',
      hidden: ({ parent }) => {
        // 👇 HERE. I would need to show the field only if referenced country is in EU, something like:
        return !!parent.country.isInEu
      },
    },

    // ...more fields here
}
3200pro commented 2 years ago

I've got a scenario where I've got global options that determine what fields should show for posts and pages. I'm using a document reference that auto-populates my settings document when a new page/post is generated. If there are global settings I'd like them to be considered for conditional fields.

{
      name: 'body',
      title: 'Richtext Content',
      type: 'richContent',
      group: 'content',
      hidden: ({ parent }) => !parent.documentSetup?.toggleRichtext,
 },
djfarly commented 2 years ago

My use case is similar to to 3200pros.

We have a configuration type. I'd love to to hide fields based on what the user set in that configuration type. It's not referenced directly, so I would have used a groq query if async was possible.