11import * as React from 'react' ;
22import { PrimaryButton , DefaultButton , IconButton } from 'office-ui-fabric-react/lib/Button' ;
33import { Panel , PanelType } from 'office-ui-fabric-react/lib/Panel' ;
4+ import { Autofill } from 'office-ui-fabric-react/lib/components/Autofill/Autofill' ;
45import { Spinner , SpinnerType } from 'office-ui-fabric-react/lib/Spinner' ;
56import { Label } from 'office-ui-fabric-react/lib/Label' ;
67import TermPicker from './TermPicker' ;
@@ -32,6 +33,7 @@ export const TERM_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQC
3233export class TaxonomyPicker extends React . Component < ITaxonomyPickerProps , ITaxonomyPickerState > {
3334 private termsService : SPTermStorePickerService ;
3435 private previousValues : IPickerTerms = [ ] ;
36+ private invalidTerm : string = null ;
3537 private cancel : boolean = true ;
3638
3739 /**
@@ -55,6 +57,9 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
5557 this . onSave = this . onSave . bind ( this ) ;
5658 this . termsChanged = this . termsChanged . bind ( this ) ;
5759 this . termsFromPickerChanged = this . termsFromPickerChanged . bind ( this ) ;
60+ this . onInputChange = this . onInputChange . bind ( this ) ;
61+ this . onBlur = this . onBlur . bind ( this ) ;
62+
5863 this . termsService = new SPTermStorePickerService ( this . props , this . props . context ) ;
5964 }
6065
@@ -101,7 +106,6 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
101106 * it checks, if all entries still exist in term store. if allowMultipleSelections is true. it have to validate all values
102107 */
103108 private async validateTerms ( ) : Promise < void > {
104-
105109 const {
106110 hideDeprecatedTags,
107111 hideTagsNotAvailableForTagging,
@@ -141,8 +145,6 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
141145 * Loads the list from SharePoint current web site
142146 */
143147 private loadTermStores ( ) : void {
144-
145-
146148 if ( this . props . termActions && this . props . termActions . initialize ) {
147149 this . props . termActions . initialize ( this . termsService ) ;
148150 // this.props.termActions.actions.forEach(x => {
@@ -276,7 +278,59 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
276278 this . validate ( terms ) ;
277279 }
278280
281+ /**
282+ * Shows an error message for any invalid input inside taxonomy picker control
283+ */
284+ private validateInputText ( ) : void {
285+ // Show error message, if any unresolved value exists inside taxonomy picker control
286+ if ( ! ! this . invalidTerm ) {
287+ // An unresolved value exists
288+ this . setState ( {
289+ errorMessage : strings . TaxonomyPickerInvalidTerms . replace ( '{0}' , this . invalidTerm )
290+ } ) ;
291+ }
292+ else {
293+ // There are no unresolved values
294+ this . setState ( {
295+ errorMessage : null
296+ } ) ;
297+ }
298+ }
299+
300+ /**
301+ * Triggers when input of taxonomy picker control changes
302+ */
303+ private onInputChange ( input : string ) : string {
304+ if ( ! input ) {
305+ const { validateInput } = this . props ;
306+ if ( ! ! validateInput ) {
307+ // Perform validation of input text, only if taxonomy picker is configured with validateInput={true} property.
308+ this . invalidTerm = null ;
309+ this . validateInputText ( ) ;
310+ }
311+ }
312+ return input ;
313+ }
279314
315+ /**
316+ * Triggers when taxonomy picker control loses focus
317+ */
318+ private onBlur ( event : React . FocusEvent < HTMLElement | Autofill > ) : void {
319+ const { validateInput } = this . props ;
320+ if ( ! ! validateInput ) {
321+ // Perform validation of input text, only if taxonomy picker is configured with validateInput={true} property.
322+ const target : HTMLInputElement = event . target as HTMLInputElement ;
323+ const targetValue = ! ! target ? target . value : null ;
324+ if ( ! ! targetValue ) {
325+ this . invalidTerm = targetValue ;
326+ }
327+ else {
328+ this . invalidTerm = null ;
329+ }
330+ this . validateInputText ( ) ;
331+ }
332+ }
333+
280334 /**
281335 * Gets the given node position in the active nodes collection
282336 * @param node
@@ -318,7 +372,6 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
318372 }
319373
320374 private validate = async ( value : IPickerTerms ) : Promise < void > => {
321-
322375 //
323376 // checking if there are any invalid nodes left after initial validation
324377 //
@@ -390,7 +443,8 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
390443 disabled,
391444 isTermSetSelectable,
392445 allowMultipleSelections,
393- disabledTermIds, disableChildrenOfDisabledParents,
446+ disabledTermIds,
447+ disableChildrenOfDisabledParents,
394448 placeholder,
395449 panelTitle,
396450 anchorId,
@@ -419,6 +473,8 @@ export class TaxonomyPicker extends React.Component<ITaxonomyPickerProps, ITaxon
419473 value = { activeNodes }
420474 isTermSetSelectable = { isTermSetSelectable }
421475 onChanged = { this . termsFromPickerChanged }
476+ onInputChange = { this . onInputChange }
477+ onBlur = { this . onBlur }
422478 allowMultipleSelections = { allowMultipleSelections }
423479 disabledTermIds = { disabledTermIds }
424480 disableChildrenOfDisabledParents = { disableChildrenOfDisabledParents }
0 commit comments