Skip to content

💡Added support to ModernTaxonomyPicker in DynamicForm - Fix 1275 [Repo Rescuer Challenge] #1962

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,4 @@ module.exports = {
}
}
]
};
};
3 changes: 2 additions & 1 deletion docs/documentation/docs/controls/DynamicForm.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ The `DynamicForm` can be configured with the following properties:
| respectEtag | boolean | no | Specifies if the form should respect the ETag of the item. Default - `true` |
| saveDisabled | boolean | no | Specifies if save button is disabled. |
| validationErrorDialogProps | IValidationErrorDialogProps | no | Specifies validation error dialog properties |
| 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. |
| 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. |
| 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` |
| 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. |
| 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` |
| className | string | no | Set CSS Class. |
| styles | IStyleFunctionOrObject<IDynamicFormStyleProps, [IDynamicFormStyles](#idynamicformstyles-interface)> | no | Styles to apply on control. See the example [here](#how-to-use-styles-property) |

Expand Down
299 changes: 230 additions & 69 deletions src/controls/dynamicForm/DynamicForm.tsx

Large diffs are not rendered by default.

12 changes: 10 additions & 2 deletions src/controls/dynamicForm/IDynamicFormProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,19 @@ export interface IDynamicFormProps {
storeLastActiveTab?: boolean;

/**
* 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.
* 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.
*/
folderPath?: string;

/**
* Set to true to use the Modern Taxonomy Picker (ModernTaxonomyPicker).
* Set to false to use the classic TaxonomyPicker.
* Default is false
*/
useModernTaxonomyPicker?: boolean;

/**
* Call to provide customized styling
* Read https://github.com/microsoft/fluentui/blob/master/docs/react-wiki-archive/Component-Styling.md#using-a-styleable-component for more information
Expand Down
107 changes: 73 additions & 34 deletions src/controls/dynamicForm/dynamicField/DynamicField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ import { IPickerTerms, TaxonomyPicker } from '../../taxonomyPicker';
import { IDynamicFieldProps, IDynamicFieldStyleProps, IDynamicFieldStyles } from './IDynamicFieldProps';
import { IDynamicFieldState } from './IDynamicFieldState';
import CurrencyMap from "../CurrencyMap";
import { ModernTaxonomyPicker } from '../../modernTaxonomyPicker';
import { classNamesFunction, IProcessedStyleSet, styled } from '@fluentui/react';
import { getFluentUIThemeOrDefault } from '../../../common/utilities/ThemeUtility';
import { getFieldStyles } from './DynamicField.styles';


const getClassNames = classNamesFunction<IDynamicFieldStyleProps, IDynamicFieldStyles>();

export class DynamicFieldBase extends React.Component<IDynamicFieldProps, IDynamicFieldState> {
Expand Down Expand Up @@ -92,7 +94,8 @@ export class DynamicFieldBase extends React.Component<IDynamicFieldProps, IDynam
minimumValue,
itemsQueryCountLimit,
customIcon,
orderBy
orderBy,
useModernTaxonomyPickerControl
} = this.props;

const {
Expand Down Expand Up @@ -516,21 +519,39 @@ export class DynamicFieldBase extends React.Component<IDynamicFieldProps, IDynam
<Icon className={styles.fieldIcon} iconName={customIcon ?? "BulletedTreeList"} />
{labelEl}
</div>
<div className={styles.pickersContainer}>
<TaxonomyPicker
label=""
disabled={disabled}
initialValues={valueToDisplay !== undefined ? valueToDisplay : defaultValue}
placeholder={placeholder}
allowMultipleSelections={true}
termsetNameOrID={fieldTermSetId}
anchorId={fieldAnchorId}
panelTitle={strings.DynamicFormTermPanelTitle}
context={context}
onChange={(newValue?: IPickerTerms) => { this.onChange(newValue, true); }}
isTermSetSelectable={false}
/>
</div>
{useModernTaxonomyPickerControl ?
<div className={styles.pickersContainer}>
<ModernTaxonomyPicker
label=""
disabled={disabled}
initialValues={valueToDisplay !== undefined ? valueToDisplay : defaultValue}
placeHolder={placeholder}
allowMultipleSelections={true}
termSetId={fieldTermSetId}
anchorTermId={fieldAnchorId}
panelTitle={strings.DynamicFormTermPanelTitle}
context={context}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onChange={(newValue?: any) => { this.onChange(newValue, true); }}
/>
</div>
:
<div className={styles.pickersContainer}>
<TaxonomyPicker
label=""
disabled={disabled}
initialValues={valueToDisplay !== undefined ? valueToDisplay : defaultValue}
placeholder={placeholder}
allowMultipleSelections={true}
termsetNameOrID={fieldTermSetId}
anchorId={fieldAnchorId}
panelTitle={strings.DynamicFormTermPanelTitle}
context={context}
onChange={(newValue?: IPickerTerms) => { this.onChange(newValue, true); }}
isTermSetSelectable={false}
/>
</div>
}
{descriptionEl}
{errorTextEl}
</div>;
Expand All @@ -541,20 +562,39 @@ export class DynamicFieldBase extends React.Component<IDynamicFieldProps, IDynam
<Icon className={styles.fieldIcon} iconName={customIcon ?? "BulletedTreeList"} />
{labelEl}
</div>
<div className={styles.pickersContainer}>
<TaxonomyPicker
label=""
disabled={disabled}
initialValues={valueToDisplay !== undefined ? valueToDisplay : defaultValue}
placeholder={placeholder}
allowMultipleSelections={false}
termsetNameOrID={fieldTermSetId}
anchorId={fieldAnchorId}
panelTitle={strings.DynamicFormTermPanelTitle}
context={context}
onChange={(newValue?: IPickerTerms) => { this.onChange(newValue, true); }}
isTermSetSelectable={false} />
</div>
{useModernTaxonomyPickerControl ?
<div className={styles.pickersContainer}>
<ModernTaxonomyPicker
label=""
disabled={disabled}
initialValues={valueToDisplay !== undefined ? [valueToDisplay] : defaultValue}
placeHolder={placeholder}
allowMultipleSelections={false}
termSetId={fieldTermSetId}
anchorTermId={fieldAnchorId}
panelTitle={strings.DynamicFormTermPanelTitle}
context={context}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onChange={(newValue?: any) => { this.onChange(newValue, true); }}
/>
</div>
:
<div className={styles.pickersContainer}>
<TaxonomyPicker
label=""
disabled={disabled}
initialValues={valueToDisplay !== undefined ? valueToDisplay : defaultValue}
placeholder={placeholder}
allowMultipleSelections={false}
termsetNameOrID={fieldTermSetId}
anchorId={fieldAnchorId}
panelTitle={strings.DynamicFormTermPanelTitle}
context={context}
onChange={(newValue?: IPickerTerms) => { this.onChange(newValue, true); }}
isTermSetSelectable={false}
/>
</div>
}
{descriptionEl}
{errorTextEl}
</div>;
Expand Down Expand Up @@ -654,20 +694,19 @@ export class DynamicFieldBase extends React.Component<IDynamicFieldProps, IDynam
const {
changedValue
} = this.state;

const { value, newValue, required,listItemId } = this.props;

if (listItemId !== undefined && listItemId !== null) {
if (newValue === undefined) {
return required && (changedValue === undefined || changedValue === '' || changedValue === null || this.isEmptyArray(changedValue))
&& (value === undefined || value === '' || value === null || this.isEmptyArray(value)) || this.checkUserArrayIsEmpty(value)) ? strings.DynamicFormRequiredErrorMessage : null;
&& (value === undefined || value === '' || value === null || this.isEmptyArray(value) || this.checkUserArrayIsEmpty(value)) ? strings.DynamicFormRequiredErrorMessage : null;
} else {
return required && (changedValue === undefined || changedValue === '' || changedValue === null || this.isEmptyArray(changedValue)) || this.checkUserArrayIsEmpty(value)) ? strings.DynamicFormRequiredErrorMessage : null;
return required && (changedValue === undefined || changedValue === '' || changedValue === null || this.isEmptyArray(changedValue) || this.checkUserArrayIsEmpty(value)) ? strings.DynamicFormRequiredErrorMessage : null;
}
}

return null;

}

private getNumberErrorText = (): string => {
Expand Down
3 changes: 3 additions & 0 deletions src/controls/dynamicForm/dynamicField/IDynamicFieldProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ export interface IDynamicFieldProps {
/** Used for files / image uploads */
additionalData?: FieldChangeAdditionalData;

/** Used to Render TaxonomyPicker or ModernTaxonomyPicker */
useModernTaxonomyPickerControl?: boolean;

// Related to various field types
options?: IDropdownOption[];
isRichText?: boolean;
Expand Down
3 changes: 2 additions & 1 deletion src/webparts/controlsTest/ControlsTestWebPart.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"dynamicFormClientSideValidationEnabled": true,
"dynamicFormFieldValidationEnabled" : true,
"dynamicFormFileSelectionEnabled": false,
"dynamicFormToggleTaxonomyPicker": false,
"controlVisibility": {
"all": false,
"AccessibleAccordion": false,
Expand Down Expand Up @@ -93,4 +94,4 @@
}
}
]
}
}
4 changes: 4 additions & 0 deletions src/webparts/controlsTest/ControlsTestWebPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
dynamicFormClientSideValidationEnabled: this.properties.dynamicFormClientSideValidationEnabled,
dynamicFormFieldValidationEnabled: this.properties.dynamicFormFieldValidationEnabled,
dynamicFormFileSelectionEnabled: this.properties.dynamicFormFileSelectionEnabled,
dynamicFormToggleTaxonomyPicker: this.properties.dynamicFormToggleTaxonomyPicker,
onOpenPropertyPane: () => {
this.context.propertyPane.open();
},
Expand Down Expand Up @@ -178,6 +179,9 @@ export default class ControlsTestWebPart extends BaseClientSideWebPart<IControls
PropertyPaneToggle('dynamicFormFileSelectionEnabled', {
label: 'Dynamic Form File Selection'
}),
PropertyPaneToggle('dynamicFormToggleTaxonomyPicker', {
label: 'Dynamic Form Use Modern Taxonomy Picker'
}),
]
},
{
Expand Down
1 change: 1 addition & 0 deletions src/webparts/controlsTest/IControlsTestWebPartProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ export interface IControlsTestWebPartProps {
dynamicFormClientSideValidationEnabled: boolean;
dynamicFormFieldValidationEnabled: boolean;
dynamicFormFileSelectionEnabled: boolean;
dynamicFormToggleTaxonomyPicker: boolean;
controlVisibility: ControlVisibility
}
1 change: 1 addition & 0 deletions src/webparts/controlsTest/components/ControlsTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,7 @@ export default class ControlsTest extends React.Component<IControlsTestProps, IC
useCustomFormatting={this.props.dynamicFormCustomFormattingEnabled}
enableFileSelection={this.props.dynamicFormFileSelectionEnabled}
customIcons={dynamicFormCustomTitleIcon}
useModernTaxonomyPicker={this.props.dynamicFormToggleTaxonomyPicker}
/>
</div>
</div>
Expand Down