decaporg / decap-cms

A Git-based CMS for Static Site Generators
https://decapcms.org
MIT License
17.94k stars 3.04k forks source link

Option to Enable input field only if a checkbox is checked #1267

Open ghost opened 6 years ago

ghost commented 6 years ago

- Do you want to request a feature or report a bug? Feature

- What is the expected behavior? I will start with an example so that this is better understood

whitelist: status: false type: start-date: end-date:

In the code above, I want the user to only fill in the type and date fields if they change the status to true, So what i am looking for is a way to set a checkbox widget that controls input fields and makes them available when clicked on.

Another example would be a typical 'Others' Input box that becomes available when the user checks the 'others' checkbox.

erquhart commented 6 years ago

This may require the same kind of dot notation field name parsing as #595, so nested fields can be referenced. Rather than being checkbox specific, what about basing a field's visibility on the value of another field (which could be a boolean/checkbox)? You could base it on the other field simply having a truthy value, or provide a specific value to look for.

Thoughts anyone?

ghost commented 6 years ago

Yes, the core idea is like how you said. When one field is set to true its dependent fields become active for user input. Implementing this will reduce a lot of clutter in the UI and give the user a better UX experience.

mbrookes commented 6 years ago

Continuing discussion from https://github.com/netlify/netlify-cms/issues/1280#issuecomment-384455171 here to avoid further cluttering the CMS 2.0 issue. (Happy to go back and delete the follow-up comments from there! 😅)

If you're saying a select widget essentially determines how the relation widget is configured (e.g. which collection it points to),

I was using select / relation interchangeably, as this may be something you want predefined in the configuration as selects, or it may be that you want to be able to edit the options available through the CMS itself by making them editable collections.

{As] an extension of #1267. [...] you'd set up a few different relation widgets and show them based on the value of the select widget.

That would be one way to do it, sure. It would mean that the top-level selection would have to be a fixed set of predefined values ("News", "Business", "Sport" etc.), but the secondary selection could be a set of editable collections.

I'd settle for that if it's the simplest to implement, as an extension of this issue, but it would be interesting to think about making the top-level a relation to a collection of collections!

erquhart commented 6 years ago

Can you provide some content/config examples of what you're currently doing and what you'd like to do?

mbrookes commented 6 years ago

Okay, here's one possible config. In this example, the section is a fixed list, the subsection is a collection.

collections:
  - name: "posts"
    label: "Posts"
    folder: "posts"
    create: true
    slug: "{{slug}}"
    fields:
      - {name: "date", widget: "datetime", hidden: true}
      - {label: "Section", name: "section", widget: "select", options: ["news", "reviews", "interviews", "blog"]}
    - {
        label: "Subsection",
        name: "subsection",
        widget: "relation",
        collection: "subsections",
        searchFields: ["title"],
        valueField: "title",
        filterField: "section" # Only subsections whose section matches the selection above are shown.
      }
      - {label: "Title", name: "title", widget: "string"}
      - {label: "Subtitle", name: "subtitle", widget: "string"}
      - {label: "Body", name: "body", widget: "markdown"}
      - {label: "Tags", name: "tags", widget: "list"}

  - name: "subsections"
    label: "Subsections"
    folder: "subsections"
    create: true
    slug: "{{slug}}"
    fields:
      - {label: "Section", name: "section", widget: "select", options: ["news", "reviews", "interviews", "blog"]}
      - {label: "Subsection name", name: "title", widget: "string"}

The Posts subsection relation is filtered to those members of the subsection collection whose section matches the section chosen in the Posts section select. Ideally the subsection widget would be disabled until a section is selected.

(The Posts date field is an aspirational config for a datetime widget that can be hidden.)

mbrookes commented 6 years ago

Here's one based on both section and subsection being collections:

collections:
  - name: "posts"
    label: "Posts"
    folder: "posts"
    create: true
    slug: "{{slug}}"
    fields:
      - {name: "date", widget: "datetime", hidden: true}
    - {
        label: "Section",
        name: "section",
        widget: "relation",
        collection: "sections",
        searchFields: ["title"],
        valueField: "title",
      }
    - {
        label: "Subsection",
        name: "subsection",
        widget: "relation",
        collection: "subsections",
        searchFields: ["title"],
        valueField: "slug",
        filterField: "section"
      }
      - {label: "Title", name: "title", widget: "string"}
      - {label: "Subtitle", name: "subtitle", widget: "string"}
      - {label: "Body", name: "body", widget: "markdown"}
      - {label: "Tags", name: "tags", widget: "list"}

  - name: "sections"
    label: "Sections"
    folder: "sections"
    create: true
    slug: "{{slug}}"
    fields:
      - {label: "Section name", name: "title", widget: "string"}

  - name: "subsections"
    label: "Subsections"
    folder: "subsections"
    create: true
    slug: "{{slug}}"
    fields:
      - {
          label: "Section",
          name: "section",
          widget: "relation",
          collection: "sections",
          searchFields: ["title"],
          valueField: "title"
        }
      - {label: "Subsection name", name: "title", widget: "string"}

This would work the same way, but both the sections and subsections are configurable by virtue of being collections.

turijs commented 5 years ago

I would also be a big fan of this feature. One use case that I have in mind is being able to change the available fields based on the chosen "layout" for a page (I am working on a Hugo site). For instance, a gallery layout would need a field for choosing images, a 2-column layout would need a second text area, etc. Right now the only way to acheive this (that I can see) would be to put all these page types into separate collections, which isn't necessarily a logical grouping for the site...or leave all fields visible at all times, which isn't great from a UX perspective.

A few thoughts on how the API could work: Simple:

fields:
  - name: foo
    widget: string
    visible_when:
      field: bar
      compare: '='
      value: 'some val'

More complex conditions:

fields:
  - name: foo
    widget: string
    visible_when:
      and:
        - field: bar
          compare: '='
          value: 'some val'
        - field: baz
          compare: '!='
          value: 1
        - or:
            - field: bar1
              compare: '<'
              value: 100
            - field: baz2
              compare: 'in'
              value: ['red', 'green']

This would allow for an arbitrary level of complexity without introducing too much specialized syntax as in #1894.

Also agree with @erquhart's point about notation for accessing nested fields. However, simple dot notation may not be sufficient, as I can imagine scenarios where it would be useful to be able to reference a field higher in the tree without specifying an 'absolute' path. For example:

fields:
  - name: galleries
    widget: list
    fields:
      - name: name
        widget: string
      - name: show_captions
        widget: boolean
      - name: images
        widget: list
        fields: 
          - name: image
            widget: image
          - name: caption
            widget: string
            visible_when:
              field: '../show_captions' # or a better syntax...
              compare: '='
              value: true

In this case a top-down field reference wouldn't make sense due to the dynamic nature of lists.

josejuanmartinez commented 1 year ago

+1