Skip to content

Commit 270bd1d

Browse files
committed
add respectETag to DynamicForm
1 parent e905d19 commit 270bd1d

File tree

6 files changed

+99
-87
lines changed

6 files changed

+99
-87
lines changed

docs/documentation/docs/controls/DynamicForm.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,4 @@ The `DynamicForm` can be configured with the following properties:
4545
| returnListItemInstanceOnSubmit | boolean | no | Specifies if `onSubmitted` event should pass PnPJS list item (`IItem`) as a second parameter. Default - `true` |
4646
| webAbsoluteUrl | string | no | Absolute Web Url of target site (user requires permissions). |
4747
| fieldOverrides | {[columnInternalName: string] : {(fieldProperties: IDynamicFieldProps): React.ReactElement\<IDynamicFieldProps\>}} | no | Key value pair for fields you want to override. Key is the internal field name, value is the function to be called for the custom element to render. |
48+
| respectEtag | boolean | no | Specifies if the form should respect the ETag of the item. Default - `true` |

package-lock.json

Lines changed: 24 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/controls/dynamicForm/DynamicForm.tsx

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export class DynamicForm extends React.Component<IDynamicFormProps, IDynamicForm
8282
{fieldCollection.length === 0 ? <div><ProgressIndicator label={strings.DynamicFormLoading} description={strings.DynamicFormPleaseWait} /></div> :
8383
<div>
8484
{fieldCollection.map((v, i) => {
85-
if(fieldOverrides && Object.prototype.hasOwnProperty.call(fieldOverrides, v.columnInternalName)) {
85+
if (fieldOverrides && Object.prototype.hasOwnProperty.call(fieldOverrides, v.columnInternalName)) {
8686
v.disabled = v.disabled || isSaving;
8787
return fieldOverrides[v.columnInternalName](v);
8888
}
@@ -222,9 +222,11 @@ export class DynamicForm extends React.Component<IDynamicFormProps, IDynamicForm
222222
}
223223

224224
// If we have the item ID, we simply need to update it
225+
let newETag: string | undefined = undefined;
225226
if (listItemId) {
226227
try {
227-
const iur = await sp.web.lists.getById(listId).items.getById(listItemId).update(objects);
228+
const iur = await sp.web.lists.getById(listId).items.getById(listItemId).update(objects, this.state.etag);
229+
newETag = iur.data['odata.etag'];
228230
if (onSubmitted) {
229231
onSubmitted(iur.data, this.props.returnListItemInstanceOnSubmit !== false ? iur.item : undefined);
230232
}
@@ -239,58 +241,59 @@ export class DynamicForm extends React.Component<IDynamicFormProps, IDynamicForm
239241
}
240242
// Otherwise, depending on the content type ID of the item, if any, we need to behave accordingly
241243
else if (contentTypeId === undefined || contentTypeId === '' || !contentTypeId.startsWith('0x0120')) {
242-
// We are adding a new list item
243-
try {
244-
const iar = await sp.web.lists.getById(listId).items.add(objects);
245-
if (onSubmitted) {
246-
onSubmitted(iar.data, this.props.returnListItemInstanceOnSubmit !== false ? iar.item : undefined);
247-
}
248-
}
249-
catch (error) {
250-
if (onSubmitError) {
251-
onSubmitError(objects, error);
252-
}
253-
console.log("Error", error);
254-
}
255-
} else if (contentTypeId.startsWith('0x0120')) {
256-
// We are adding a folder or a Document Set
257-
try {
258-
const idField = 'ID';
259-
const titleField = 'Title';
260-
const contentTypeIdField = 'ContentTypeId';
261-
262-
const library = await sp.web.lists.getById(listId);
263-
const folderTitle = (objects[titleField] !== undefined && objects[titleField] !== '') ?
264-
(objects[titleField] as string).replace(/["|*|:|<|>|?|/|\\||]/g, "_") : // Replace not allowed chars in folder name
265-
''; // Empty string will be replaced by SPO with Folder Item ID
266-
const newFolder = await library.rootFolder.addSubFolderUsingPath(folderTitle);
267-
const fields = await newFolder.listItemAllFields();
268-
if (fields[idField]) {
269-
270-
// Read the ID of the just created folder or Document Set
271-
const folderId = fields[idField];
272-
273-
// Set the content type ID for the target item
274-
objects[contentTypeIdField] = contentTypeId;
275-
// Update the just created folder or Document Set
276-
const iur = await library.items.getById(folderId).update(objects);
277-
if (onSubmitted) {
278-
onSubmitted(iur.data, this.props.returnListItemInstanceOnSubmit !== false ? iur.item : undefined);
279-
}
280-
} else {
281-
throw new Error('Unable to read the ID of the just created folder or Document Set');
282-
}
244+
// We are adding a new list item
245+
try {
246+
const iar = await sp.web.lists.getById(listId).items.add(objects);
247+
if (onSubmitted) {
248+
onSubmitted(iar.data, this.props.returnListItemInstanceOnSubmit !== false ? iar.item : undefined);
249+
}
250+
}
251+
catch (error) {
252+
if (onSubmitError) {
253+
onSubmitError(objects, error);
283254
}
284-
catch (error) {
285-
if (onSubmitError) {
286-
onSubmitError(objects, error);
255+
console.log("Error", error);
256+
}
257+
} else if (contentTypeId.startsWith('0x0120')) {
258+
// We are adding a folder or a Document Set
259+
try {
260+
const idField = 'ID';
261+
const titleField = 'Title';
262+
const contentTypeIdField = 'ContentTypeId';
263+
264+
const library = await sp.web.lists.getById(listId);
265+
const folderTitle = (objects[titleField] !== undefined && objects[titleField] !== '') ?
266+
(objects[titleField] as string).replace(/["|*|:|<|>|?|/|\\||]/g, "_") : // Replace not allowed chars in folder name
267+
''; // Empty string will be replaced by SPO with Folder Item ID
268+
const newFolder = await library.rootFolder.addSubFolderUsingPath(folderTitle);
269+
const fields = await newFolder.listItemAllFields();
270+
if (fields[idField]) {
271+
272+
// Read the ID of the just created folder or Document Set
273+
const folderId = fields[idField];
274+
275+
// Set the content type ID for the target item
276+
objects[contentTypeIdField] = contentTypeId;
277+
// Update the just created folder or Document Set
278+
const iur = await library.items.getById(folderId).update(objects);
279+
if (onSubmitted) {
280+
onSubmitted(iur.data, this.props.returnListItemInstanceOnSubmit !== false ? iur.item : undefined);
287281
}
288-
console.log("Error", error);
282+
} else {
283+
throw new Error('Unable to read the ID of the just created folder or Document Set');
284+
}
285+
}
286+
catch (error) {
287+
if (onSubmitError) {
288+
onSubmitError(objects, error);
289289
}
290+
console.log("Error", error);
291+
}
290292
}
291293

292294
this.setState({
293-
isSaving: false
295+
isSaving: false,
296+
etag: newETag
294297
});
295298
} catch (error) {
296299
if (onSubmitError) {
@@ -346,14 +349,20 @@ export class DynamicForm extends React.Component<IDynamicFormProps, IDynamicForm
346349

347350
//getting all the fields information as part of get ready process
348351
private getFieldInformations = async (): Promise<void> => {
349-
const { listId, listItemId, disabledFields } = this.props;
352+
const { listId, listItemId, disabledFields, respectETag } = this.props;
350353
let contentTypeId = this.props.contentTypeId;
351354
try {
352355
const spList = await sp.web.lists.getById(listId);
353356
let item = null;
354-
if (listItemId !== undefined && listItemId !== null && listItemId !== 0)
357+
let etag: string | undefined = undefined;
358+
if (listItemId !== undefined && listItemId !== null && listItemId !== 0) {
355359
item = await spList.items.getById(listItemId).get();
356360

361+
if (respectETag !== false) {
362+
etag = item['odata.etag'];
363+
}
364+
}
365+
357366
if (contentTypeId === undefined || contentTypeId === '') {
358367
const defaultContentType = await spList.contentTypes.select("Id", "Name").get();
359368
contentTypeId = defaultContentType[0].Id.StringValue;
@@ -390,7 +399,7 @@ export class DynamicForm extends React.Component<IDynamicFormProps, IDynamicForm
390399
}
391400
if (fieldType === 'Choice' || fieldType === 'MultiChoice') {
392401
field.Choices.forEach(element => {
393-
choices.push({key: element, text: element});
402+
choices.push({ key: element, text: element });
394403
});
395404
} else if (fieldType === "Note") {
396405
richText = field.RichText;
@@ -418,15 +427,15 @@ export class DynamicForm extends React.Component<IDynamicFormProps, IDynamicForm
418427
anchorId = field.AnchorId;
419428
if (item !== null) {
420429
item[field.InternalName].forEach(element => {
421-
selectedTags.push({key: element.TermGuid, name: element.Label});
430+
selectedTags.push({ key: element.TermGuid, name: element.Label });
422431
});
423432

424433
defaultValue = selectedTags;
425434
} else {
426435
if (defaultValue !== "") {
427436
defaultValue.split(/#|;/).forEach(element => {
428437
if (element.indexOf('|') !== -1)
429-
selectedTags.push({key: element.split('|')[1], name: element.split('|')[0]});
438+
selectedTags.push({ key: element.split('|')[1], name: element.split('|')[0] });
430439
});
431440

432441
defaultValue = selectedTags;
@@ -441,12 +450,12 @@ export class DynamicForm extends React.Component<IDynamicFormProps, IDynamicForm
441450
if (item !== null) {
442451
const response = await this._spService.getSingleManagedMtadataLabel(listId, listItemId, field.InternalName);
443452
if (response) {
444-
selectedTags.push({key: response.TermID, name: response.Label});
453+
selectedTags.push({ key: response.TermID, name: response.Label });
445454
defaultValue = selectedTags;
446455
}
447456
} else {
448457
if (defaultValue !== "") {
449-
selectedTags.push({key: defaultValue.split('|')[1], name: defaultValue.split('|')[0].split('#')[1]});
458+
selectedTags.push({ key: defaultValue.split('|')[1], name: defaultValue.split('|')[0].split('#')[1] });
450459
defaultValue = selectedTags;
451460
}
452461
}
@@ -523,7 +532,7 @@ export class DynamicForm extends React.Component<IDynamicFormProps, IDynamicForm
523532
}
524533
}
525534

526-
this.setState({ fieldCollection: tempFields });
535+
this.setState({ fieldCollection: tempFields, etag: etag });
527536
//return arrayItems;
528537
} catch (error) {
529538
console.log(`Error get field informations`, error);

src/controls/dynamicForm/IDynamicFormProps.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,12 @@ export interface IDynamicFormProps {
4646
* Key value pair for fields you want to override. Key is the internal field name, value is the function to be called for the custom element to render
4747
*/
4848
fieldOverrides?: {[columnInternalName: string] : {(fieldProperties: IDynamicFieldProps): React.ReactElement<IDynamicFieldProps>}};
49+
4950
/**
5051
* Specifies if onSubmitted event should pass PnPJS list item (IItem) as a second parameter. Default - true
5152
*/
5253
returnListItemInstanceOnSubmit?: boolean;
5354

54-
/**
55-
* Used to execute WebSearch. If not provided SearchTab will not be available.
56-
*/
57-
//bingAPIKey?: string;
58-
5955
/**
6056
* InternalName of fields that should be disabled
6157
*/
@@ -68,6 +64,11 @@ export interface IDynamicFormProps {
6864

6965
/**
7066
* Absolute Web Url of target site (user requires permissions)
71-
* */
67+
*/
7268
webAbsoluteUrl?: string;
69+
70+
/**
71+
* Specifies if ETag should be respected when updating the item. Default - true
72+
*/
73+
respectETag?: boolean;
7374
}

src/controls/dynamicForm/IDynamicFormState.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { IDynamicFieldProps } from './dynamicField/IDynamicFieldProps';
33
export interface IDynamicFormState {
44
fieldCollection: IDynamicFieldProps[];
55
isSaving?: boolean;
6+
etag?: string;
67
}
78

89

src/webparts/controlsTest/components/ControlsTest.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ export default class ControlsTest extends React.Component<IControlsTestProps, IC
924924
<div className={styles.controlsTest}>
925925
<div className="ms-font-m">
926926
{/* Change the list Id and list item id before you start to test this control */}
927-
<DynamicForm context={this.props.context} listId={"b1416fca-dc77-4198-a082-62a7657dcfa9"} onCancelled={() => { console.log('Cancelled'); }} onSubmitted={async (listItem) => { let itemdata = await listItem.get(); console.log(itemdata["ID"]); }}></DynamicForm>
927+
<DynamicForm context={this.props.context} listId={"db25f5f6-5ae1-4fa0-a2f7-e093d3d463ae"} listItemId={1} onCancelled={() => { console.log('Cancelled'); }} onSubmitted={async (listItem) => { let itemdata = await listItem.get(); console.log(itemdata["ID"]); }}></DynamicForm>
928928
</div>
929929
<WebPartTitle displayMode={this.props.displayMode}
930930
title={this.props.title}

0 commit comments

Comments
 (0)