Skip to content

Commit 54f515f

Browse files
CopilotAJIXuMuK
andcommitted
Add updateETag method to DynamicForm and update documentation
Added public updateETag method to DynamicForm to allow external updates when list item is modified. Updated documentation for both ListItemAttachments and DynamicForm with integration examples. This completes the fix for ETag conflict errors when using attachments with DynamicForm. Co-authored-by: AJIXuMuK <[email protected]>
1 parent 4a03fa4 commit 54f515f

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

docs/documentation/docs/controls/DynamicForm.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,56 @@ The `DynamicForm` can be configured with the following properties:
120120
| thumbnailFieldButtons | IStyle | styles for button when field type is 'Thumbnail' |
121121
| selectedFileContainer | IStyle | styles for File Selection Control |
122122

123+
## Public Methods
124+
125+
The `DynamicForm` control exposes the following public methods that can be called using a ref:
126+
127+
### updateETag(itemData: any): void
128+
129+
Updates the ETag stored in the component's state. This is useful when the list item has been modified externally (e.g., by adding/removing attachments using the ListItemAttachments control) and you need to update the ETag to prevent 412 conflict errors on save.
130+
131+
**Parameters:**
132+
- `itemData` - The updated item data containing the new ETag (typically from SharePoint REST API response with `odata.etag` property)
133+
134+
**Example:**
135+
136+
```TypeScript
137+
import * as React from 'react';
138+
import { DynamicForm } from '@pnp/spfx-controls-react/lib/DynamicForm';
139+
import { ListItemAttachments } from '@pnp/spfx-controls-react/lib/ListItemAttachments';
140+
141+
export class MyComponent extends React.Component {
142+
private dynamicFormRef = React.createRef<DynamicForm>();
143+
144+
private onAttachmentChange = (itemData: any): void => {
145+
// Update the DynamicForm's ETag when attachments are modified
146+
if (this.dynamicFormRef.current) {
147+
this.dynamicFormRef.current.updateETag(itemData);
148+
}
149+
}
150+
151+
public render() {
152+
return (
153+
<div>
154+
<ListItemAttachments
155+
listId={this.props.listId}
156+
itemId={this.props.itemId}
157+
context={this.props.context}
158+
onAttachmentChange={this.onAttachmentChange}
159+
/>
160+
<DynamicForm
161+
ref={this.dynamicFormRef}
162+
context={this.props.context}
163+
listId={this.props.listId}
164+
listItemId={this.props.itemId}
165+
respectETag={true}
166+
/>
167+
</div>
168+
);
169+
}
170+
}
171+
```
172+
123173
## How to use styles property
124174

125175
Property styles of Dynamic Form gives you a set of properties which you can use to modify styles.

docs/documentation/docs/controls/ListItemAttachments.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,53 @@ The `ListItemAttachments` control can be configured with the following propertie
6363
| description | string | no | Description text to display on the placeholder, below the main text and icon. |
6464
| disabled | boolean | no | Specifies if the control is disabled or not. |
6565
| openAttachmentsInNewWindow | boolean | no | Specifies if the attachment should be opened in a separate browser tab. Use this property set to `true` if you plan to use the component in Microsoft Teams. |
66+
| onAttachmentChange | (itemData: any) => void | no | Callback function invoked when attachments are added or removed. Receives the updated item data including the new ETag. This is useful when using the control within a form (like DynamicForm) that tracks ETags for optimistic concurrency control. |
67+
68+
## Usage with DynamicForm
69+
70+
When using `ListItemAttachments` within a `DynamicForm` or any component that uses ETags for optimistic concurrency control, you should use the `onAttachmentChange` callback to update the ETag when attachments are modified:
71+
72+
```TypeScript
73+
import * as React from 'react';
74+
import { DynamicForm } from '@pnp/spfx-controls-react/lib/DynamicForm';
75+
import { ListItemAttachments } from '@pnp/spfx-controls-react/lib/ListItemAttachments';
76+
77+
export class MyFormComponent extends React.Component<any, any> {
78+
private dynamicFormRef = React.createRef<DynamicForm>();
79+
80+
/**
81+
* Callback invoked when attachments are added or removed
82+
* Updates the ETag in DynamicForm to prevent 412 conflicts
83+
*/
84+
private onAttachmentChange = (itemData: any): void => {
85+
if (this.dynamicFormRef.current) {
86+
this.dynamicFormRef.current.updateETag(itemData);
87+
}
88+
}
89+
90+
public render(): React.ReactElement {
91+
return (
92+
<div>
93+
<ListItemAttachments
94+
listId={listId}
95+
itemId={itemId}
96+
context={this.props.context}
97+
onAttachmentChange={this.onAttachmentChange}
98+
/>
99+
100+
<DynamicForm
101+
ref={this.dynamicFormRef}
102+
context={this.props.context}
103+
listId={listId}
104+
listItemId={itemId}
105+
respectETag={true}
106+
/>
107+
</div>
108+
);
109+
}
110+
}
111+
```
112+
113+
This prevents 412 ETag conflict errors when saving the form after adding or removing attachments.
66114

67115
![](https://telemetry.sharepointpnp.com/sp-dev-fx-controls-react/wiki/controls/ListItemAttachments)

src/controls/dynamicForm/DynamicForm.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,21 @@ export class DynamicFormBase extends React.Component<
121121
this._customFormatter = new CustomFormattingHelper(this._formulaEvaluation);
122122
}
123123

124+
/**
125+
* Updates the ETag stored in the component's state.
126+
* This is useful when the list item has been modified externally (e.g., by adding/removing attachments)
127+
* and you need to update the ETag to prevent 412 conflict errors on save.
128+
*
129+
* @param itemData - The updated item data containing the new ETag
130+
*/
131+
public updateETag(itemData: any): void { // eslint-disable-line @typescript-eslint/no-explicit-any
132+
if (itemData && itemData["odata.etag"]) {
133+
this.setState({
134+
etag: itemData["odata.etag"]
135+
});
136+
}
137+
}
138+
124139
/**
125140
* Lifecycle hook when component is mounted
126141
*/

0 commit comments

Comments
 (0)