decap-cms
decap-cms copied to clipboard
dependent fields in collection
hey,
i could not find any information about this therefor i thought i would ask here.
is it possible to show and hide fields depending on some other field?
eg. this is my frontmatter
---
...
structure:
- type: productCircle
- type: divider
- type: copy
content:
text: >-
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fugiat fugit enim quo consequuntur amet quasi ullam officia assumenda nihil. Corrupti delectus magnam excepturi nobis quae nihil explicabo provident repellat quaerat.
- type: infographic
content:
src: http://example.com/text.png
overlay: http://example.com/text.png
- type: divider
- type: copy
content:
text: >-
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi nihil error repellendus perspiciatis ratione, dolores, cum dicta sapiente quod labore saepe, quam ab placeat veniam nobis culpa totam vitae nam.
- type: infographic
content:
src: http://example.com/text.png
overlay: http://example.com/text.png
- type: copy
content:
text: >-
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur vero, quos velit minima placeat alias, quibusdam at sed quia illum dolorum. A, rem aut quidem excepturi aliquam. Aliquid, ea, cumque.
- type: quote
variant:
- with-divider
content:
items:
- image: http://example.com/text.png
copy: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Vitae sunt, earum? Perferendis ab blanditiis ut sequi consequuntur repudiandae ad ratione, amet eligendi laborum itaque labore, eius. Illo, quidem tempore quam!
author: Mario and Luigi
type: light
- type: divider
- type: copy
content:
text: >-
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deleniti, illum qui. Adipisci fugit, obcaecati, vel nostrum cumque a dignissimos odit eveniet ab. Aut cum officiis nesciunt necessitatibus, provident, ullam delectus!
- type: image
content:
src: http://example.com/text.png
---
based on that type different configurations for this list item might be needed
eg.
if my type is image only a image field is necessary but if the type is infographicand additional overlay image can be added
my config.yml looks like this
- label: 'structure'
name: structure
widget: 'list'
fields:
- {label: "type", name: "type", widget: "select", options: ["copy", "divider", "image", "infographic", "productCircle", "quote"]}
- label: content
name: content
widget: object
fields:
- {label: 'text', name: 'text', widget: 'markdown'}
- {label: 'src', name: 'src', widget: 'image'}
- {label: 'overlay', name: 'overlay', widget: 'image'}
this list has a lot of unused options and i am far from done adding all the fields
what would a good way to implement this kind of structure?
cms version 0.4.6
You could create a custom widget that provides a select input for selecting type, and the type definitions could be an array of objects defined in the widget config. Then you just swap in fields based on the selected type.
So I've been considering how this might look. We're now focusing heavily on the extensibility story around the CMS, and a big part of that is making widget authoring simpler, and the available API's more robust.
For this particular issue, we should have a widget as I mentioned in my last comment, but I want it to just be a button with configurable text. In the OP case you would configure the label to "Add content", and it's appearance would simply be that of a dropdown, which editors can use to add one of the widgets configured in the "fields" array. The UI around this could be further enhanced by passing control of labels (optionally) to widget authors (currently all widgets automatically receive a label in the UI direct through the CMS). This means an entry could consist of nothing more than this widget and be entirely dynamic, very similar to what ACF provides to WordPress users.
Furthermore, if the added widgets are themselves draggable, we'd have all that's needed for site building. Doing all of this in a widget is pretty compelling.
Thoughts?
@erquhart thanks for reminding me about this, I have been meaning to get it finished.
Anyhow, I did manage to find a solution to an extent, I could only get preview to work through a custom preview layout. Anyhow, here are some snippets that I generated:
config.yml
- name: slides
label: Slides
widget: list
required: false
fields:
- label: "Slide"
name: "slide"
widget: "dynamic"
dynamicWidgets:
- string
- image
- file
Control
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { Map } from 'immutable';
import CMS from 'netlify-cms';
export default class DynamicControl extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
onAddAsset: PropTypes.func.isRequired,
onRemoveAsset: PropTypes.func.isRequired,
getAsset: PropTypes.func.isRequired,
value: PropTypes.oneOfType([
PropTypes.node,
PropTypes.object,
PropTypes.bool,
]),
field: PropTypes.object,
forID: PropTypes.string,
dynamicWidgets: PropTypes.object
};
constructor(props) {
super(props);
const fieldValue = this.props.value && Map.isMap(this.props.value) ?
this.props.value.get(this.props.field.get('name')) :
'';
if (!fieldValue) {
this.state = {
widget: null,
};
} else {
this.state = {
widget: CMS.getWidget(fieldValue),
};
}
}
handleChange = (e) => {
this.props.onChange(Map().set(e.target.id, e.target.value));
if (!e.target.value) {
this.setState({
widget: null,
});
} else {
this.setState({
widget: CMS.getWidget(e.target.value),
});
}
};
render() {
const { field, value, forID, onChange, onAddAsset, onRemoveAsset, getAsset } = this.props;
const { widget } = this.state;
const name = field.get('name');
const selectedName = `${ field.get('name') }_selected`;
const fieldValue = this.props.value && Map.isMap(this.props.value) ?
this.props.value.get(name || '') :
'';
const fieldValueSelected = this.props.value && Map.isMap(this.props.value) ?
this.props.value.get(selectedName || '') :
'';
let options = field.get('dynamicWidgets').map((option) => {
if (typeof option === 'string') {
return { label: option, value: option };
}
return option;
});
options = options.insert(0, {
label: 'Please Select',
value: '',
});
return (
<div>
<div>
<select id={forID} value={fieldValue || ''} onChange={this.handleChange}>
{options.map((option, idx) => <option key={idx} value={option.value}>
{option.label}
</option>)}
</select>
</div>
<div>
{
widget ?
<div key={selectedName}>
<div key={selectedName}>
<label htmlFor={selectedName}>{`${ field.get('label') } Data`}</label>
{
React.createElement(widget.control, {
id: selectedName,
field,
value: fieldValueSelected,
onChange: (val, metadata) => {
onChange((value || Map()).set(selectedName, val), metadata);
},
onAddAsset,
onRemoveAsset,
getAsset,
forID: selectedName,
})
}
</div>
</div>
:
''
}
</div>
</div>
);
}
}
Hope that helps kick start this conversation ;)
@domtalbot can you open a "WIP" PR with a working implementation?
Hi Shawn,
I should be able to do this over the christmas period yes, will keep this thread updated :)
On 19 December 2017 at 21:48, Shawn Erquhart [email protected] wrote:
@domtalbot https://github.com/domtalbot can you open a "WIP" PR with a working implementation?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/netlify/netlify-cms/issues/565#issuecomment-352896609, or mute the thread https://github.com/notifications/unsubscribe-auth/AG11467bYwSm0kzYwWEBDGURYYZlLx5Lks5tCC9LgaJpZM4PGGOv .
--
Kind Regards
Dominic Talbot 07791193905
Started another issue similar to this. Wondering if you got anywhere @domtalbot and if you need any help? #1066
While considering #2405 I think I found a way to statically configure conditional fields right in the yaml while still providing flexibility. Using the original case from @kevinfoerster's OP:
- label: structure
name: structure
widget: list
fields:
- label: type
name: type
widget: select
options:
- copy
- divider
- image
- infographic
- productCircle
- quote
- label: content
name: content
widget: object
fields:
- label: text
name: text
widget: markdown
condition: {type: fieldValue, field: type, oneOf: [copy, productCircle, quote]}
- label: src
name: src
widget: image
condition: {type: fieldValue, field: type, oneOf: [image, infographic, productCircle]}
- label: overlay
name: overlay
widget: image
condition: {type: fieldValue, field: type, equals: infographic}
fieldValue is just one potential type, and each type can accept different properties, here we use equals and oneOf.
condition could accept either an object or an array. The example above is shorthand for condition.oneOf, which accepts an object or array of objects, and can be used if condition itself can be configured with other properties for more control, or alternatives to condition.oneOf, such as condition.allOf, which would require all condition objects in an array to validate.
I love this idea of the condition property suggested above ☝️ Do we have any forward progression on this? Just ran into a couple of scenarios where this would be very helpful. Thanks in advance.
Looks great already @erquhart. Maybe add condition.not to the list of conditions
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Any updates on this? I want to display a datetime widget only if a boolean widget is false.
Hi @caseykey, we're working our way through the most upvoted issues first, so best way to push something forward is to upvote it.
Hi @caseykey, we're working our way through the most upvoted issues first, so best way to push something forward is to upvote it.
Like give it a thumbs up?
Hi @caseykey, we're working our way through the most upvoted issues first, so best way to push something forward is to upvote it.
Like give it a thumbs up?
Exactly
@erezrokah Where is this on the roadmap? Would be great to get this feature added! I've got a situation that looks like this:

It's very confusing for content editors and hinders their productivity and the potential flexibility of NetlifyCMS.
Thanks to all for your hard work on this project !
Kyle
Hi @kylekirkby, see my comment https://github.com/netlify/netlify-cms/issues/565#issuecomment-576140240 and the most upvoted features here https://github.com/netlify/netlify-cms/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc. I think one could implement this in a custom widget, and if that works well we can import it into the main repo.
I managed to get it working as a custom widget for my client site so is perfectly doable. I don't have access to the code anymore though :(
On Mon, 11 May 2020, 11:29 Erez Rokah, [email protected] wrote:
Hi @kylekirkby https://github.com/kylekirkby, see my comment #565 (comment) https://github.com/netlify/netlify-cms/issues/565#issuecomment-576140240 and the most upvoted features here https://github.com/netlify/netlify-cms/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc . I think one could implement this in a custom widget, and if that works well we can import it into the main repo.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/netlify/netlify-cms/issues/565#issuecomment-626618054, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABWXLY65G5PJCLFOZAPCOHLRQ7HQPANCNFSM4DYYMOXQ .
Hi guys, I would love to see this feature added too. I have a requirement for a page builder. The way I would like it to work would be that you create a new page based on the following in your config.yml:
collections:
- name: 'pages'
label: 'Pages'
label_singular: 'Page'
folder: 'src/_pages/pages'
create: true
identifier_field: name
fields:
- {
label: 'Page Template',
name: 'templateKey',
widget: 'select',
default: 'standardPage',
options:
[
{ label: 'Standard Layout', value: 'standardPage' },
{ label: 'Background Layout', value: 'backgroundPage' },
{ label: 'Carousel Layout', value: 'carouselPage' },
{ label: 'Gallery Layout', value: 'galleryPage' },
],
}
The relevant fields for each type of Layout would be rendered out in the editor panel depending on which dropdown option you selected. Although, I'm not sure how I would associate each dropdown value with a unique set of fields (is this where the beta Variable Types widget comes in to play?) When I publish the page, the page's markdown would just include the frontmatter fields that correspond to the selected layout template (e.g a columns field) that was selected during page creation - all pre-populated of course:
---
templateKey: standardPage
title: Page Title
columns:
columnOne: Column One Text
columnTwo: Column Two Text
columnThree: Column Three Text
---
Hi, any updates on this?
Hi, I need this feature for a client requirement, how is going on?
Hi @filipburian and @miguelt1, we have some in progress work in https://github.com/netlify/netlify-cms/pull/3891 if you'd like to pick it up.
6 years and multiple solutions proposed and still nothing🥲
In my case, I just needed a boolean widget that is attached to a list widget, and boolean widget can show/hide the list. you can use a custom widget similar to this:
// custom widget
import React, { Component } from "react"
import CMS from "netlify-cms-app"
import _ from "lodash"
import { List } from "immutable"
const booleanWidget = CMS.getWidget("boolean")
const listWidget = CMS.getWidget("list")
export class ToggleListControl extends Component {
constructor(props) {
super(props)
this.state = {
show: !_.isNil(this.props.value),
}
}
render() {
const {
value,
forID,
onChange,
classNameWrapper,
setActiveStyle,
setInactiveStyle,
} = this.props
return (
<div>
<div>
{React.createElement(booleanWidget.control, {
value: !_.isNil(value),
onChange: () => {
if (!_.isNil(value)) {
this.setState({ show: false })
onChange(undefined)
} else {
this.setState({ show: true })
onChange(List())
}
},
forID: `${forID}-toggle`,
classNameWrapper,
setActiveStyle,
setInactiveStyle,
})}
</div>
<div style={{ marginTop: "16px" }}>
{!_.isNil(this.props.value) && (
<div>
{React.createElement(listWidget.control, { ...this.props })}
</div>
)}
</div>
</div>
)
}
}
export const ToggleListPreview = ({ value }) => {
return <div></div>
}
and the config would be the same as the one you use for list:
- label: Toggle List
name: fieldname
widget: toggleList
required: false
field: { label: Text, name: text, widget: string }