Extend the Content list widget
List views
To define a custom List view that you can use with the Content list widget, perform the following:
- Create a
.tsxfile that holds the implementation of your custom list view
The component’s props is an object of typeContentListMasterViewProps:
The model has a property calleditems, which contains all the content items that need to be rendered. The property is automatically populated with objects that contain all the properties defined in theFieldMappings(in theListFieldMappingprop of the entity). Each object also includes a property calledOriginal, which stores the original content item as returned by Sitefinity CMS. These items are of typeSdkItem, which is the base class used for working with Sitefinity CMS REST services. - Extend the entity.
Add the fields metadata for the new view. For more information, see Extending the entity and views metadata. - Register the extended entity and custom view in the widget registry.
Add a new entry to thewidget-registry.tsfile. For more information, see Register the extended entity and custom views.
Views metadata
The view metadata must be passed to the ListFieldMapping and CssClasses properties of the entity in the FieldMappings attribute. It contains all the mappings between views and their corresponding metadata.
import { CssFieldMappings, FieldMapping, FieldMappings } from '@progress/sitefinity-widget-designers-sdk';
import { ContentListEntity } from '@progress/sitefinity-nextjs-sdk/widgets';
import { contentListDefaultViewMeta, ContentListEntity } from '@progress/sitefinity-nextjs-sdk/widgets';
const viewMeta = {
...contentListDefaultViewMeta,
CardsListCustom: [
{ fieldTitle: 'Heading', fieldType: 'ShortText' }
]
};
export class ExtendedContentListEntity extends ContentListEntity {
/**
* Decorators defined here will override the ones from the base entity.
* Other decorators will be inherited
*/
@FieldMappings(viewMeta)
ListFieldMapping: Array<FieldMapping> | null = null;
/**
* Decorators defined here will override the ones from the base entity.
* Other decorators will be inherited
*/
@CssFieldMappings(viewMeta, true)
CssClasses: Array<{ FieldName: string; CssClass: string; }> | null = null;
}
Mappings
The purpose of metadata for mappings is to create reusable views that can be used across different content types. This is achieved by providing a list of fields and their types. Thus, when selecting different content types, each of the fields provided by the view can be mapped to a corresponding field of the selected content type.
The supported field types are the following:
ShortText- for string fields.LongText- for html fields.Text- for all kinds of string fields (including LongText).YesNo- for boolean fields.DateTime- for dates.Number- for all kinds of numbers.Classification- for classifications like tags, categories etc..Address- for address fields.RelatedData- for related data like news, blogs, dynamic.RelatedImages- for related images.RelatedVideos- for related videos.RelatedDocuments- for related documents.
You can use the following sample for reference:
import { CssFieldMappings, FieldMapping, FieldMappings } from '@progress/sitefinity-widget-designers-sdk';
import { ContentListEntity } from '@progress/sitefinity-nextjs-sdk/widgets';
import { contentListDefaultViewMeta, ContentListEntity } from '@progress/sitefinity-nextjs-sdk/widgets';
const viewMeta = {
...contentListDefaultViewMeta,
CardsListCustom: [
{ fieldTitle: 'Heading', fieldType: 'ShortText' }
]
};
export class ExtendedContentListEntity extends ContentListEntity {
/**
* Decorators defined here will override the ones from the base entity.
* Other decorators will be inherited
*/
@FieldMappings(viewMeta)
ListFieldMapping: Array<FieldMapping> | null = null;
/**
* Decorators defined here will override the ones from the base entity.
* Other decorators will be inherited
*/
@CssFieldMappings(viewMeta, true)
CssClasses: Array<{ FieldName: string; CssClass: string; }> | null = null;
}
All these fields are almost a 1:1 mapping with the custom fields dialog in the administrative interface. The entries for the mappings are case sensitive, so be sure to provide an exact match of the field name.
Detail Views
To define your own set of custom detail views in the code, you must do the following:
- Create a
.tsxfile that holds implementation of the details view. The component accepts a single property props. - The model for the view must be of type:
ContentListDetailViewProps
TheContentListDetailViewPropscontains a property calleddetailItemwhich refers to the resolved item. The item property is of typeSdkItem. This object contains the values of the fields that are defined in theDetailItemSelectExpressionin the entity. By default it is set to*.
Field values can be accessed by name fromprops.detailItem
Example:
props.detailItem?.MyShortTextFieldName - Register the extended entity and custom view in the widget registry.
Add a new entry to thewidget-registry.tsfile. For more information, see Register the extended entity and custom views.
Extending the entity and views metadata
To register your custom views and their metadata you have to extend the content list entity and modify some of its properties.
To register the custom views metadata you have to pass it in the @FieldMappings attribute of the ListFieldMapping and @CssFieldMappings properties.
NOTE: Decorators added in the extended entity, which are also present in the base entity, override the base ones. Decorators that are not being overridden in the extended entity are being inherited from the base entity.
export class ExtendedContentListEntity extends ContentListEntity {
@FieldMappings(viewMeta)
ListFieldMapping: Array<FieldMapping> | null = null;
@CssFieldMappings(viewMeta, true)
CssClasses: Array<{ FieldName: string; CssClass: string; }> | null = null;
}
Register the extended entity and custom views
To register the newly created views and the extended entity you need to go to the file widget-registry.ts and to add a new entry. For example:
import { WidgetRegistry, initRegistry, defaultWidgetRegistry } from '@progress/sitefinity-nextjs-sdk';
import { ContentList } from '@progress/sitefinity-nextjs-sdk/widgets';
import { CardsListCustomView } from './widgets/content-list/cards-list-custom.view';
import { CustomDetailView } from './widgets/content-list/custom-detail.view';
import { ExtendedContentListEntity } from './widgets/content-list/extended-content-list.entity';
const defaultRegistration = defaultWidgetRegistry.widgets['SitefinityContentList'];
const customWidgetRegistry: WidgetRegistry = {
widgets: {
'SitefinityContentList': {
entity: ExtendedContentListEntity,
componentType: ContentList,
editorMetadata: {
Title: 'Content list',
Category: 'Content',
Section: 'Lists',
EmptyIconText: 'Select content',
EmptyIcon: 'plus-circle',
IconName: 'content-list'
},
ssr: true,
views: {
...defaultRegistration.views,
'CardsListCustom': CardsListCustomView,
'Details.Custom': CustomDetailView
}
}
}
};
export const widgetRegistry: WidgetRegistry = initRegistry(customWidgetRegistry);
Exclude content types
Extend ContentListEntity
In order to exclude content types form the content list widget, you need to inherit and extend the ContentListEntity class and add TypeBlacklist paramater to exlclude content types or add Type paramater to specify a list of allowed contet types.
For example:
import { Content, ContentSection, DisplayName } from '@progress/sitefinity-widget-designers-sdk';
import { ContentListEntity } from './content-list/content-list-entity';
import { MixedContentContext } from '../../editor/widget-framework/mixed-content-context';
export class ExtendedContentListEntity extends ContentListEntity {
@Content({
Type: 'Telerik.Sitefinity.Lists.Model.ListItem, Telerik.Sitefinity.News.Model.NewsItem, Telerik.Sitefinity.Events.Model.Event',
TypeBlacklist: 'Telerik.Sitefinity.DynamicTypes.Model.PressReleases.Pressrelease'
})
@DisplayName('')
@ContentSection('Select content to display', 0)
SelectedItems: MixedContentContext | null = null;
}
Register the entity
Then you need to register the entity in the widget registry file:
`defaultWidgetRegistry.widgets['SitefinityContentList'].entity = ExtendedContentListEntity;
export const widgetRegistry: WidgetRegistry = initRegistry(defaultWidgetRegistry);`