Skip to content

Commit b484e17

Browse files
💡Added support to ModernTaxonomyPicker in DynamicForm - Fix 1275 [Repo Rescuer Challenge] (#1962)
* InitialCommit - Fix 1275 * bump-updated documentation * Resolved comments and conflicts * Resolved conflicts as suggested * Removed anchor term guid from ModernTaxonomyPicker * Resolving comments from Michael * Roll-back on spfx-fast-serve-helpers version to be explicit
1 parent 7a8e182 commit b484e17

10 files changed

Lines changed: 327 additions & 108 deletions

File tree

‎.eslintrc.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,4 +325,4 @@ module.exports = {
325325
}
326326
}
327327
]
328-
};
328+
};

‎docs/documentation/docs/controls/DynamicForm.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,10 @@ The `DynamicForm` can be configured with the following properties:
6666
| respectEtag | boolean | no | Specifies if the form should respect the ETag of the item. Default - `true` |
6767
| saveDisabled | boolean | no | Specifies if save button is disabled. |
6868
| validationErrorDialogProps | IValidationErrorDialogProps | no | Specifies validation error dialog properties |
69-
| 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. |
69+
| 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. |
7070
| storeLastActiveTab | boolean | no | When uploading files: Specifies if last active tab will be stored after the Upload panel has been closed. Note: the value of selected tab is stored in the queryString hash. Default - `true` |
7171
| folderPath | string | no | Server relative or library relative folder to create the item in. This option is only available for document libraries and works only when the contentTypeId is specified and has a base type of type Document or Folder. Defaults to the root folder of the library. |
72+
| useModernTaxonomyPicker | boolean | no | Specifies if the form should render [ModernTaxonomyPicker](./ModernTaxonomyPicker.md) control for Managed metadata fields. If set to `true`, Dynamic form will render ModernTaxonomyPicker control. If set to `false`, Dynamic form will render TaxonomyPicker control. Default is `false` |
7273
| className | string | no | Set CSS Class. |
7374
| styles | IStyleFunctionOrObject<IDynamicFormStyleProps, [IDynamicFormStyles](#idynamicformstyles-interface)> | no | Styles to apply on control. See the example [here](#how-to-use-styles-property) |
7475

‎src/controls/dynamicForm/DynamicForm.tsx‎

Lines changed: 230 additions & 69 deletions
Large diffs are not rendered by default.

‎src/controls/dynamicForm/IDynamicFormProps.ts‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,19 @@ export interface IDynamicFormProps {
142142
storeLastActiveTab?: boolean;
143143

144144
/**
145-
* Library relative folder to create the item in.
146-
* This option is only available for document libraries and works only when the contentTypeId is specified and has a base type of type Document or Folder.
145+
* Library relative folder to create the item in.
146+
* This option is only available for document libraries and works only when the contentTypeId is specified and has a base type of type Document or Folder.
147147
* Defaults to the root folder.
148148
*/
149149
folderPath?: string;
150+
151+
/**
152+
* Set to true to use the Modern Taxonomy Picker (ModernTaxonomyPicker).
153+
* Set to false to use the classic TaxonomyPicker.
154+
* Default is false
155+
*/
156+
useModernTaxonomyPicker?: boolean;
157+
150158
/**
151159
* Call to provide customized styling
152160
* Read https://github.com/microsoft/fluentui/blob/master/docs/react-wiki-archive/Component-Styling.md#using-a-styleable-component for more information

‎src/controls/dynamicForm/dynamicField/DynamicField.tsx‎

Lines changed: 73 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ import { IPickerTerms, TaxonomyPicker } from '../../taxonomyPicker';
2222
import { IDynamicFieldProps, IDynamicFieldStyleProps, IDynamicFieldStyles } from './IDynamicFieldProps';
2323
import { IDynamicFieldState } from './IDynamicFieldState';
2424
import CurrencyMap from "../CurrencyMap";
25+
import { ModernTaxonomyPicker } from '../../modernTaxonomyPicker';
2526
import { classNamesFunction, IProcessedStyleSet, styled } from '@fluentui/react';
2627
import { getFluentUIThemeOrDefault } from '../../../common/utilities/ThemeUtility';
2728
import { getFieldStyles } from './DynamicField.styles';
2829

30+
2931
const getClassNames = classNamesFunction<IDynamicFieldStyleProps, IDynamicFieldStyles>();
3032

3133
export class DynamicFieldBase extends React.Component<IDynamicFieldProps, IDynamicFieldState> {
@@ -92,7 +94,8 @@ export class DynamicFieldBase extends React.Component<IDynamicFieldProps, IDynam
9294
minimumValue,
9395
itemsQueryCountLimit,
9496
customIcon,
95-
orderBy
97+
orderBy,
98+
useModernTaxonomyPickerControl
9699
} = this.props;
97100

98101
const {
@@ -516,21 +519,39 @@ export class DynamicFieldBase extends React.Component<IDynamicFieldProps, IDynam
516519
<Icon className={styles.fieldIcon} iconName={customIcon ?? "BulletedTreeList"} />
517520
{labelEl}
518521
</div>
519-
<div className={styles.pickersContainer}>
520-
<TaxonomyPicker
521-
label=""
522-
disabled={disabled}
523-
initialValues={valueToDisplay !== undefined ? valueToDisplay : defaultValue}
524-
placeholder={placeholder}
525-
allowMultipleSelections={true}
526-
termsetNameOrID={fieldTermSetId}
527-
anchorId={fieldAnchorId}
528-
panelTitle={strings.DynamicFormTermPanelTitle}
529-
context={context}
530-
onChange={(newValue?: IPickerTerms) => { this.onChange(newValue, true); }}
531-
isTermSetSelectable={false}
532-
/>
533-
</div>
522+
{useModernTaxonomyPickerControl ?
523+
<div className={styles.pickersContainer}>
524+
<ModernTaxonomyPicker
525+
label=""
526+
disabled={disabled}
527+
initialValues={valueToDisplay !== undefined ? valueToDisplay : defaultValue}
528+
placeHolder={placeholder}
529+
allowMultipleSelections={true}
530+
termSetId={fieldTermSetId}
531+
anchorTermId={fieldAnchorId}
532+
panelTitle={strings.DynamicFormTermPanelTitle}
533+
context={context}
534+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
535+
onChange={(newValue?: any) => { this.onChange(newValue, true); }}
536+
/>
537+
</div>
538+
:
539+
<div className={styles.pickersContainer}>
540+
<TaxonomyPicker
541+
label=""
542+
disabled={disabled}
543+
initialValues={valueToDisplay !== undefined ? valueToDisplay : defaultValue}
544+
placeholder={placeholder}
545+
allowMultipleSelections={true}
546+
termsetNameOrID={fieldTermSetId}
547+
anchorId={fieldAnchorId}
548+
panelTitle={strings.DynamicFormTermPanelTitle}
549+
context={context}
550+
onChange={(newValue?: IPickerTerms) => { this.onChange(newValue, true); }}
551+
isTermSetSelectable={false}
552+
/>
553+
</div>
554+
}
534555
{descriptionEl}
535556
{errorTextEl}
536557
</div>;
@@ -541,20 +562,39 @@ export class DynamicFieldBase extends React.Component<IDynamicFieldProps, IDynam
541562
<Icon className={styles.fieldIcon} iconName={customIcon ?? "BulletedTreeList"} />
542563
{labelEl}
543564
</div>
544-
<div className={styles.pickersContainer}>
545-
<TaxonomyPicker
546-
label=""
547-
disabled={disabled}
548-
initialValues={valueToDisplay !== undefined ? valueToDisplay : defaultValue}
549-
placeholder={placeholder}
550-
allowMultipleSelections={false}
551-
termsetNameOrID={fieldTermSetId}
552-
anchorId={fieldAnchorId}
553-
panelTitle={strings.DynamicFormTermPanelTitle}
554-
context={context}
555-
onChange={(newValue?: IPickerTerms) => { this.onChange(newValue, true); }}
556-
isTermSetSelectable={false} />
557-
</div>
565+
{useModernTaxonomyPickerControl ?
566+
<div className={styles.pickersContainer}>
567+
<ModernTaxonomyPicker
568+
label=""
569+
disabled={disabled}
570+
initialValues={valueToDisplay !== undefined ? [valueToDisplay] : defaultValue}
571+
placeHolder={placeholder}
572+
allowMultipleSelections={false}
573+
termSetId={fieldTermSetId}
574+
anchorTermId={fieldAnchorId}
575+
panelTitle={strings.DynamicFormTermPanelTitle}
576+
context={context}
577+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
578+
onChange={(newValue?: any) => { this.onChange(newValue, true); }}
579+
/>
580+
</div>
581+
:
582+
<div className={styles.pickersContainer}>
583+
<TaxonomyPicker
584+
label=""
585+
disabled={disabled}
586+
initialValues={valueToDisplay !== undefined ? valueToDisplay : defaultValue}
587+
placeholder={placeholder}
588+
allowMultipleSelections={false}
589+
termsetNameOrID={fieldTermSetId}
590+
anchorId={fieldAnchorId}
591+
panelTitle={strings.DynamicFormTermPanelTitle}
592+
context={context}
593+
onChange={(newValue?: IPickerTerms) => { this.onChange(newValue, true); }}
594+
isTermSetSelectable={false}
595+
/>
596+
</div>
597+
}
558598
{descriptionEl}
559599
{errorTextEl}
560600
</div>;
@@ -654,20 +694,19 @@ export class DynamicFieldBase extends React.Component<IDynamicFieldProps, IDynam
654694
const {
655695
changedValue
656696
} = this.state;
657-
697+
658698
const { value, newValue, required,listItemId } = this.props;
659699

660700
if (listItemId !== undefined && listItemId !== null) {
661701
if (newValue === undefined) {
662702
return required && (changedValue === undefined || changedValue === '' || changedValue === null || this.isEmptyArray(changedValue))
663-
&& (value === undefined || value === '' || value === null || this.isEmptyArray(value)) || this.checkUserArrayIsEmpty(value)) ? strings.DynamicFormRequiredErrorMessage : null;
703+
&& (value === undefined || value === '' || value === null || this.isEmptyArray(value) || this.checkUserArrayIsEmpty(value)) ? strings.DynamicFormRequiredErrorMessage : null;
664704
} else {
665-
return required && (changedValue === undefined || changedValue === '' || changedValue === null || this.isEmptyArray(changedValue)) || this.checkUserArrayIsEmpty(value)) ? strings.DynamicFormRequiredErrorMessage : null;
705+
return required && (changedValue === undefined || changedValue === '' || changedValue === null || this.isEmptyArray(changedValue) || this.checkUserArrayIsEmpty(value)) ? strings.DynamicFormRequiredErrorMessage : null;
666706
}
667707
}
668708

669709
return null;
670-
671710
}
672711

673712
private getNumberErrorText = (): string => {

‎src/controls/dynamicForm/dynamicField/IDynamicFieldProps.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ export interface IDynamicFieldProps {
8080
/** Used for files / image uploads */
8181
additionalData?: FieldChangeAdditionalData;
8282

83+
/** Used to Render TaxonomyPicker or ModernTaxonomyPicker */
84+
useModernTaxonomyPickerControl?: boolean;
85+
8386
// Related to various field types
8487
options?: IDropdownOption[];
8588
isRichText?: boolean;

‎src/webparts/controlsTest/ControlsTestWebPart.manifest.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"dynamicFormClientSideValidationEnabled": true,
3131
"dynamicFormFieldValidationEnabled" : true,
3232
"dynamicFormFileSelectionEnabled": false,
33+
"dynamicFormToggleTaxonomyPicker": false,
3334
"controlVisibility": {
3435
"all": false,
3536
"AccessibleAccordion": false,
@@ -93,4 +94,4 @@
9394
}
9495
}
9596
]
96-
}
97+
}

‎src/webparts/controlsTest/ControlsTestWebPart.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
107107
dynamicFormClientSideValidationEnabled: this.properties.dynamicFormClientSideValidationEnabled,
108108
dynamicFormFieldValidationEnabled: this.properties.dynamicFormFieldValidationEnabled,
109109
dynamicFormFileSelectionEnabled: this.properties.dynamicFormFileSelectionEnabled,
110+
dynamicFormToggleTaxonomyPicker: this.properties.dynamicFormToggleTaxonomyPicker,
110111
onOpenPropertyPane: () => {
111112
this.context.propertyPane.open();
112113
},
@@ -178,6 +179,9 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
178179
PropertyPaneToggle('dynamicFormFileSelectionEnabled', {
179180
label: 'Dynamic Form File Selection'
180181
}),
182+
PropertyPaneToggle('dynamicFormToggleTaxonomyPicker', {
183+
label: 'Dynamic Form Use Modern Taxonomy Picker'
184+
}),
181185
]
182186
},
183187
{

‎src/webparts/controlsTest/IControlsTestWebPartProps.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@ export interface IControlsTestWebPartProps {
3232
dynamicFormClientSideValidationEnabled: boolean;
3333
dynamicFormFieldValidationEnabled: boolean;
3434
dynamicFormFileSelectionEnabled: boolean;
35+
dynamicFormToggleTaxonomyPicker: boolean;
3536
controlVisibility: ControlVisibility
3637
}

‎src/webparts/controlsTest/components/ControlsTest.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,7 @@ export default class ControlsTest extends React.Component<IControlsTestProps, IC
11491149
useCustomFormatting={this.props.dynamicFormCustomFormattingEnabled}
11501150
enableFileSelection={this.props.dynamicFormFileSelectionEnabled}
11511151
customIcons={dynamicFormCustomTitleIcon}
1152+
useModernTaxonomyPicker={this.props.dynamicFormToggleTaxonomyPicker}
11521153
/>
11531154
</div>
11541155
</div>

0 commit comments

Comments
 (0)