Skip to content

Commit 83eed58

Browse files
authored
Merge pull request #1745 from GuidoZam/DynamicForm-custom-icon
Added customIcons property on DynamicForm.
2 parents ff377a6 + c2c58d0 commit 83eed58

File tree

6 files changed

+50
-28
lines changed

6 files changed

+50
-28
lines changed

docs/documentation/docs/controls/DynamicForm.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ The `DynamicForm` can be configured with the following properties:
6262
| fieldOverrides | {[columnInternalName: string] : {(fieldProperties: IDynamicFieldProps): React.ReactElement\<IDynamicFieldProps\>}} | no | Key value pair for fields you want to override. Key is the internal field name, value is the function to be called for the custom element to render. |
6363
| respectEtag | boolean | no | Specifies if the form should respect the ETag of the item. Default - `true` |
6464
| validationErrorDialogProps | IValidationErrorDialogProps | no | Specifies validation error dialog properties |
65+
| customIcons | { [ columnInternalName: string ]: string } | no | Specifies custom icons for the form. The key of this dictionary is the column internal name, the value is the Fluent UI icon name. |
6566

6667
## Validation Error Dialog Properties `IValidationErrorDialogProps`
6768
| Property | Type | Required | Description |

src/controls/dynamicForm/DynamicForm.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,7 @@ export class DynamicForm extends React.Component<
908908
listItemId,
909909
disabledFields,
910910
respectETag,
911+
customIcons,
911912
onListItemLoaded,
912913
} = this.props;
913914
let contentTypeId = this.props.contentTypeId;
@@ -986,7 +987,8 @@ export class DynamicForm extends React.Component<
986987
numberFields,
987988
listId,
988989
listItemId,
989-
disabledFields
990+
disabledFields,
991+
customIcons
990992
);
991993

992994
// Get installed languages for Currency fields
@@ -1028,7 +1030,7 @@ export class DynamicForm extends React.Component<
10281030
* @returns
10291031
*/
10301032
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1031-
private async buildFieldCollection(listInfo: IRenderListDataAsStreamClientFormResult, contentTypeName: string, item: any, numberFields: ISPField[], listId: string, listItemId: number, disabledFields: string[]): Promise<IDynamicFieldProps[]> {
1033+
private async buildFieldCollection(listInfo: IRenderListDataAsStreamClientFormResult, contentTypeName: string, item: any, numberFields: ISPField[], listId: string, listItemId: number, disabledFields: string[], customIcons: {[key: string]: string}): Promise<IDynamicFieldProps[]> {
10321034
const tempFields: IDynamicFieldProps[] = [];
10331035
let order: number = 0;
10341036
const hiddenFields = this.props.hiddenFields !== undefined ? this.props.hiddenFields : [];
@@ -1285,6 +1287,7 @@ export class DynamicForm extends React.Component<
12851287
minimumValue: minValue,
12861288
maximumValue: maxValue,
12871289
showAsPercentage: showAsPercentage,
1290+
customIcon: customIcons ? customIcons[field.InternalName] : undefined
12881291
});
12891292

12901293
// This may not be necessary now using RenderListDataAsStream

src/controls/dynamicForm/IDynamicFormProps.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@ export interface IDynamicFormProps {
5151
/**
5252
* Key value pair for fields you want to override. Key is the internal field name, value is the function to be called for the custom element to render
5353
*/
54-
fieldOverrides?: {[columnInternalName: string] : {(fieldProperties: IDynamicFieldProps): React.ReactElement<IDynamicFieldProps>}};
54+
fieldOverrides?: {
55+
[columnInternalName: string]: {
56+
(
57+
fieldProperties: IDynamicFieldProps
58+
): React.ReactElement<IDynamicFieldProps>;
59+
};
60+
};
5561

5662
/**
5763
* Specifies if onSubmitted event should pass PnPJS list item (IItem) as a second parameter. Default - true
@@ -110,4 +116,10 @@ export interface IDynamicFormProps {
110116
* Only used when enableFileSelection is true
111117
*/
112118
supportedFileExtensions?: string[];
119+
120+
/**
121+
* Specify a set of custom icons to be used.
122+
* The key is the field internal name and the value is the Fluent UI icon name.
123+
*/
124+
customIcons?: { [columnInternalName: string]: string };
113125
}

src/controls/dynamicForm/dynamicField/DynamicField.tsx

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
8080
description,
8181
maximumValue,
8282
minimumValue,
83+
customIcon,
8384
orderBy
8485
} = this.props;
8586

@@ -114,7 +115,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
114115
case 'Text':
115116
return <div>
116117
<div className={styles.titleContainer}>
117-
<Icon className={styles.fieldIcon} iconName={"TextField"} />
118+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "TextField"} />
118119
{labelEl}
119120
</div>
120121
<TextField
@@ -135,7 +136,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
135136
const noteValue = valueToDisplay !== undefined ? valueToDisplay : defaultValue;
136137
return <div className={styles.richText}>
137138
<div className={styles.titleContainer}>
138-
<Icon className={styles.fieldIcon} iconName={"AlignLeft"} />
139+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "AlignLeft"} />
139140
{labelEl}
140141
</div>
141142
<RichText
@@ -151,7 +152,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
151152
else {
152153
return <div>
153154
<div className={styles.titleContainer}>
154-
<Icon className={styles.fieldIcon} iconName={"AlignLeft"} />
155+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "AlignLeft"} />
155156
{labelEl}
156157
</div>
157158
<TextField
@@ -172,7 +173,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
172173
case 'Choice':
173174
return <div className={styles.fieldContainer}>
174175
<div className={`${styles.labelContainer} ${styles.titleContainer}`}>
175-
<Icon className={styles.fieldIcon} iconName={"CheckMark"} />
176+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "CheckMark"} />
176177
{labelEl}
177178
</div>
178179
<Dropdown
@@ -188,7 +189,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
188189
case 'MultiChoice':
189190
return <div className={styles.fieldContainer}>
190191
<div className={`${styles.labelContainer} ${styles.titleContainer}`}>
191-
<Icon className={styles.fieldIcon} iconName={"MultiSelect"} />
192+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "MultiSelect"} />
192193
{labelEl}
193194
</div>
194195
<Dropdown
@@ -205,7 +206,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
205206
case 'Location':
206207
return <div className={styles.fieldContainer}>
207208
<div className={`${styles.labelContainer} ${styles.titleContainer}`}>
208-
<Icon className={styles.fieldIcon} iconName={"POI"} />
209+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "POI"} />
209210
{labelEl}
210211
</div>
211212
<LocationPicker
@@ -224,7 +225,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
224225
const lookupValue = valueToDisplay !== undefined ? valueToDisplay : defaultValue;
225226
return <div>
226227
<div className={styles.titleContainer}>
227-
<Icon className={styles.fieldIcon} iconName={"Switch"} />
228+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "Switch"} />
228229
{labelEl}
229230
</div>
230231
<ListItemPicker
@@ -249,7 +250,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
249250
const lookupMultiValue = valueToDisplay !== undefined ? valueToDisplay : defaultValue;
250251
return <div>
251252
<div className={styles.titleContainer}>
252-
<Icon className={styles.fieldIcon} iconName={"Switch"} />
253+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "Switch"} />
253254
{labelEl}
254255
</div>
255256
<ListItemPicker
@@ -273,7 +274,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
273274

274275
return <div>
275276
<div className={styles.titleContainer}>
276-
<Icon className={styles.fieldIcon} iconName={"NumberField"} />
277+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "NumberField"} />
277278
{labelEl}
278279
</div>
279280
<TextField
@@ -296,7 +297,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
296297

297298
return <div>
298299
<div className={styles.titleContainer}>
299-
<Icon className={styles.fieldIcon} iconName={"AllCurrency"} />
300+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "AllCurrency"} />
300301
{labelEl}
301302
</div>
302303
<TextField
@@ -317,7 +318,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
317318
case 'DateTime':
318319
return <div className={styles.fieldContainer}>
319320
<div className={styles.titleContainer}>
320-
<Icon className={styles.fieldIcon} iconName={"Calendar"} />
321+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "Calendar"} />
321322
{labelEl}
322323
</div>
323324
{
@@ -350,7 +351,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
350351
case 'Boolean':
351352
return <div>
352353
<div className={styles.titleContainer}>
353-
<Icon className={styles.fieldIcon} iconName={"CheckboxComposite"} />
354+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "CheckboxComposite"} />
354355
{labelEl}
355356
</div>
356357
<Toggle
@@ -370,7 +371,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
370371
const userValue = Boolean(changedValue) ? changedValue.map(cv => cv.secondaryText) : (value ? value : defaultValue);
371372
return <div>
372373
<div className={styles.titleContainer}>
373-
<Icon className={styles.fieldIcon} iconName={"Contact"} />
374+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "Contact"} />
374375
{labelEl}
375376
</div>
376377
<PeoplePicker
@@ -394,7 +395,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
394395
case 'UserMulti':
395396
return <div>
396397
<div className={styles.titleContainer}>
397-
<Icon className={styles.fieldIcon} iconName={"Contact"} />
398+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "Contact"} />
398399
{labelEl}
399400
</div>
400401
<PeoplePicker
@@ -417,7 +418,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
417418
case 'URL':
418419
return <div>
419420
<div className={styles.titleContainer}>
420-
<Icon className={styles.fieldIcon} iconName={"Link"} />
421+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "Link"} />
421422
{labelEl}
422423
</div>
423424
<Stack
@@ -446,7 +447,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
446447
case 'Thumbnail':
447448
return <div>
448449
<div className={styles.titleContainer}>
449-
<Icon className={styles.fieldIcon} iconName={"photo2"} />
450+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "photo2"} />
450451
{labelEl}
451452
</div>
452453
<Stack
@@ -493,7 +494,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
493494
case 'TaxonomyFieldTypeMulti':
494495
return <div className={styles.fieldContainer}>
495496
<div className={styles.titleContainer}>
496-
<Icon className={styles.fieldIcon} iconName={"BulletedTreeList"} />
497+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "BulletedTreeList"} />
497498
{labelEl}
498499
</div>
499500
<div className={styles.pickersContainer}>
@@ -518,7 +519,7 @@ export class DynamicField extends React.Component<IDynamicFieldProps, IDynamicFi
518519
case 'TaxonomyFieldType':
519520
return <div className={styles.fieldContainer}>
520521
<div className={styles.titleContainer}>
521-
<Icon className={styles.fieldIcon} iconName={"BulletedTreeList"} />
522+
<Icon className={styles.fieldIcon} iconName={customIcon ?? "BulletedTreeList"} />
522523
{labelEl}
523524
</div>
524525
<div className={styles.pickersContainer}>

src/controls/dynamicForm/dynamicField/IDynamicFieldProps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,6 @@ export interface IDynamicFieldProps {
8989
maximumValue?: number;
9090
minimumValue?: number;
9191
showAsPercentage?: boolean;
92+
customIcon?: string;
9293
orderBy?: string;
9394
}

src/webparts/controlsTest/components/ControlsTest.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,9 @@ export default class ControlsTest extends React.Component<IControlsTestProps, IC
818818
dynamicFormListItemId = Number(this.props.dynamicFormListItemId);
819819
}
820820

821+
const dynamicFormCustomTitleIcon: {[key: string]: string} = {};
822+
dynamicFormCustomTitleIcon["Title"] = "FavoriteStar";
823+
821824
// Size options for the icon size dropdown
822825
const sizeOptions: IDropdownOption[] = [
823826
{
@@ -962,19 +965,20 @@ export default class ControlsTest extends React.Component<IControlsTestProps, IC
962965
</div>
963966
<div id="DynamicFormDiv" className={styles.container} hidden={!controlVisibility.DynamicForm}>
964967
<div className="ms-font-m">
965-
<DynamicForm
966-
key={this.props.dynamicFormListId}
967-
context={this.props.context}
968-
listId={this.props.dynamicFormListId}
969-
listItemId={dynamicFormListItemId}
968+
<DynamicForm
969+
key={this.props.dynamicFormListId}
970+
context={this.props.context}
971+
listId={this.props.dynamicFormListId}
972+
listItemId={dynamicFormListItemId}
970973
validationErrorDialogProps={this.props.dynamicFormErrorDialogEnabled ? { showDialogOnValidationError: true } : undefined}
971974
returnListItemInstanceOnSubmit={true}
972-
onCancelled={() => { console.log('Cancelled'); }}
975+
onCancelled={() => { console.log('Cancelled'); }}
973976
onSubmitted={async (data, item) => { let itemdata = await item.get(); console.log('Saved item', itemdata)}}
974977
useClientSideValidation={this.props.dynamicFormClientSideValidationEnabled}
975978
useFieldValidation={this.props.dynamicFormFieldValidationEnabled}
976979
useCustomFormatting={this.props.dynamicFormCustomFormattingEnabled}
977980
enableFileSelection={this.props.dynamicFormFileSelectionEnabled}
981+
customIcons={dynamicFormCustomTitleIcon}
978982
/>
979983
</div>
980984
</div>
@@ -2591,5 +2595,5 @@ export default class ControlsTest extends React.Component<IControlsTestProps, IC
25912595

25922596
// private _onFolderSelect = (folder: IFolder): void => {
25932597
// console.log('selected folder', folder);
2594-
//
2598+
//
25952599
}

0 commit comments

Comments
 (0)