Skip to content

Commit 79b614f

Browse files
author
niels.soeth
committed
add itemsQueryCountLimit to DynamicForm
1 parent 9cfb9d6 commit 79b614f

File tree

3 files changed

+100
-94
lines changed

3 files changed

+100
-94
lines changed

docs/documentation/docs/controls/DynamicForm.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ The `DynamicForm` can be configured with the following properties:
7272
| 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` |
7373
| className | string | no | Set CSS Class. |
7474
| styles | IStyleFunctionOrObject<IDynamicFormStyleProps, [IDynamicFormStyles](#idynamicformstyles-interface)> | no | Styles to apply on control. See the example [here](#how-to-use-styles-property) |
75+
| itemsQueryCountLimit | number | no | Number of items to display in the lookup fields of the form | |
7576

7677
## Validation Error Dialog Properties `IValidationErrorDialogProps`
7778

src/controls/dynamicForm/DynamicForm.tsx

Lines changed: 85 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ export class DynamicFormBase extends React.Component<
173173
// Custom Formatting - Header
174174
let headerContent: JSX.Element;
175175
if (!customFormattingDisabled && customFormatting?.header) {
176-
headerContent = <div className={styles.header}>
176+
headerContent = <div className={styles.header}>
177177
{this._customFormatter.renderCustomFormatContent(customFormatting.header, this.getFormValuesForValidation(), true)}
178178
</div>
179179
}
@@ -196,8 +196,8 @@ export class DynamicFormBase extends React.Component<
196196
let footerContent: JSX.Element;
197197
if (!customFormattingDisabled && customFormatting?.footer) {
198198
footerContent = <div className={styles.footer}>
199-
{this._customFormatter.renderCustomFormatContent(customFormatting.footer, this.getFormValuesForValidation(), true)}
200-
</div>
199+
{this._customFormatter.renderCustomFormatContent(customFormatting.footer, this.getFormValuesForValidation(), true)}
200+
</div>
201201
}
202202

203203
// Content Type
@@ -227,20 +227,20 @@ export class DynamicFormBase extends React.Component<
227227
{(bodySections.length > 0 && !customFormattingDisabled) && bodySections
228228
.filter(bs => bs.fields.filter(bsf => hiddenByFormula.indexOf(bsf) < 0).length > 0)
229229
.map((section, i) => (
230-
<>
231-
<h2 className={styles.sectionTitle}>{section.displayname}</h2>
232-
<div className={styles.sectionFormFields}>
233-
{section.fields
234-
.filter(f => fieldCollection.find(fc => fc.label === f))
235-
.map((f, i) => (
236-
<div key={f} className={styles.sectionFormField}>
237-
{this.renderField(fieldCollection.find(fc => fc.label === f) as IDynamicFieldProps)}
238-
</div>
239-
))}
240-
</div>
241-
{i < bodySections.length - 1 && <hr className={styles.sectionLine} aria-hidden={true} />}
242-
</>
243-
))}
230+
<>
231+
<h2 className={styles.sectionTitle}>{section.displayname}</h2>
232+
<div className={styles.sectionFormFields}>
233+
{section.fields
234+
.filter(f => fieldCollection.find(fc => fc.label === f))
235+
.map((f, i) => (
236+
<div key={f} className={styles.sectionFormField}>
237+
{this.renderField(fieldCollection.find(fc => fc.label === f) as IDynamicFieldProps)}
238+
</div>
239+
))}
240+
</div>
241+
{i < bodySections.length - 1 && <hr className={styles.sectionLine} aria-hidden={true} />}
242+
</>
243+
))}
244244
{(bodySections.length === 0 || customFormattingDisabled) && fieldCollection.map((f, i) => this.renderField(f))}
245245
{footerContent}
246246
{!this.props.disabled && (
@@ -296,16 +296,16 @@ export class DynamicFormBase extends React.Component<
296296
}
297297

298298
const sortedFields = customSort
299-
.map((sortColumn) => sortColumn.toLowerCase())
300-
.filter((normalizedSortColumn) => fMap.has(normalizedSortColumn))
301-
.map((normalizedSortColumn) => fMap.get(normalizedSortColumn))
302-
.filter((field) => field !== undefined);
299+
.map((sortColumn) => sortColumn.toLowerCase())
300+
.filter((normalizedSortColumn) => fMap.has(normalizedSortColumn))
301+
.map((normalizedSortColumn) => fMap.get(normalizedSortColumn))
302+
.filter((field) => field !== undefined);
303303

304304
const remainingFields = fields.filter((field) => !sortedFields.includes(field));
305305
const uniqueRemainingFields = Array.from(new Set(remainingFields));
306306

307307
return [...sortedFields, ...uniqueRemainingFields];
308-
}
308+
}
309309

310310
private renderField = (field: IDynamicFieldProps): JSX.Element => {
311311
const { fieldOverrides } = this.props;
@@ -331,7 +331,7 @@ export class DynamicFormBase extends React.Component<
331331
field.columnInternalName
332332
)
333333
) {
334-
return fieldOverrides[field.columnInternalName]({ ...field,disabled: field.disabled || isSaving} )
334+
return fieldOverrides[field.columnInternalName]({ ...field, disabled: field.disabled || isSaving })
335335
}
336336

337337
// Default render
@@ -342,6 +342,7 @@ export class DynamicFormBase extends React.Component<
342342
{...field}
343343
disabled={field.disabled || isSaving}
344344
validationErrorMessage={validationErrorMessage}
345+
itemsQueryCountLimit={this.props.itemsQueryCountLimit}
345346
/>
346347
);
347348
}
@@ -509,21 +510,21 @@ export class DynamicFormBase extends React.Component<
509510
}
510511

511512
// Taxonomy / Managed Metadata fields
512-
if(useModernTaxonomyPicker){
513+
if (useModernTaxonomyPicker) {
513514
//Use ITermInfo[] for modern taxonomy picker
514515
if (fieldType === "TaxonomyFieldType") {
515516
objects[fieldcolumnInternalName] = {
516-
__metadata: { type: "SP.Taxonomy.TaxonomyFieldValue" },
517-
Label: value[0]?.labels[0]?.name ?? "",
518-
TermGuid: value[0]?.id ?? "11111111-1111-1111-1111-111111111111",
519-
WssId: "-1",
517+
__metadata: { type: "SP.Taxonomy.TaxonomyFieldValue" },
518+
Label: value[0]?.labels[0]?.name ?? "",
519+
TermGuid: value[0]?.id ?? "11111111-1111-1111-1111-111111111111",
520+
WssId: "-1",
520521
};
521522
}
522523

523524
if (fieldType === "TaxonomyFieldTypeMulti") {
524525
objects[hiddenFieldName] = field.newValue
525-
.map((term) => `-1#;${term.labels[0]?.name || ""}|${term.id};`)
526-
.join("#");
526+
.map((term) => `-1#;${term.labels[0]?.name || ""}|${term.id};`)
527+
.join("#");
527528
}
528529

529530
} else {
@@ -608,7 +609,7 @@ export class DynamicFormBase extends React.Component<
608609
contentTypeId === undefined ||
609610
contentTypeId === "" ||
610611
(!contentTypeId.startsWith("0x0120") &&
611-
contentTypeId.startsWith("0x01"))
612+
contentTypeId.startsWith("0x01"))
612613
) {
613614
if (fileSelectRendered === true) {
614615
await this.addFileToLibrary(objects);
@@ -710,51 +711,51 @@ export class DynamicFormBase extends React.Component<
710711

711712

712713
if (selectedFile !== undefined) {
713-
try {
714-
const idField = "ID";
715-
const contentTypeIdField = "ContentTypeId";
716-
717-
const library = await sp.web.lists.getById(listId);
718-
const itemTitle =
719-
selectedFile !== undefined && selectedFile.fileName !== undefined && selectedFile.fileName !== ""
720-
? (selectedFile.fileName as string).replace(
721-
/["|*|:|<|>|?|/|\\||]/g,
722-
"_"
723-
).trim() // Replace not allowed chars in folder name and trim empty spaces at the start or end.
724-
: ""; // Empty string will be replaced by SPO with Folder Item ID
725-
726-
const folder = !this.props.folderPath ? library.rootFolder : await this.getFolderByPath(this.props.folderPath, library.rootFolder);
727-
const fileCreatedResult = await folder.files.addChunked(encodeURI(itemTitle), await selectedFile.downloadFileContent());
728-
const fields = await fileCreatedResult.file.listItemAllFields();
729-
730-
if (fields[idField]) {
731-
// Read the ID of the just created file
732-
const fileId = fields[idField];
733-
734-
// Set the content type ID for the target item
735-
objects[contentTypeIdField] = contentTypeId;
736-
// Update the just created file
737-
const iur = await this.updateListItemRetry(library, fileId, objects);
738-
if (onSubmitted) {
739-
onSubmitted(
740-
iur.data,
741-
returnListItemInstanceOnSubmit !== false
742-
? iur.item
743-
: undefined
744-
);
745-
}
746-
} else {
747-
throw new Error(
748-
"Unable to read the ID of the just created file"
714+
try {
715+
const idField = "ID";
716+
const contentTypeIdField = "ContentTypeId";
717+
718+
const library = await sp.web.lists.getById(listId);
719+
const itemTitle =
720+
selectedFile !== undefined && selectedFile.fileName !== undefined && selectedFile.fileName !== ""
721+
? (selectedFile.fileName as string).replace(
722+
/["|*|:|<|>|?|/|\\||]/g,
723+
"_"
724+
).trim() // Replace not allowed chars in folder name and trim empty spaces at the start or end.
725+
: ""; // Empty string will be replaced by SPO with Folder Item ID
726+
727+
const folder = !this.props.folderPath ? library.rootFolder : await this.getFolderByPath(this.props.folderPath, library.rootFolder);
728+
const fileCreatedResult = await folder.files.addChunked(encodeURI(itemTitle), await selectedFile.downloadFileContent());
729+
const fields = await fileCreatedResult.file.listItemAllFields();
730+
731+
if (fields[idField]) {
732+
// Read the ID of the just created file
733+
const fileId = fields[idField];
734+
735+
// Set the content type ID for the target item
736+
objects[contentTypeIdField] = contentTypeId;
737+
// Update the just created file
738+
const iur = await this.updateListItemRetry(library, fileId, objects);
739+
if (onSubmitted) {
740+
onSubmitted(
741+
iur.data,
742+
returnListItemInstanceOnSubmit !== false
743+
? iur.item
744+
: undefined
749745
);
750746
}
751-
} catch (error) {
752-
if (onSubmitError) {
753-
onSubmitError(objects, error);
754-
}
755-
console.log("Error", error);
747+
} else {
748+
throw new Error(
749+
"Unable to read the ID of the just created file"
750+
);
751+
}
752+
} catch (error) {
753+
if (onSubmitError) {
754+
onSubmitError(objects, error);
756755
}
756+
console.log("Error", error);
757757
}
758+
}
758759
}
759760

760761
/**
@@ -776,7 +777,7 @@ export class DynamicFormBase extends React.Component<
776777
const { useModernTaxonomyPicker } = this.props;
777778
// Init new value(s)
778779
field.newValue = newValue;
779-
field.stringValue = newValue? newValue.toString():'';
780+
field.stringValue = newValue ? newValue.toString() : '';
780781
field.additionalData = additionalData;
781782
field.subPropertyValues = {};
782783

@@ -791,12 +792,12 @@ export class DynamicFormBase extends React.Component<
791792
if (field.fieldType === "Lookup" || field.fieldType === "LookupMulti") {
792793
field.stringValue = newValue.map(nv => nv.key + ';#' + nv.name).join(';#');
793794
}
794-
if(useModernTaxonomyPicker){
795+
if (useModernTaxonomyPicker) {
795796
if (field.fieldType === "TaxonomyFieldType" || field.fieldType === "TaxonomyFieldTypeMulti") {
796797
if (Array.isArray(newValue) && newValue.length > 0) {
797-
field.stringValue = newValue.map(nv => nv.labels.map(label => label.name).join(';')).join(';');
798+
field.stringValue = newValue.map(nv => nv.labels.map(label => label.name).join(';')).join(';');
798799
} else {
799-
field.stringValue = "";
800+
field.stringValue = "";
800801
}
801802
}
802803
} else {
@@ -851,7 +852,7 @@ export class DynamicFormBase extends React.Component<
851852
field.stringValue = emails.join(";");
852853
}
853854

854-
const validationErrors = {...this.state.validationErrors};
855+
const validationErrors = { ...this.state.validationErrors };
855856
if (validationErrors[field.columnInternalName]) delete validationErrors[field.columnInternalName];
856857

857858
this.setState({
@@ -1048,7 +1049,7 @@ export class DynamicFormBase extends React.Component<
10481049
const spListItem = spList.items.getById(listItemId);
10491050

10501051
if (contentTypeId.startsWith("0x0120") || contentTypeId.startsWith("0x0101")) {
1051-
spListItem.select("*","FileLeafRef"); // Explainer: FileLeafRef is not loaded by default. Load it to show the file/folder name in the field.
1052+
spListItem.select("*", "FileLeafRef"); // Explainer: FileLeafRef is not loaded by default. Load it to show the file/folder name in the field.
10521053
}
10531054

10541055
item = await spListItem.get().catch(err => this.updateFormMessages(MessageBarType.error, err.message));
@@ -1117,8 +1118,8 @@ export class DynamicFormBase extends React.Component<
11171118
* @returns
11181119
*/
11191120
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1120-
private async buildFieldCollection(listInfo: IRenderListDataAsStreamClientFormResult, contentTypeName: string, item: any, numberFields: ISPField[], listId: string, listItemId: number, disabledFields: string[], customIcons: {[key: string]: string}): Promise<IDynamicFieldProps[]> {
1121-
const{ useModernTaxonomyPicker } = this.props;
1121+
private async buildFieldCollection(listInfo: IRenderListDataAsStreamClientFormResult, contentTypeName: string, item: any, numberFields: ISPField[], listId: string, listItemId: number, disabledFields: string[], customIcons: { [key: string]: string }): Promise<IDynamicFieldProps[]> {
1122+
const { useModernTaxonomyPicker } = this.props;
11221123
const tempFields: IDynamicFieldProps[] = [];
11231124
let order: number = 0;
11241125
const hiddenFields = this.props.hiddenFields !== undefined ? this.props.hiddenFields : [];
@@ -1129,7 +1130,7 @@ export class DynamicFormBase extends React.Component<
11291130

11301131
// Process fields that are not marked as hidden
11311132
if (hiddenFields.indexOf(field.InternalName) < 0) {
1132-
if(field.Hidden === false) {
1133+
if (field.Hidden === false) {
11331134
order++;
11341135
let hiddenName = "";
11351136
let termSetId = "";
@@ -1265,7 +1266,7 @@ export class DynamicFormBase extends React.Component<
12651266
}
12661267

12671268
// Setup Taxonomy / Metadata fields
1268-
if(useModernTaxonomyPicker){
1269+
if (useModernTaxonomyPicker) {
12691270
if (field.FieldType === "TaxonomyFieldType") {
12701271
termSetId = field.TermSetId;
12711272
anchorId = field.AnchorId !== Guid.empty.toString() ? field.AnchorId : null;
@@ -1301,7 +1302,7 @@ export class DynamicFormBase extends React.Component<
13011302
termSetId = field.TermSetId;
13021303
anchorId = field.AnchorId !== Guid.empty.toString() ? field.AnchorId : null;
13031304
if (item && item[field.InternalName]) {
1304-
const _selectedTags = await this.getTermsForModernTaxonomyPicker(field.TermSetId,item[field.InternalName]);
1305+
const _selectedTags = await this.getTermsForModernTaxonomyPicker(field.TermSetId, item[field.InternalName]);
13051306
item[field.InternalName].forEach((element) => {
13061307
selectedTags.push({
13071308
key: element.TermGuid,
@@ -1730,8 +1731,7 @@ export class DynamicFormBase extends React.Component<
17301731
try {
17311732
return await list.items.getById(itemId).update(objects);
17321733
}
1733-
catch (error)
1734-
{
1734+
catch (error) {
17351735
if (error.status === 409 && retry < 3) {
17361736
await timeout(100);
17371737
return await this.updateListItemRetry(list, itemId, objects, retry + 1);

src/controls/dynamicForm/IDynamicFormProps.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { BaseComponentContext } from '@microsoft/sp-component-base';
22
import { IItem } from '@pnp/sp/items';
33
import { IStyle, IStyleFunctionOrObject } from '@fluentui/react';
44
import React from 'react';
5-
import { IDynamicFieldProps,IDynamicFieldStyles } from './dynamicField';
5+
import { IDynamicFieldProps, IDynamicFieldStyles } from './dynamicField';
66
import { IValidationErrorDialogProps } from './IValidationErrorDialogProps';
77

88
export interface IDynamicFormProps {
@@ -139,7 +139,7 @@ export interface IDynamicFormProps {
139139
* Note: the value of selected tab is stored in the queryString hash.
140140
* @default true
141141
*/
142-
storeLastActiveTab?: boolean;
142+
storeLastActiveTab?: boolean;
143143

144144
/**
145145
* Library relative folder to create the item in.
@@ -165,11 +165,16 @@ export interface IDynamicFormProps {
165165
* CSS Class name to add to the root element.
166166
*/
167167
className?: string;
168+
169+
/**
170+
* Number of items to display in the lookup fields of the form.
171+
*/
172+
itemsQueryCountLimit?: number;
168173
}
169174

170175

171176

172-
export type IDynamicFormStyleProps = Pick<IDynamicFormProps, 'className'> & { };
177+
export type IDynamicFormStyleProps = Pick<IDynamicFormProps, 'className'> & {};
173178

174179
export interface IDynamicFormSubComponentStyles {
175180
fieldStyles: IDynamicFieldStyles;
@@ -181,15 +186,15 @@ export interface IDynamicFormStyles {
181186
sectionFormFields: IStyle;
182187
sectionFormField: IStyle;
183188
sectionLine: IStyle;
184-
header:IStyle;
185-
footer:IStyle;
189+
header: IStyle;
190+
footer: IStyle;
186191
validationErrorDialog: IStyle;
187192
buttons: IStyle;
188193
actions: IStyle;
189194
actionsRight: IStyle;
190195
action: IStyle;
191-
/**
192-
* sub component styles for dynamic field
193-
*/
194-
subComponentStyles: IDynamicFormSubComponentStyles;
196+
/**
197+
* sub component styles for dynamic field
198+
*/
199+
subComponentStyles: IDynamicFormSubComponentStyles;
195200
}

0 commit comments

Comments
 (0)