Modern page provisioning using page template

In this article let's see how to dynamically provision a modern page based on a modern page template and update its webpart properties using pnp/js in SPFx React webpart.

Create a modern page template

Create a page and add the webpart as per your requirements, finally save it as a template. it will be stored under the "Templates" folder in SitePages.

In the below example I have as Section=>3 Colum layout=>3 webparts.






Create a page provision form component


public render(): React.ReactElement<IDynamicPageCreaterProps> {
    let thisHandler = this;
    return (
      <div>
        <h1>{this.props.webpartName}</h1>
        {
          (this.props.selectedTemplate != undefined) ?
            <h4><i>Selected Template- {this.props.selectedTemplate.text}</i></h4> :
            <h4>Selcte Template in webapart property</h4>
        }
        <div>
          <TextField id="txtPageName" label="Page Name" onChanged={(val=> {
            this.setState({ pageName: val })
          }} />

          <TextField label="Page Title" onChanged={(val=> {
            this.setState({ pageTitle: val })
          }} />
          <br /> 

          <PrimaryButton text="Create Page" onClick={() => this.CreatePage()} />
        </div>
      </div>
    );
  }


Which looks like the below and waiting for user input.



Provision modern page based on the template

Using pnp/js we have to load the template relative URL(in my case I am reading ti from webpart property), then using the copy method from pnp/js to create a page by providing name, title from my "state" variables. 

  
//Load Template
  const page = sp.web.loadClientsidePage(this.props.selectedTemplate.key);
  page.then((pageResponse=> {
  //Create page based on the template
  let pageVar = pageResponse.copy(sp.webthis.state.pageNamethis.state.pageTitlefalse);
....
....


Scan newly created page for webparts & Update webpart properties 

Since we structured this page template we know the available webparts. So, we can target them individually and apply their appropriate webpart properties.

In code, we need to scan it in the below order:

|-Sections
|--Section
|---Columns
|----Column
|-----Control(s)


pageVar.then(async (_page=> {
        _page.sections.forEach(section => {
          section.columns.forEach(column => {
            column.controls.forEach(control => {
              switch (control.id) {
                //Left Image webpart
                case "7892e87e-832f-4255-9078-b45db861cc8c": {
                  let prop = {
                    imageSource: "https://xxx.sharepoint.com/sites/Development/Shared%20Documents/photo-1615607905884-366831fc787f.jfif",
                    altText: "Sample Image alttext",
                    overlayText: "Sample Overlay text",
                    "imgWidth": "200",
                    "imgHeight": "300",
                    "alignment": "Center"
                  }
                  // all-props
                  // "imageSourceType": 0,
                  // "imageSource": "",
                  // "captionText": "",
                  // "altText": "",
                  // "linkUrl": "",
                  // "overlayText": "",
                  // "fileName": "",
                  // "siteId": "",
                  // "webId": "",
                  // "listId": "",
                  // "uniqueId": "",
                  // "imgWidth": "",
                  // "imgHeight": "",
                  // "alignment": "Center"    

                  //Update properties with custom values
                  control.setProperties(prop);
                  break;
                }

                //Middle Text editor webpart
                case "a875946b-bf76-47e3-afc3-1c296f1b9a12": {
                  control.data.innerHTML = "this is dynamic content 1";
                  break;
                }

                //Right Text editor webpart
                case "dd643bdf-6924-4a46-b86f-3cf409ecfc8c": {
                  control.data.innerHTML = "this is dynamic content 2";
                  break;
                }
              }

              //Save the page with updated properties.
              _page.save();
            });
          });
        });
      });



Final Output















Comments

  1. Nice solution, can this also be used for SharePoint 2019 (on-premises)?

    ReplyDelete

Post a Comment

Enter your comments..

Popular posts from this blog

Secure When a HTTP request is received Power Automate a.k.a MS Flow

People picker Control in PowerApps

Upload attachment to SharePoint list item using Microsoft Flow

Approval and auto escalation with time out in Microsoft Flow

Headless-Daemon calling AAD secured API

Developing custom reusable components in PowerApps

Step-By-Step Azure AD App Registration

HTML field & Date Time formatting in powerapps

Create and configure custom connectors for PowerApps and MSFlow from AzureFunctions