Skip to content
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

Required prop for Taxonomy Picker #600

Merged
merged 2 commits into from
Jul 3, 2020
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
3 changes: 3 additions & 0 deletions docs/documentation/docs/controls/TaxonomyPicker.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ The TaxonomyPicker control can be configured with the following properties:
| hideTagsNotAvailableForTagging | boolean | no | Specifies if the tags marked with 'Available for tagging' = false should be hidden |
| hideDeprecatedTags | boolean | no | Specifies if deprecated tags should be hidden |
| placeholder | string | no | Short text hint to display in empty picker |
| errorMessage | string | no | Static error message displayed below the text field. Use `onGetErrorMessage` to dynamically change the error message displayed (if any) based on the current value. `errorMessage` and `onGetErrorMessage` are mutually exclusive (`errorMessage` takes precedence). |
| onGetErrorMessage | (value: IPickerTerms) => string \| Promise&lt;string&gt; | no | The method is used to get the validation error message and determine whether the input value is valid or not. Mutually exclusive with the static string `errorMessage` (it will take precedence over this).<br />When it returns string:<ul><li>If valid, it returns empty string.</li><li>If invalid, it returns the error message string and the text field will</li><li>show a red border and show an error message below the text field.</li></ul><br />When it returns Promise&lt;string&gt;:<ul><li>The resolved value is display as error message.</li><li>The rejected, the value is thrown away.</li></ul> |
| required | boolean | no | Specifies if to display an asterisk near the label. Note that error message should be specified in `onGetErrorMessage` or `errorMessage` |

Interface `IPickerTerm`

Expand Down
2 changes: 1 addition & 1 deletion src/controls/taxonomyPicker/ErrorMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface IFieldErrorMessageProps {
*/
export default class FieldErrorMessage extends React.Component<IFieldErrorMessageProps> {
public render(): JSX.Element {
if (this.props.errorMessage !== 'undefined' && this.props.errorMessage !== null && this.props.errorMessage !== '') {
if (this.props.errorMessage !== undefined && this.props.errorMessage !== null && this.props.errorMessage !== '') {
return (
<div aria-live="assertive">
<p className={`ms-TextField-errorMessage ${styles.errorMessage}`}>
Expand Down
12 changes: 12 additions & 0 deletions src/controls/taxonomyPicker/ITaxonomyPicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export interface ITaxonomyPickerProps {

/**
* The method is used to get the validation error message and determine whether the input value is valid or not.
* Mutually exclusive with the static string errorMessage (it will take precedence over this).
*
* When it returns string:
* - If valid, it returns empty string.
Expand All @@ -94,10 +95,21 @@ export interface ITaxonomyPickerProps {
*/
onGetErrorMessage?: (value: IPickerTerms) => string | Promise<string>;

/**
* Static error message displayed below the text field. Use onGetErrorMessage to dynamically change the error message displayed (if any) based on the current value. errorMessage and onGetErrorMessage are mutually exclusive (errorMessage takes precedence).
*/
errorMessage?: string;

/**
* onChange Event
*/
onChange?: (newValue?: IPickerTerms) => void;

/**
* Specifies if to display an asterisk near the label.
* Note that error message should be specified in onGetErrorMessage
*/
required?: boolean;
}

/**
Expand Down
79 changes: 68 additions & 11 deletions src/controls/taxonomyPicker/TaxonomyPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
termSetAndTerms: null,
loaded: false,
openPanel: false,
errorMessage: ''
errorMessage: props.errorMessage
};

this.onOpenPanel = this.onOpenPanel.bind(this);
Expand All @@ -69,12 +69,21 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
/**
* componentWillUpdate lifecycle hook
*/
public componentDidUpdate(prevProps: ITaxonomyPickerProps): void {
public async componentDidUpdate(prevProps: ITaxonomyPickerProps): Promise<void> {
let newState: ITaxonomyPickerState | undefined;
// Check if the initial values objects are not equal, if that is the case, data can be refreshed
if (!isEqual(this.props.initialValues, prevProps.initialValues)) {
this.setState({
newState = {
activeNodes: this.props.initialValues || []
});
};
}

if (this.props.errorMessage) {
if (!newState) {
newState = {};
}

newState.errorMessage = this.props.errorMessage;
}
}

Expand Down Expand Up @@ -158,8 +167,8 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
private onSave(): void {
this.cancel = false;
this.onClosePanel();
// Trigger the onChange event
this.props.onChange(this.state.activeNodes);

this.validate(this.state.activeNodes);
}

/**
Expand Down Expand Up @@ -210,10 +219,11 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
* @param node
*/
private termsFromPickerChanged(terms: IPickerTerms) {
this.props.onChange(terms);
this.setState({
activeNodes: terms
});

this.validate(terms);
}


Expand All @@ -236,7 +246,7 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
* @param isChecked
*/
private termSetSelectedChange = (termSet: ITermSet, isChecked: boolean) => {
const ts: ITermSet = {...termSet};
const ts: ITermSet = { ...termSet };
// Clean /Guid.../ from the ID
ts.Id = this.termsService.cleanGuid(ts.Id);
// Create a term for the termset
Expand All @@ -257,6 +267,52 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
this.termsChanged(term, isChecked);
}

private validate = async (value: IPickerTerms): Promise<void> => {
if (this.props.errorMessage || !this.props.onGetErrorMessage) { // ignoring all onGetErrorMessage logic
this.validated(value);
return;
}

const result: string | PromiseLike<string> = this.props.onGetErrorMessage(value || []);

if (!result) {
this.validated(value);
return;
}

if (typeof result === 'string') {
if (!result) {
this.validated(value);
}
else {
this.setState({
errorMessage: result
});
}
}
else {
try {
const resolvedResult = await result;

if (!resolvedResult) {
this.validated(value);
}
else {
this.setState({
errorMessage: resolvedResult
});
}
}
catch (err) {
this.validated(value);
}
}
}

private validated = (value: IPickerTerms): void => {
this.props.onChange(value);
}

/**
* Renders the SPListpicker controls with Office UI Fabric
*/
Expand All @@ -267,11 +323,12 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
disabled,
isTermSetSelectable,
allowMultipleSelections,
disabledTermIds,disableChildrenOfDisabledParents,
disabledTermIds, disableChildrenOfDisabledParents,
placeholder,
panelTitle,
anchorId,
termActions
termActions,
required
} = this.props;

const {
Expand All @@ -284,7 +341,7 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon

return (
<div>
{label && <Label>{label}</Label>}
{label && <Label required={required}>{label}</Label>}
<div className={styles.termField}>
<div className={styles.termFieldInput}>
<TermPicker
Expand Down
7 changes: 5 additions & 2 deletions src/webparts/controlsTest/components/ControlsTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -643,13 +643,16 @@ export default class ControlsTest extends React.Component<IControlsTestProps, IC

<TaxonomyPicker
allowMultipleSelections={true}
termsetNameOrID="e813224c-bb1b-4086-b828-3d71434ddcd7" // id to termset that has a default sort
termsetNameOrID="8ea5ac06-fd7c-4269-8d0d-02f541df8eb9" // id to termset that has a default sort
panelTitle="Select Default Sorted Term"
label="Service Picker"
context={this.props.context}
onChange={this.onServicePickerChange}
isTermSetSelectable={false}
placeholder="Select service"
required={true}
errorMessage='this field is required'
onGetErrorMessage={(value) => { return 'comment errorMessage to see this one'; }}
/>

<TaxonomyPicker
Expand Down Expand Up @@ -1250,7 +1253,7 @@ export default class ControlsTest extends React.Component<IControlsTestProps, IC
//limiterIcon={"NumberedListText"}
/>
</div>

<div>
<FieldCollectionData
key={"FieldCollectionData"}
Expand Down