pnp / sp-dev-fx-controls-react

Reusable React controls for SPFx solutions
https://pnp.github.io/sp-dev-fx-controls-react/
MIT License
380 stars 380 forks source link

[Dynamic Form] Implement Attachments functionality #1795

Open Ruslan-Urban opened 3 months ago

Ruslan-Urban commented 3 months ago

Category

Version 3.17.0

Expected / Desired Behavior / Question

Standard SharePoint list forms implement Attachments functionality. This functionality is required for our implementation. Ideally, I would like to inject simple customizations into standard SharePoint forms, similar to injecting JSLink in classic forms. However, no such functionality exists in modern forms. For example, I need to set default value of the Org Unit field from a URL parameter value and make the field read only. Now, the only way we can implement it is with SPFx or Power Apps. Both options are an overkill and a deployment and maintenance nightmare. If there was a site collection feature to enable custom JavaScript injections, that would address a myriad of challenges.

Observed Behavior

Attachments functionality is missing from Dynamic Forms component.

Steps to Reproduce

Implement Form Customizer extensions with a Dynamic Form for a list that has attachments enabled. Notice that Attachments control is missing from the form.

wuxiaojun514 commented 3 months ago

Hi , I have some sample code to implement attachment functionality in Form Customizer. You need use ListItemAttachments control.

First , you need declare listItemAttachmentsComponentReference in the component class, it will be used if it is a new item. SharePoint need create the item first before upload the attachment.

private listItemAttachmentsComponentReference = React.createRef<ListItemAttachments>();

Then update the render method with the following code. Note: it would have two scenarios : Create New Item (this.props.context.itemId does not exist, the attachment will be uploaded in Dynamic Form onSubmittedevent ) and Update Existing Item (contains itemId)

  public render(): React.ReactElement<{}> {

    return (
      <div className={styles.demo + " ms-Fabric--v6-0-0"} >
        <SiteBreadcrumb context={this.props.context as any} />
        <DynamicForm
          context={this.props.context as any}
          listId={this.props.context.list.guid.toString()}
          listItemId={this.props.context.itemId}
          contentTypeId={this.props.context.contentType.id}
          onCancelled={
            this.props.onClose
          }

          onSubmitError={(listItem, error) => {
            alert(error.message);
          }}
          onSubmitted={(listItemData: any) => {
            console.log(listItemData);
            if (this.props.displayMode === FormDisplayMode.New) {
              this.listItemAttachmentsComponentReference.current.uploadAttachments(listItemData.Id).then((data) => {
                this.props.onSave();
              })
            }
            else {
              setTimeout(() => {
                this.props.onSave();
              }, 1000);
            }

          }} />
        <div className="ms-Grid-col ms-sm12 ms-md12 ms-lg12">
          {
            this.props.context.itemId ? <ListItemAttachments listId={this.props.context.list.guid.toString()}
              openAttachmentsInNewWindow={true}
              itemId={this.props.context.itemId}
              description="Please put document here"
              context={this.props.context as any}
              disabled={this.state.readonly} /> :
              <ListItemAttachments
                ref={this.listItemAttachmentsComponentReference}
                description="Please put document here.   Note: It is not able to preview since it hasn't been uploaded to site"
                openAttachmentsInNewWindow={true}
                context={this.props.context as any}
                listId={this.props.context.list.guid.toString()}
                itemId={0} />
          }
        </div>
      </div>
    )
  }

Here is how it looks like in my project. image