I've been trying to get the attributes of a custom content type in a custom block. The problem is that I don't receive the attributes, and I don't understand how I can pass these attributes to the block.
I specified the attributes for the person content type (image, name, email, position, entrance, tags) and tried to log them in the isotopeView (console.log(data)), but the data attribute only contains the title and description of the person content type. I figured out that I can add attributes with the "selectedItemAttrs" property in isotopeSchema.js, but I can't just add any attribute, only selected, and there is no documentation about which attributes can be added.
Backend:
person.py
from plone import schema
from plone.autoform import directives
from plone.dexterity.content import Container
from plone.supermodel import model
from plone.namedfile.field import NamedBlobImage
from plone.schema.email import Email
from z3c.form.browser.checkbox import CheckBoxFieldWidget
from zope.interface import implementer
class IPerson(model.Schema):
"""Dexterity-Schema for Person"""
image = NamedBlobImage(
title='Image',
description='Portrait of the person',
required=True,
)
name = schema.TextLine(
title='Name',
description='Name of the person',
required=True,
)
email = Email(
title='Email',
description='Email of the person',
required=False,
)
position = schema.TextLine(
title='Position',
description='Position of the person',
required=False,
)
entrance = schema.Int(
title='Entrance',
description='Year of employment',
required=False,
)
directives.widget(tags=CheckBoxFieldWidget)
tags = schema.Set(
title='Tags',
value_type=schema.Choice(
values=['Medienproduktion', 'Vorstufe', 'Redaktion', 'Sekretariat'],
),
required=True,
)
@implementer(IPerson)
class Person(Container):
"""Person instance class"""
person.xml
<?xml version="1.0"?>
<object name="person" meta_type="Dexterity FTI" i18n:domain="plone"
xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<property name="title" i18n:translate="">Person</property>
<property name="description" i18n:translate=""></property>
<property name="icon_expr">string:${portal_url}/document_icon.png</property>
<property name="factory">person</property>
<property name="add_view_expr">string:${folder_url}/++add++person</property>
<property name="link_target"></property>
<property name="immediate_view">view</property>
<property name="global_allow">True</property>
<property name="filter_content_types">True</property>
<property name="allowed_content_types"/>
<property name="allow_discussion">False</property>
<property name="default_view">view</property>
<property name="view_methods">
<element value="view"/>
</property>
<property name="default_view_fallback">False</property>
<property name="add_permission">cmf.AddPortalContent</property>
<property name="klass">herme_backend.content.person.Person</property>
<property name="schema">herme_backend.content.person.IPerson</property>
<property name="behaviors">
<element value="plone.dublincore"/>
<element value="plone.namefromtitle"/>
<element value="plone.versioning" />
</property>
<property name="model_source"></property>
<property name="model_file"></property>
<property name="schema_policy">dexterity</property>
<alias from="(Default)" to="(dynamic view)"/>
<alias from="edit" to="@@edit"/>
<alias from="sharing" to="@@sharing"/>
<alias from="view" to="(selected layout)"/>
<action title="View" action_id="view" category="object" condition_expr=""
description="" icon_expr="" link_target="" url_expr="string:${object_url}"
visible="True">
<permission value="View"/>
</action>
<action title="Edit" action_id="edit" category="object" condition_expr=""
description="" icon_expr="" link_target=""
url_expr="string:${object_url}/edit" visible="True">
<permission value="Modify portal content"/>
</action>
</object>
types.xml
<?xml version="1.0" encoding="utf-8"?>
<object meta_type="Plone Types Tool" name="portal_types" >
<object meta_type="Dexterity FTI" name="person" />
</object>
Frontend:
isotopeSchema.js
import config from '@plone/volto/registry';
const DEFAULT_TAGS = [
['Medienproduktion', 'Medienproduktion'],
['Vorstufe', 'Vorstufe'],
['Redaktion', 'Redaktion'],
]
const isotopeItemSchema = (props) => {
const { intl } = props;
return {
title: 'Item',
addMessage: 'Add item',
fieldsets: [
{
id: 'default',
title: 'Default',
fields: ['href'],
},
],
properties: {
href: {
title: 'Source',
widget: 'object_browser',
mode: 'link',
selectedItemAttrs: ['Title', 'Description', 'image', 'name', 'email', 'position', 'entrance', 'tags' ],
allowExternals: false,
selectableTypes: ['Person'],
},
},
required: [],
};
};
export const IsotopeSchema = (props) => {
const default_tags =
config.blocks?.blocksConfig?.listing?.default_tags ||
DEFAULT_TAGS;
return {
title: 'People',
fieldsets: [
{
id: 'default',
title: 'Default',
fields: ['columns', 'default_tags'],
},
],
properties: {
columns: {
widget: 'object_list',
title: 'People',
schema: isotopeItemSchema,
},
default_tags: {
title: 'Tags',
widget: 'select',
isMulti: true,
choices: default_tags,
noValueOption: true,
},
},
required: [],
};
};
export default IsotopeSchema;
isotopeView.jsx
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { Helmet } from '../../../../../omelette/src/helpers/Helmet/Helmet';
const IsotopeView = ({ data }) => {
console.log(data);
// console.log(data.columns[0].href[0].title);
// init one ref to store the future isotope object
var isotope;
if (typeof window !== "undefined") {
isotope = window.Isotope;
}
// store the filter keyword in a state
const [filterKey, setFilterKey] = useState('*')
// initialize an Isotope object with configs
useEffect(() => {
console.log("handle it");
isotope.current = new Isotope('.grid', {
itemSelector: '.grid-item',
sortBy: 'random',
})
// cleanup
return () => isotope.current.destroy()
}, [])
// handling filter key change
useEffect(() => {
filterKey === '*'
? isotope.current.arrange({filter: `*`})
: isotope.current.arrange({filter: `.${filterKey}`})
}, [filterKey])
const handleFilterKeyChange = key => () => setFilterKey(key)
return(
<>
<Helmet>
<script src="https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js"></script>
</Helmet>
<div id="filters" className="button-group filter-button-group">
<button className="filterBtn is-checked" onClick={handleFilterKeyChange('*')}>Alle</button>
{data.default_tags.map((filter) => (
<button className="filterBtn" onClick={handleFilterKeyChange(filter)}>{ filter }</button>
))}
</div>
<div className='grid'>
<div className='grid-item Medienproduktion'><p>Medienproduktion</p></div>
<div className='grid-item Vorstufe'><p>Vorstufe</p></div>
<div className='grid-item Redaktion'><p>Redaktion</p></div>
</div>
</>
);
};
IsotopeView.propTypes = {
data: PropTypes.objectOf(PropTypes.any).isRequired,
};
export default IsotopeView;
isotopeEdit.jsx
import React from "react";
import PropTypes from 'prop-types';
import IsotopeData from "./IsotopeData";
import SidebarPortal from "../../../../../omelette/src/components/manage/Sidebar/SidebarPortal";
const IsotopeEdit = React.memo((props) => {
const { selected, onChangeBlock, block, data } = props;
return(
<>
<p>This is the filter cards edit</p>
<SidebarPortal selected={selected}>
<IsotopeData
{...props}
data={data}
block={block}
onChangeBlock={onChangeBlock}
/>
</SidebarPortal>
</>
)
})
export default IsotopeEdit;
isotopeData.jsx
import React from 'react';
import { IsotopeSchema } from './IsotopeSchema';
import BlockDataForm from '../../../../../omelette/src/components/manage/Form/BlockDataForm';
const IsotopeView = (props) => {
const { block, data, onChangeBlock } = props;
const schema = IsotopeSchema({ ...props });
return (
<BlockDataForm
schema={ schema }
title={ schema.title }
onChangeField={(id, value) => {
onChangeBlock(block, {
...data,
[id]: value,
});
}}
formData={ data }
block={ block }
/>
);
};
export default IsotopeView;