import * as React from 'react' ; import { Label } from 'office-ui-fabric-react/lib/Label' ; import { IChoiceGroupOption } from 'office-ui-fabric-react/lib/ChoiceGroup' ; import { Spinner , SpinnerSize , SpinnerType } from 'office-ui-fabric-react/lib/Spinner' ; import { Async } from 'office-ui-fabric-react/lib/Utilities' ; import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox' ; import { IPropertyFieldListMultiPickerHostProps , IPropertyFieldListMultiPickerHostState } from './IPropertyFieldListMultiPickerHost' ; import { ISPLists , ISPList } from './IPropertyFieldListPickerHost' ; import SPListPickerService from '../../services/SPListPickerService' ; import FieldErrorMessage from '../errorMessage/FieldErrorMessage' ; import * as telemetry from '../../common/telemetry' ; import { IPropertyFieldList } from './IPropertyFieldListPicker' ; import { setPropertyValue } from '../../helpers/GeneralHelper' ; /**
* Renders the controls for PropertyFieldSPListMultiplePicker component
*/ export default class PropertyFieldListMultiPickerHost extends React . Component < IPropertyFieldListMultiPickerHostProps , IPropertyFieldListMultiPickerHostState > { private loaded : boolean = false ; private async : Async ; private delayedValidate : ( value : string [ ] ) => void ; /**
    * Constructor
    */ constructor ( props ) { super ( props ) ; telemetry . track ( 'PropertyFieldListMultiPicker' , { disabled : props . disabled } ) ; this . onChanged = this . onChanged . bind ( this ) ; this . onSelectAllChanged = this . onSelectAllChanged . bind ( this ) ; this . state = { loadedLists : { value : [ ] } , results : [ ] , selectedKeys : [ ] , loaded : this . loaded , errorMessage : '' } ; this . async = new Async ( this ) ; this . validate = this . validate . bind ( this ) ; this . notifyAfterValidate = this . notifyAfterValidate . bind ( this ) ; this . delayedValidate = this . async . debounce ( this . validate , this . props . deferredValidationTime ) ; } public componentDidMount ( ) { this . loadLists ( ) ; } public componentDidUpdate ( prevProps , prevState ) { if ( this . props . baseTemplate !== prevProps . baseTemplate || this . props . webAbsoluteUrl !== prevProps . webAbsoluteUrl ) { this . loadLists ( ) ; } } /**
    * Loads the list from SharePoint current web site, or target site if specified by webRelativeUrl
    */ private async loadLists ( ) { const { context , selectedLists } = this . props ; const listService = new SPListPickerService ( this . props , context ) ; const listsToExclude = this . props . listsToExclude || [ ] ; let selectedListsKeys = [ ] ; if ( selectedLists && selectedLists . length ) { const firstItem = selectedLists [ 0 ] ; if ( typeof firstItem === 'string' ) { selectedListsKeys = selectedLists as string [ ] ; } else { selectedListsKeys = ( selectedLists as IPropertyFieldList [ ] ) . map ( sl => sl . id ) ; } } const options = [ ] ; const selectedKeys = [ ] ; const response = await listService . getLibs ( ) ; response . value . forEach ( ( list ) => { let isSelected = false ; let indexInExisting = - 1 ; if ( selectedListsKeys ) { indexInExisting = selectedListsKeys . indexOf ( list . Id ) ; } if ( indexInExisting > - 1 ) { isSelected = true ; selectedKeys . push ( list . Id ) ; } if ( listsToExclude . indexOf ( list . Title ) === - 1 && listsToExclude . indexOf ( list . Id ) === - 1 ) { options . push ( { key : list . Id , text : list . Title , checked : isSelected } ) ; } } ) ; this . loaded = true ; this . setState ( { loadedLists : response , results : options , selectedKeys : selectedKeys , loaded : true } ) ; } /**
    * Raises when a list has been selected
    */ private onChanged ( element , isChecked ) { if ( element ) { const value = ( element . currentTarget as any ) . value ; let selectedKeys = this . state . selectedKeys ; if ( isChecked === false ) { selectedKeys = selectedKeys . filter ( s => s !== value ) ; } else { selectedKeys . push ( value ) ; selectedKeys = selectedKeys . filter ( ( item , pos , self ) => { return self . indexOf ( item ) === pos ; } ) ; } this . setState ( { selectedKeys : selectedKeys } ) ; this . delayedValidate ( selectedKeys ) ; } } /**
     * Raises when the select all checkbox is changed
     */ private onSelectAllChanged ( element , isChecked ) { if ( element ) { let selectedKeys = new Array < string > ( ) ; const { results } = this . state ; if ( isChecked === true ) { results . forEach ( ( value ) => { selectedKeys . push ( value . key ) ; } ) ; } this . setState ( { selectedKeys : selectedKeys } ) ; this . delayedValidate ( selectedKeys ) ; } } /**
    * Validates the new custom field value
    */ private validate ( value ) { if ( this . props . onGetErrorMessage === null || typeof this . props . onGetErrorMessage === 'undefined' ) { this . notifyAfterValidate ( value ) ; return ; } const errResult = this . props . onGetErrorMessage ( value || [ ] ) ; if ( typeof errResult !== 'undefined' ) { if ( typeof errResult === 'string' ) { if ( errResult === '' ) { this . notifyAfterValidate ( value ) ; } this . setState ( { errorMessage : errResult } ) ; } else { errResult . then ( ( errorMessage ) => { if ( typeof errorMessage === 'undefined' || errorMessage === '' ) { this . notifyAfterValidate ( value ) ; } this . setState ( { errorMessage : errorMessage } ) ; } ) ; } } else { this . notifyAfterValidate ( value ) ; } } /**
    * Notifies the parent Web Part of a property value change
    */ private notifyAfterValidate ( newValue ) { const { onPropertyChange , onChange , selectedLists , targetProperty , properties , includeListTitleAndUrl } = this . props ; const { loadedLists } = this . state ; let propValue ; if ( ! newValue || ! newValue . length ) { propValue = [ ] ; } else { if ( includeListTitleAndUrl ) { propValue = loadedLists . value . filter ( l => newValue . indexOf ( l . Id ) !== - 1 ) . map ( l => { return { id : l . Id , title : l . Title , url : l . RootFolder . ServerRelativeUrl } ; } ) ; } else { propValue = [ ... newValue ] ; } } if ( onPropertyChange && newValue !== null ) { setPropertyValue ( properties , targetProperty , propValue ) ; onPropertyChange ( targetProperty , selectedLists , propValue ) ; if ( typeof onChange !== 'undefined' && onChange !== null ) { onChange ( targetProperty , propValue ) ; } } } /**
    * Called when the component will unmount
    */ public componentWillUnmount ( ) { this . async . dispose ( ) ; } /**
    * Renders the SPListMultiplePicker controls with Office UI  Fabric
    */ public render ( ) { const { selectedKeys , results , errorMessage } = this . state ; const { label , disabled , showSelectAll , selectAllInList , selectAllInListLabel , targetProperty } = this . props ; if ( this . loaded === false ) { return ( < div > < Label > { label } < /Label> < Spinner size = { SpinnerSize . medium } / > < /div>); } else { const styleOfLabel = { color : disabled === true ? '#A6A6A6' : 'auto' } ; return ( < div > { ( showSelectAll === false || selectAllInList === true ) && < Label > { label } < /Label>} { showSelectAll === true && < div style = { { marginBottom : '5px' } } className = 'ms-ChoiceField' > < Checkbox checked = { selectedKeys . length === results . length } label = { selectAllInList === true ? selectAllInListLabel : label } onChange = { this . onSelectAllChanged } styles = { { checkbox : { backgroundColor : ( selectedKeys . length > 0 ? '#f4f4f4' : 'inherit' ) , visibility : ( selectAllInList === false ? 'hidden' : 'visible' ) } } } /> < /div>} { results . map ( ( item , index ) => { const uniqueKey = targetProperty + '-' + item . key ; return ( < div style = { { marginBottom : '5px' } } className = 'ms-ChoiceField' key = { uniqueKey } > < Checkbox checked = { selectedKeys . indexOf ( item . key . toString ( ) ) >= 0 } disabled = { disabled } label = { item . text } onChange = { this . onChanged } inputProps = { { value : item . key } } /> < /div>); } ) } < FieldErrorMessage errorMessage = { errorMessage } /> < /div>); } } }