Open form in a panel with iframe (redirect parent site)

Hi,

I designed a custom webpart to display list items as cards. For this I created a custom "new item" button and also try to open the display form when clicking at the element title.

At first the iframe opens the default form (e.g. "DispForm.aspx?IsDlg=1"). But as soon as the form gets loaded, the whole website gets redirected to the plumsail form.

Logging in the console shows:

Panel mounted
URL: "/sites/mySite/Lists/Tickets/NewForm.aspx?IsDlg=1"
spredirect.js:1 /sites/mySite/SitePages/PlumsailForms/Tickets/Tickets/NewForm.aspx
Navigated to https://<mytenant>.sharepoint.com/sites/mySite/SitePages/PlumsailForms/Tickets/Tickets/NewForm.aspx

If we load the plumsail form direct by passing the "correct" url, it loads just fine in the panel without redirecting the parent :slight_smile: (but that's not possible, because we use the "listinfos => forms" from @pnp/sp/forms rest call to get the "default" forms)

The right side panel is the fabric ui default panel with an iframe inside:
https://developer.microsoft.com/en-us/fluentui#/controls/web/panel

<Panel
                type={PanelType.medium}
                isBlocking={false}
                isOpen={this.state.isOpen}
                headerText={this.props.title}     
                className={this.props.className}           
                >
                {   this.state.loading &&
                    <Spinner size={SpinnerSize.large} ></Spinner>
                }
                <iframe 
                    className={"defaultClass " + (this.state.loading?this.cssClass:"")}
                    src={this.props.url}                
                    onLoad={this.iframeLoaded.bind(this)}
                    ref={this.iFrameRef}
                >
                </iframe>
            </Panel>

How to make it work? Thx a lot!

Dear @Hagrid,
An interesting case, but the details are a little vague... Would you be able to attach some screenshots or maybe a short of video of what this looks like in your environment? I just want to get the full picture.

Hi @Nikita_Kurguzov ,

screencast 1 shows opening the (custom) iframe with the standard sharepoint form

After creating a plumsail form and reopening, the iframe opens one second and after that the whole site redirects to the plumsail form (https://mysite/SitePages/PlumsailForms/testlist/Tickets/NewForm.aspx)

Dear @Hagrid,
How does the custom iFrame know what form to open? Can you just use the final URL of the form in the iframe?

The issue is that before any specific form is opened, you get a redirect page which selects which form to open. We avoid it in our panel, of course, but this could happen with custom solutions.

Hi @Nikita_Kurguzov

this is the response of the rest service (pnp, https://pnp.github.io/pnpjs/sp/lists/#forms)

[
	{
		"odata.type":"SP.Form",
		"odata.id":"https://mySite.sharepoint.com/_api/Web/Lists(guid'c9ca98cf-a3fa-4537-be2a-abcdefghijklm')/Forms(guid'47ce30a0-1209-4716-ad5f-e3e8c9ed51ee')",
		"odata.editLink":"Web/Lists(guid'c9ca98cf-a3fa-4537-be2a-abcdefghijklm')/Forms(guid'47ce30a0-1209-4716-ad5f-e3e8c9ed51ee')",
		"Id":"47ce30a0-1209-4716-ad5f-e3e8c9ed51ee",
		"ResourcePath":{"DecodedUrl":"Lists/Test3/DispForm.aspx"},
		"ServerRelativeUrl":"/Lists/Test3/DispForm.aspx",
		"FormType":4
	},
	{
		"odata.type":"SP.Form",
		"odata.id":"https://mySite.sharepoint.com/_api/Web/Lists(guid'c9ca98cf-a3fa-4537-be2a-abcdefghijklm')/Forms(guid'b21ab0a4-3364-4460-abe2-bf174f76aa0d')",
		"odata.editLink":"Web/Lists(guid'c9ca98cf-a3fa-4537-be2a-abcdefghijklm')/Forms(guid'b21ab0a4-3364-4460-abe2-bf174f76aa0d')",
		"Id":"b21ab0a4-3364-4460-abe2-bf174f76aa0d",
		"ResourcePath":{"DecodedUrl":"Lists/Test3/EditForm.aspx"},
		"ServerRelativeUrl":"/Lists/Test3/EditForm.aspx",
		"FormType":6
	},
	{
		"odata.type":"SP.Form",
		"odata.id":"https://mySite.sharepoint.com/_api/Web/Lists(guid'c9ca98cf-a3fa-4537-be2a-abcdefghijklm')/Forms(guid'9f69e052-02ef-4ed8-a701-a0b4f9ab28d2')",
		"odata.editLink":"Web/Lists(guid'c9ca98cf-a3fa-4537-be2a-abcdefghijklm')/Forms(guid'9f69e052-02ef-4ed8-a701-a0b4f9ab28d2')",
		"Id":"9f69e052-02ef-4ed8-a701-a0b4f9ab28d2",
		"ResourcePath":{"DecodedUrl":"Lists/Test3/NewForm.aspx"},
		"ServerRelativeUrl":"/Lists/Test3/NewForm.aspx",
		"FormType":8
	}
] 

If I use the final URL, everything opens correctly without redirecting:
url = "/SitePages/PlumsailForms/Test3/Tickets/NewForm.aspx?IsDlg=1"

But I want to develop a general webpart. This means that not all forms are necessarily provided via Plumsail.
Is it possible to get the final plumsail form url by any query or can I avoid the redirect?

Thanks.

Dear @Hagrid,
I see! This is what you can try, though, be wary it's not recommended and it's an undocumented trick (so, it's functionality is subject to change in some ways).

Our redirect page detects whether the form is opening in our dialog or in the full window by the following property:
typeof window.frameElement.__fdCloseDialog === 'function'

If the property exists, 'redirect' opens the form in the same window and the above function is called when a user closes the form.

So you need to obtain the iframe from DOM and attach '__fdCloseDialog' field to it:

iframe.__fdCloseDialog = function() {};

Thank you @Nikita_Kurguzov!
It works like a charm :slight_smile:

1 Like

Hello @Hagrid ,
I have the same issue, can you share the code you used to associate the __fdCloseDialog function into your iframe component ?
Thank you !
David

Hi David,

here are some code snippets. Hope they are useful.

public setIFrameRef(ctx){
        let iFrame = ctx;
        if(iFrame && !iFrame.cancelPopUp){
            this.iFrameRef = iFrame;
            iFrame.cancelPopUp = this.closeIframe.bind(this, false);
            iFrame.commitPopup = this.closeIframe.bind(this, true);
            iFrame.commonModalDialogClose = this.closeIframe.bind(this, false);
            // hack for plumsail forms to avoid redirect
            iFrame.__fdCloseDialog = this.closeIframe.bind(this, true);
            this.hasEventHandler = true;
        }
   }

//ctx = iframe dom element

public render() {
        return (
            <Panel
                type={PanelType.medium}
                isBlocking={false}
                isOpen={this.state.isOpen}
                headerText={this.props.title}     
                className={this.props.className}           
                >
                {   this.state.loading &&
                    <Spinner size={SpinnerSize.large} ></Spinner>
                }
                <iframe 
                    className={"kanbanBoardiFrame " + (this.state.loading?this.cssClass:"")}
                    src={this.props.url}                
                    onLoad={this.iframeLoaded.bind(this)}
                    ref={this.setIFrameRef.bind(this)}
                >
                </iframe>
            </Panel>
        );
    }

So the setIFrameRef function is additionally registered.

1 Like

Thank you @Hagrid for your reply. Meanwhile I have managed to figure it out by adding the sandbox attributes in the iframe element:
**<iframe src='https://mysite.com' frameBorder='0' sandbox='allow-modals allow-scripts allow-same-origin'>
Cheers