diff --git a/docs/documentation/docs/controls/DynamicForm.md b/docs/documentation/docs/controls/DynamicForm.md
index 4aca7cc0a..f4870a18a 100644
--- a/docs/documentation/docs/controls/DynamicForm.md
+++ b/docs/documentation/docs/controls/DynamicForm.md
@@ -72,6 +72,7 @@ The `DynamicForm` can be configured with the following properties:
| 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) |
+| itemsQueryCountLimit | number | no | Number of items to display in the lookup fields of the form | |
## Validation Error Dialog Properties `IValidationErrorDialogProps`
diff --git a/src/controls/dynamicForm/DynamicForm.tsx b/src/controls/dynamicForm/DynamicForm.tsx
index dce87e453..d83d9bf5b 100644
--- a/src/controls/dynamicForm/DynamicForm.tsx
+++ b/src/controls/dynamicForm/DynamicForm.tsx
@@ -173,7 +173,7 @@ export class DynamicFormBase extends React.Component<
// Custom Formatting - Header
let headerContent: JSX.Element;
if (!customFormattingDisabled && customFormatting?.header) {
- headerContent =
+ headerContent =
{this._customFormatter.renderCustomFormatContent(customFormatting.header, this.getFormValuesForValidation(), true)}
}
@@ -196,8 +196,8 @@ export class DynamicFormBase extends React.Component<
let footerContent: JSX.Element;
if (!customFormattingDisabled && customFormatting?.footer) {
footerContent =
- {this._customFormatter.renderCustomFormatContent(customFormatting.footer, this.getFormValuesForValidation(), true)}
-
+ {this._customFormatter.renderCustomFormatContent(customFormatting.footer, this.getFormValuesForValidation(), true)}
+
}
// Content Type
@@ -227,20 +227,20 @@ export class DynamicFormBase extends React.Component<
{(bodySections.length > 0 && !customFormattingDisabled) && bodySections
.filter(bs => bs.fields.filter(bsf => hiddenByFormula.indexOf(bsf) < 0).length > 0)
.map((section, i) => (
- <>
- {section.displayname}
-
- {section.fields
- .filter(f => fieldCollection.find(fc => fc.label === f))
- .map((f, i) => (
-
- {this.renderField(fieldCollection.find(fc => fc.label === f) as IDynamicFieldProps)}
-
- ))}
-
- {i < bodySections.length - 1 &&
}
- >
- ))}
+ <>
+ {section.displayname}
+
+ {section.fields
+ .filter(f => fieldCollection.find(fc => fc.label === f))
+ .map((f, i) => (
+
+ {this.renderField(fieldCollection.find(fc => fc.label === f) as IDynamicFieldProps)}
+
+ ))}
+
+ {i < bodySections.length - 1 &&
}
+ >
+ ))}
{(bodySections.length === 0 || customFormattingDisabled) && fieldCollection.map((f, i) => this.renderField(f))}
{footerContent}
{!this.props.disabled && (
@@ -296,16 +296,16 @@ export class DynamicFormBase extends React.Component<
}
const sortedFields = customSort
- .map((sortColumn) => sortColumn.toLowerCase())
- .filter((normalizedSortColumn) => fMap.has(normalizedSortColumn))
- .map((normalizedSortColumn) => fMap.get(normalizedSortColumn))
- .filter((field) => field !== undefined);
+ .map((sortColumn) => sortColumn.toLowerCase())
+ .filter((normalizedSortColumn) => fMap.has(normalizedSortColumn))
+ .map((normalizedSortColumn) => fMap.get(normalizedSortColumn))
+ .filter((field) => field !== undefined);
const remainingFields = fields.filter((field) => !sortedFields.includes(field));
const uniqueRemainingFields = Array.from(new Set(remainingFields));
return [...sortedFields, ...uniqueRemainingFields];
-}
+ }
private renderField = (field: IDynamicFieldProps): JSX.Element => {
const { fieldOverrides } = this.props;
@@ -331,7 +331,7 @@ export class DynamicFormBase extends React.Component<
field.columnInternalName
)
) {
- return fieldOverrides[field.columnInternalName]({ ...field,disabled: field.disabled || isSaving} )
+ return fieldOverrides[field.columnInternalName]({ ...field, disabled: field.disabled || isSaving })
}
// Default render
@@ -342,6 +342,7 @@ export class DynamicFormBase extends React.Component<
{...field}
disabled={field.disabled || isSaving}
validationErrorMessage={validationErrorMessage}
+ itemsQueryCountLimit={this.props.itemsQueryCountLimit}
/>
);
}
@@ -509,21 +510,21 @@ export class DynamicFormBase extends React.Component<
}
// Taxonomy / Managed Metadata fields
- if(useModernTaxonomyPicker){
+ if (useModernTaxonomyPicker) {
//Use ITermInfo[] for modern taxonomy picker
if (fieldType === "TaxonomyFieldType") {
objects[fieldcolumnInternalName] = {
- __metadata: { type: "SP.Taxonomy.TaxonomyFieldValue" },
- Label: value[0]?.labels[0]?.name ?? "",
- TermGuid: value[0]?.id ?? "11111111-1111-1111-1111-111111111111",
- WssId: "-1",
+ __metadata: { type: "SP.Taxonomy.TaxonomyFieldValue" },
+ Label: value[0]?.labels[0]?.name ?? "",
+ TermGuid: value[0]?.id ?? "11111111-1111-1111-1111-111111111111",
+ WssId: "-1",
};
}
if (fieldType === "TaxonomyFieldTypeMulti") {
objects[hiddenFieldName] = field.newValue
- .map((term) => `-1#;${term.labels[0]?.name || ""}|${term.id};`)
- .join("#");
+ .map((term) => `-1#;${term.labels[0]?.name || ""}|${term.id};`)
+ .join("#");
}
} else {
@@ -608,7 +609,7 @@ export class DynamicFormBase extends React.Component<
contentTypeId === undefined ||
contentTypeId === "" ||
(!contentTypeId.startsWith("0x0120") &&
- contentTypeId.startsWith("0x01"))
+ contentTypeId.startsWith("0x01"))
) {
if (fileSelectRendered === true) {
await this.addFileToLibrary(objects);
@@ -710,51 +711,51 @@ export class DynamicFormBase extends React.Component<
if (selectedFile !== undefined) {
- try {
- const idField = "ID";
- const contentTypeIdField = "ContentTypeId";
-
- const library = await sp.web.lists.getById(listId);
- const itemTitle =
- selectedFile !== undefined && selectedFile.fileName !== undefined && selectedFile.fileName !== ""
- ? (selectedFile.fileName as string).replace(
- /["|*|:|<|>|?|/|\\||]/g,
- "_"
- ).trim() // Replace not allowed chars in folder name and trim empty spaces at the start or end.
- : ""; // Empty string will be replaced by SPO with Folder Item ID
-
- const folder = !this.props.folderPath ? library.rootFolder : await this.getFolderByPath(this.props.folderPath, library.rootFolder);
- const fileCreatedResult = await folder.files.addChunked(encodeURI(itemTitle), await selectedFile.downloadFileContent());
- const fields = await fileCreatedResult.file.listItemAllFields();
-
- if (fields[idField]) {
- // Read the ID of the just created file
- const fileId = fields[idField];
-
- // Set the content type ID for the target item
- objects[contentTypeIdField] = contentTypeId;
- // Update the just created file
- const iur = await this.updateListItemRetry(library, fileId, objects);
- if (onSubmitted) {
- onSubmitted(
- iur.data,
- returnListItemInstanceOnSubmit !== false
- ? iur.item
- : undefined
- );
- }
- } else {
- throw new Error(
- "Unable to read the ID of the just created file"
+ try {
+ const idField = "ID";
+ const contentTypeIdField = "ContentTypeId";
+
+ const library = await sp.web.lists.getById(listId);
+ const itemTitle =
+ selectedFile !== undefined && selectedFile.fileName !== undefined && selectedFile.fileName !== ""
+ ? (selectedFile.fileName as string).replace(
+ /["|*|:|<|>|?|/|\\||]/g,
+ "_"
+ ).trim() // Replace not allowed chars in folder name and trim empty spaces at the start or end.
+ : ""; // Empty string will be replaced by SPO with Folder Item ID
+
+ const folder = !this.props.folderPath ? library.rootFolder : await this.getFolderByPath(this.props.folderPath, library.rootFolder);
+ const fileCreatedResult = await folder.files.addChunked(encodeURI(itemTitle), await selectedFile.downloadFileContent());
+ const fields = await fileCreatedResult.file.listItemAllFields();
+
+ if (fields[idField]) {
+ // Read the ID of the just created file
+ const fileId = fields[idField];
+
+ // Set the content type ID for the target item
+ objects[contentTypeIdField] = contentTypeId;
+ // Update the just created file
+ const iur = await this.updateListItemRetry(library, fileId, objects);
+ if (onSubmitted) {
+ onSubmitted(
+ iur.data,
+ returnListItemInstanceOnSubmit !== false
+ ? iur.item
+ : undefined
);
}
- } catch (error) {
- if (onSubmitError) {
- onSubmitError(objects, error);
- }
- console.log("Error", error);
+ } else {
+ throw new Error(
+ "Unable to read the ID of the just created file"
+ );
+ }
+ } catch (error) {
+ if (onSubmitError) {
+ onSubmitError(objects, error);
}
+ console.log("Error", error);
}
+ }
}
/**
@@ -776,7 +777,7 @@ export class DynamicFormBase extends React.Component<
const { useModernTaxonomyPicker } = this.props;
// Init new value(s)
field.newValue = newValue;
- field.stringValue = newValue? newValue.toString():'';
+ field.stringValue = newValue ? newValue.toString() : '';
field.additionalData = additionalData;
field.subPropertyValues = {};
@@ -791,12 +792,12 @@ export class DynamicFormBase extends React.Component<
if (field.fieldType === "Lookup" || field.fieldType === "LookupMulti") {
field.stringValue = newValue.map(nv => nv.key + ';#' + nv.name).join(';#');
}
- if(useModernTaxonomyPicker){
+ if (useModernTaxonomyPicker) {
if (field.fieldType === "TaxonomyFieldType" || field.fieldType === "TaxonomyFieldTypeMulti") {
if (Array.isArray(newValue) && newValue.length > 0) {
- field.stringValue = newValue.map(nv => nv.labels.map(label => label.name).join(';')).join(';');
+ field.stringValue = newValue.map(nv => nv.labels.map(label => label.name).join(';')).join(';');
} else {
- field.stringValue = "";
+ field.stringValue = "";
}
}
} else {
@@ -851,7 +852,7 @@ export class DynamicFormBase extends React.Component<
field.stringValue = emails.join(";");
}
- const validationErrors = {...this.state.validationErrors};
+ const validationErrors = { ...this.state.validationErrors };
if (validationErrors[field.columnInternalName]) delete validationErrors[field.columnInternalName];
this.setState({
@@ -1048,7 +1049,7 @@ export class DynamicFormBase extends React.Component<
const spListItem = spList.items.getById(listItemId);
if (contentTypeId.startsWith("0x0120") || contentTypeId.startsWith("0x0101")) {
- spListItem.select("*","FileLeafRef"); // Explainer: FileLeafRef is not loaded by default. Load it to show the file/folder name in the field.
+ spListItem.select("*", "FileLeafRef"); // Explainer: FileLeafRef is not loaded by default. Load it to show the file/folder name in the field.
}
item = await spListItem.get().catch(err => this.updateFormMessages(MessageBarType.error, err.message));
@@ -1117,8 +1118,8 @@ export class DynamicFormBase extends React.Component<
* @returns
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- private async buildFieldCollection(listInfo: IRenderListDataAsStreamClientFormResult, contentTypeName: string, item: any, numberFields: ISPField[], listId: string, listItemId: number, disabledFields: string[], customIcons: {[key: string]: string}): Promise {
- const{ useModernTaxonomyPicker } = this.props;
+ private async buildFieldCollection(listInfo: IRenderListDataAsStreamClientFormResult, contentTypeName: string, item: any, numberFields: ISPField[], listId: string, listItemId: number, disabledFields: string[], customIcons: { [key: string]: string }): Promise {
+ const { useModernTaxonomyPicker } = this.props;
const tempFields: IDynamicFieldProps[] = [];
let order: number = 0;
const hiddenFields = this.props.hiddenFields !== undefined ? this.props.hiddenFields : [];
@@ -1129,7 +1130,7 @@ export class DynamicFormBase extends React.Component<
// Process fields that are not marked as hidden
if (hiddenFields.indexOf(field.InternalName) < 0) {
- if(field.Hidden === false) {
+ if (field.Hidden === false) {
order++;
let hiddenName = "";
let termSetId = "";
@@ -1265,7 +1266,7 @@ export class DynamicFormBase extends React.Component<
}
// Setup Taxonomy / Metadata fields
- if(useModernTaxonomyPicker){
+ if (useModernTaxonomyPicker) {
if (field.FieldType === "TaxonomyFieldType") {
termSetId = field.TermSetId;
anchorId = field.AnchorId !== Guid.empty.toString() ? field.AnchorId : null;
@@ -1301,7 +1302,7 @@ export class DynamicFormBase extends React.Component<
termSetId = field.TermSetId;
anchorId = field.AnchorId !== Guid.empty.toString() ? field.AnchorId : null;
if (item && item[field.InternalName]) {
- const _selectedTags = await this.getTermsForModernTaxonomyPicker(field.TermSetId,item[field.InternalName]);
+ const _selectedTags = await this.getTermsForModernTaxonomyPicker(field.TermSetId, item[field.InternalName]);
item[field.InternalName].forEach((element) => {
selectedTags.push({
key: element.TermGuid,
@@ -1730,8 +1731,7 @@ export class DynamicFormBase extends React.Component<
try {
return await list.items.getById(itemId).update(objects);
}
- catch (error)
- {
+ catch (error) {
if (error.status === 409 && retry < 3) {
await timeout(100);
return await this.updateListItemRetry(list, itemId, objects, retry + 1);
diff --git a/src/controls/dynamicForm/IDynamicFormProps.ts b/src/controls/dynamicForm/IDynamicFormProps.ts
index 05c010787..6352b1c03 100644
--- a/src/controls/dynamicForm/IDynamicFormProps.ts
+++ b/src/controls/dynamicForm/IDynamicFormProps.ts
@@ -2,7 +2,7 @@ import { BaseComponentContext } from '@microsoft/sp-component-base';
import { IItem } from '@pnp/sp/items';
import { IStyle, IStyleFunctionOrObject } from '@fluentui/react';
import React from 'react';
-import { IDynamicFieldProps,IDynamicFieldStyles } from './dynamicField';
+import { IDynamicFieldProps, IDynamicFieldStyles } from './dynamicField';
import { IValidationErrorDialogProps } from './IValidationErrorDialogProps';
export interface IDynamicFormProps {
@@ -139,7 +139,7 @@ export interface IDynamicFormProps {
* Note: the value of selected tab is stored in the queryString hash.
* @default true
*/
- storeLastActiveTab?: boolean;
+ storeLastActiveTab?: boolean;
/**
* Library relative folder to create the item in.
@@ -165,11 +165,16 @@ export interface IDynamicFormProps {
* CSS Class name to add to the root element.
*/
className?: string;
+
+ /**
+ * Number of items to display in the lookup fields of the form.
+ */
+ itemsQueryCountLimit?: number;
}
-export type IDynamicFormStyleProps = Pick & { };
+export type IDynamicFormStyleProps = Pick & {};
export interface IDynamicFormSubComponentStyles {
fieldStyles: IDynamicFieldStyles;
@@ -181,15 +186,15 @@ export interface IDynamicFormStyles {
sectionFormFields: IStyle;
sectionFormField: IStyle;
sectionLine: IStyle;
- header:IStyle;
- footer:IStyle;
+ header: IStyle;
+ footer: IStyle;
validationErrorDialog: IStyle;
buttons: IStyle;
actions: IStyle;
actionsRight: IStyle;
action: IStyle;
- /**
- * sub component styles for dynamic field
- */
- subComponentStyles: IDynamicFormSubComponentStyles;
+ /**
+ * sub component styles for dynamic field
+ */
+ subComponentStyles: IDynamicFormSubComponentStyles;
}
\ No newline at end of file