During customization of the complex form using SharePoint Framework, there is an additional effort required by developers to include taxonomy picker & people picker.
In this article, it is explained how taxonomy & people picker can be included in SPFx webpart using Reusable React Control.
Kindly refer this article to know the pre-requisite for creating SPFx web part.
Step 1) Open Windows Powershell.
Note: If SPFx solution already exists and only web part needs to be added to an existing solution, then directly jump to Step 5.
Step 2) Create a folder inside a directory by entering the below command, here for example
md ReactSPFxPnP
cd ReactSPFxPnP
yo @microsoft/SharePoint
Step 5) Once the project is created, open it in Visual Studio Code using the below command.
code .
npm install @pnp/spfx-controls-react --save --save-exact
Step 7) Import the following classes from react controls by adding the below code in ReactSPFxPnP.tsx file located under solution > src > webparts > reactSPFxPnP > components
import { TaxonomyPicker, IPickerTerms } from "@pnp/spfx-controls-react/lib/TaxonomyPicker";
import { PeoplePicker } from "@pnp/spfx-controls-react/lib/PeoplePicker";
Step 8) Replace the default render method inside in ReactSPFxPnP.tsx file located under solution > src > webparts > reactSPFxPnP > components
with the below code.
public render(): React.ReactElement<
IReactSpFxPnPProps
> {
return (
<
form
>
div
className={styles.reactSpFxPnP}>
className={styles.container}>
className={`ms-Grid-row ms-bgColor-neutralLight ms-fontColor-white ${styles.row}`}>
className
=
"ms-Grid-col ms-u-sm12 block"
TaxonomyPicker
allowMultipleSelections={true}
termsetNameOrID
"Countries"
panelTitle
"Select Term"
label
"Taxonomy Picker"
context={this.props.context}
onChange={this.onTaxPickerChange}
isTermSetSelectable={false}
/></
"ms-Grid-col ms-u-sm8 block"
PeoplePicker
titleText
"People Picker"
personSelectionLimit={3}
groupName={"Team Site Owners"} // Leave this blank in case you want to filter from all users
showtooltip={true}
isRequired={true}
disabled={false}
selectedItems={this._getPeoplePickerItems} />
</
);
}
Step 9) Add the below function inside the extend class from react component ReactSPFxPnP.tsx file located under solution > src > webparts > reactSPFxPnP > components.
private onTaxPickerChange(terms : IPickerTerms) {
this.setState({ termKey: terms[0].key.toString() });
console.log("Terms", terms);
private _getPeoplePickerItems(items: any[]) {
console.log('Items:', items);
Step 10) Replace the content inside IReactSpFxPnPProps.ts file located under solution > src > webparts > reactSPFxPnP > components
import { WebPartContext } from '@microsoft/sp-webpart-base';
export interface IReactSpFxPnPProps {
description: string;
context: WebPartContext;
Step 11) Include the context of the webpart & pass it along with the property by adding it in the file ReactSpFxPnPWebPart.ts located under solution > src > webparts > reactSPFxPnP
public render(): void {
const element: React.ReactElement<
> = React.createElement(
ReactSpFxPnP,
{
context: this.context,
description: this.properties.description
Step 12) Run the below command to see the output (see below video).
gulp serve
Building a complex form can vary based on the requirement, for this article, we will create an employee registration form.
Like any other MVC project, all fields required for the form need to be specified. Create a Model folder inside the project in parallel with components. Add a file name 'IReactSpFxPnP.ts' & include the below code.
import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
export interface IReactSpFxPnP {
selectedItems: any[];
name: string;
dpselectedItem?: { key: string | number | undefined };
termKey?: string | number;
dpselectedItems: IDropdownOption[];
disableToggle: boolean;
defaultChecked: boolean;
pplPickerType:string;
userIDs: number[];
userManagerIDs: number[];
hideDialog: boolean;
status: string;
isChecked: boolean;
showPanel: boolean;
required:string;
onSubmission:boolean;
termnCond:boolean;
Run the below command in Windows PowerShell to include PnP components.
npm install node-pnp-js --save
Create a list name "Employee Registration" in a SharePoint site and add columns specified in the below image Assuming a Term Group is created with the name "BU" and mapped with Projects column.
By including the below code we are creating a user interface which includes people picker, Taxonomy picker react controls inside our components. Replace this code export default class with the existing one in ReactSpFxPnP.tsx file located under Solution > src > webparts > components.
export default class ReactSpFxPnP extends React.Component<
, IReactSpFxPnP> {
constructor() {
super();
this.handleTitle = this.handleTitle.bind(this);
this.handleDesc = this.handleDesc.bind(this);
this._onCheckboxChange = this._onCheckboxChange.bind(this);
this._onRenderFooterContent = this._onRenderFooterContent.bind(this);
this.createItem = this.createItem.bind(this);
this.onTaxPickerChange = this.onTaxPickerChange.bind(this);
this._getManager = this._getManager.bind(this);
this.state = {
name:"",
description:"",
selectedItems: [],
hideDialog: true,
showPanel: false,
dpselectedItem: undefined,
dpselectedItems: [],
disableToggle:false,
defaultChecked:false,
termKey: undefined,
userIDs: [],
userManagerIDs: [],
pplPickerType: "",
status:"",
isChecked: false,
required:"This is required",
onSubmission:false,
termnCond:false,
const { dpselectedItem, dpselectedItems } = this.state;
const { name, description } = this.state;
pnp.setup({
spfxContext: this.props.context
});
"ms-Grid-col ms-u-sm4 block"
"ms-Label"
>Employee Name</
TextField
value={this.state.name} required={true} onChanged={this.handleTitle}
errorMessage={(this.state.name.length === 0 && this.state.onSubmission === true) ? this.state.required : ""}/>
>Job Description</
multiline autoAdjustHeight value={this.state.description} onChanged={this.handleDesc}
/>
>Project Assigned To</
><
br
allowMultipleSelections={false}
"BU"
"Select Assignment"
""
p
className={(this.state.termKey === undefined && this.state.onSubmission === true)? styles.fontRed : styles.hideElement}>This is required</
>Department</
Dropdown
placeHolder
"Select an Option"
id
"component"
selectedKey={dpselectedItem ? dpselectedItem.key : undefined}
ariaLabel
"Basic dropdown example"
options={[
{ key: 'Human Resource', text: 'Human Resource' },
{ key: 'Finance', text: 'Finance' },
{ key: 'Employee', text: 'Employee' }
]}
onChanged={this._changeState}
onFocus={this._log('onFocus called')}
onBlur={this._log('onBlur called')}
>External Hiring?</
Toggle
disabled={this.state.disableToggle}
checked={this.state.defaultChecked}
onAriaLabel
"This toggle is checked. Press to uncheck."
offAriaLabel
"This toggle is unchecked. Press to check."
onText
"On"
offText
"Off"
onChanged={(checked) =>this._changeSharing(checked)}
onFocus={() => console.log('onFocus called')}
onBlur={() => console.log('onBlur called')}
>Reporting Manager</
" "
personSelectionLimit={1}
groupName={""} // Leave this blank in case you want to filter from all users
showtooltip={false}
selectedItems={this._getManager}
errorMessage={(this.state.userManagerIDs.length === 0 && this.state.onSubmission === true) ? this.state.required : " "}
errorMessageclassName={styles.hideElementManager}
"ms-Grid-col ms-u-sm1 block"
Checkbox
onChange={this._onCheckboxChange} ariaDescribedBy={'descriptionID'} />
"ms-Grid-col ms-u-sm11 block"
span
className={`${styles.customFont}`}>I have read and agree to the terms & condition</
className={(this.state.termnCond === false && this.state.onSubmission === true)? styles.fontRed : styles.hideElement}>Please check the Terms & Condition</
"ms-Grid-col ms-u-sm6 block"
"ms-Grid-col ms-u-sm2 block"
PrimaryButton
text
"Create"
onClick={() => { this.validateForm(); }} />
DefaultButton
"Cancel"
onClick={() => { this.setState({}); }} />
Panel
isOpen={this.state.showPanel}
type={PanelType.smallFixedFar}
onDismiss={this._onClosePanel}
isFooterAtBottom={false}
headerText
"Are you sure you want to create site ?"
closeButtonAriaLabel
"Close"
onRenderFooterContent={this._onRenderFooterContent}
>Please check the details filled and click on Confirm button to create site.</
Dialog
hidden={this.state.hideDialog}
onDismiss={this._closeDialog}
dialogContentProps={{
type: DialogType.largeHeader,
title: 'Request Submitted Successfully',
subText: "" }}
modalProps={{
titleAriaId: 'myLabelId',
subtitleAriaId: 'mySubTextId',
isBlocking: false,
containerClassName: 'ms-dialogMainOverride'
}}>
dangerouslySetInnerHTML={{__html:this.state.status}}/>
DialogFooter
onClick={()=>this.gotoHomePage()} text="Okay" />
} }
Include the below code inside export default class in ReactSpFxPnP.tsx file located under Solution > src > webparts > components. This takes care of the validation (validateForm() function) of the form. All the values including people picker and taxonomy are maintained in State.
private onTaxPickerChange(terms : IPickerTerms) {
private _getManager(items: any[]) {
this.state.userManagerIDs.length = 0;
for (let item in items)
this.state.userManagerIDs.push(items[item].id);
console.log(items[item].id);
private _onRenderFooterContent = (): JSX.Element => {
onClick={this.createItem} style={{ marginRight: '8px' }}>
Confirm
onClick={this._onClosePanel}>Cancel</
private _log(str: string): () => void {
return (): void => {
console.log(str);
};
private _onClosePanel = () => {
this.setState({ showPanel: false });
private _onShowPanel = () => {
this.setState({ showPanel: true });
private _changeSharing(checked:any):void{
this.setState({defaultChecked: checked});
private _changeState = (item: IDropdownOption): void => {
console.log('here is the things updating...' + item.key + ' ' + item.text + ' ' + item.selected);
this.setState({ dpselectedItem: item });
if(item.text == "Employee")
this.setState({defaultChecked: false});
this.setState({disableToggle: true});
else
this.setState({disableToggle:false});
private handleTitle(value: string): void {
return this.setState({
name: value
private handleDesc(value: string): void {
description: value
private _onCheckboxChange(ev: React.FormEvent<
HTMLElement
>, isChecked: boolean): void {
console.log(`The option has been changed to ${isChecked}.`);
this.setState({termnCond: (isChecked)?true:false});
private _closeDialog = (): void => {
this.setState({ hideDialog: true });
private _showDialog = (status:string): void => {
this.setState({ hideDialog: false });
this.setState({ status: status });
private validateForm():void{
let allowCreate: boolean = true;
this.setState({ onSubmission : true });
if(this.state.name.length === 0)
allowCreate = false;
if(this.state.termKey === undefined)
if(allowCreate)
this._onShowPanel();
//do nothing
private gotoHomePage():void{
window.location.replace(this.props.siteUrl);
private createItem():void {
this._onClosePanel();
this._showDialog("Submitting Request");
console.log(this.state.termKey);
pnp.sp.web.lists.getByTitle("Employee Registeration").items.add({
Title: this.state.name,
Description: this.state.description,
Department: this.state.dpselectedItem.key,
Projects: {
__metadata: { "type": "SP.Taxonomy.TaxonomyFieldValue" },
Label: "1",
TermGuid: this.state.termKey,
WssId: -1
},
Reporting_x0020_ManagerId: this.state.userManagerIDs[0]
}).then((iar: ItemAddResult) => {
this.setState({ status: "Your request has been submitted sucessfully " });