Binding buttons in SPFx

When writing a react based SPFx application one has to make a note that ES6 React.Component doesn’t auto bind methods to itself.

Hence it’s required to manually bind and the following are two ways to do it.

Method 1

onClick={this.addButtonClicked.bind(this)}

import * as React from 'react';

import { Stack, IStackProps, IStackStyles } from 'office-ui-fabric-react/lib/Stack';
import { ActionButton } from 'office-ui-fabric-react/lib/Button';
import { IIconProps } from 'office-ui-fabric-react/';

import { ITestComponentState } from './ITestComponentState';
import { ITestComponentProps } from './ITestComponentProps';

//Stack related styles
const outerStackTokens = {
    childrenGap: 50
};
const addFriendIcon: IIconProps = { iconName: 'Add' };

let outerStackStyles: Partial<IStackStyles> = {};
let innerStackColumnProps: Partial<IStackProps> = {};

export default class TestComponent extends React.Component<ITestComponentProps, ITestComponentState> {
    constructor(props: ITestComponentProps) {
        super(props);
        this.state = {
            items: []
        };
    }
  
    public render(): React.ReactElement<{}> {
        return (
            <div>
                <Stack horizontal tokens={outerStackTokens} styles={outerStackStyles}>
                    <Stack verticalAlign="start" {...innerStackColumnProps}>
                        <Stack.Item align="start" >
                            <ActionButton iconProps={addFriendIcon} onClick={this.addButtonClicked.bind(this)} allowDisabledFocus disabled={this.state.sortItems.length >= 10 ? true : false} >Add Item</ActionButton>
                        </Stack.Item>
                    </Stack>
                </Stack>
            </div>
        );
    }

    private addButtonClicked(event?: React.MouseEvent<HTMLButtonElement>) {
        let itemsOnAdd = this.state.items;
        let itemTitle = "Item " + (this.state.items.length + 1);
        itemsOnAdd.push({ title: itemTitle });
        this.setState({ items: itemsOnAdd });
    }
}

Method 2

this.addButtonClicked = this.addButtonClicked.bind(this);

import * as React from 'react';

import { Stack, IStackProps, IStackStyles } from 'office-ui-fabric-react/lib/Stack';
import { ActionButton } from 'office-ui-fabric-react/lib/Button';
import { IIconProps } from 'office-ui-fabric-react/';

import { ITestComponentState } from './ITestComponentState';
import { ITestComponentProps } from './ITestComponentProps';

//Stack related styles
const outerStackTokens = {
    childrenGap: 50
};
const addFriendIcon: IIconProps = { iconName: 'Add' };

let outerStackStyles: Partial<IStackStyles> = {};
let innerStackColumnProps: Partial<IStackProps> = {};

export default class TestComponent extends React.Component<ITestComponentProps, ITestComponentState> {
    constructor(props: ITestComponentProps) {
        super(props);
        this.state = {
            items: []
        };
        this.addButtonClicked = this.addButtonClicked.bind(this);
    }
  
    public render(): React.ReactElement<{}> {
        return (
            <div>
                <Stack horizontal tokens={outerStackTokens} styles={outerStackStyles}>
                    <Stack verticalAlign="start" {...innerStackColumnProps}>
                        <Stack.Item align="start" >
                            <ActionButton iconProps={addFriendIcon} onClick={this.addButtonClicked} allowDisabledFocus disabled={this.state.sortItems.length >= 10 ? true : false} >Add Item</ActionButton>
                        </Stack.Item>
                    </Stack>
                </Stack>
            </div>
        );
    }

    private addButtonClicked(event?: React.MouseEvent<HTMLButtonElement>) {
        let itemsOnAdd = this.state.items;
        let itemTitle = "Item " + (this.state.items.length + 1);
        itemsOnAdd.push({ title: itemTitle });
        this.setState({ items: itemsOnAdd });
    }
}

Generate PDF from SharePoint Online list item using Power Automate

Generating a PDF from SharePoint used to be a common requirement and when using server-side object model, it was easy to use some kind of PDF library and generate PDFs. But in SharePoint Online we can use Power Automate to generate PDFs and the following are the steps that can be used for this.

There are two ways by which a PDF can be generated.

  • Using OneDrive for Business’s “Convert HTML file to PDF”
  • Word Online’s “Populate a Microsoft Word Template” & “Convert Word Document to PDF” (These are premium action so a premium license is required and is in preview as of Feb 2021.)

In my example the scenario is to generate an invite pass for attendees attending a conference.

The generated PDF

The generated PDF will look like the following.

The data source

SharePoint List

Here we are using SharePoint Online and the data source is a simple SharePoint list which contains the following.

OneDrive for Business

The OneDrive for Business has two artificats

  1. A Logo image is used for both methods.
  2. A Microsoft Word Document (This will be used for the second method and not for the first method)

Please note that for both methods, the Power Automate is triggered whenever the SharePoint list item is created or modified.

In the below article when the product “OneDrive” is mentioned, it’s actually “OneDrive for Business”.

Method 1: Using OneDrive for Business’s “Convert HTML file to PDF”

The trigger is when a SharePoint List item is created or modified.

The next action would be to fetch the image of the logo located in the OneDrive.

Now we have to convert the logo into a Uri format using the expression editor and initialize a variable with it.

dataUri(outputs('Get_logo_file_content')?['body'])

Creating the HTML Content

Next is the important action where the actual HTML content will be created.

HTML Content Method 1: Using Simple HTML script like below.

<html>
    <body>
        <p>
            <img style="display: block; margin-left: auto; margin-right: auto;" src="" alt="">
            <img>
        </p>
        <p style="text-align: center;">
            <h1>
            </h1>
        </p>
        <p style="text-align: center;">
            <h2>
            </h2>
        </p>
    </body>
</html>

For the seasoned HTML developer who is well versed with HTML & CSS, he/she/they can create the HTML content or the other easiest method is to use the Microsoft Word desktop software to create the HTML.

If you use a simple method, do make sure the CSS is perfect. For the most part I tried, the conversion from HTML to PDF kept ignore the CSS, hence the second method.

HTML Content Method 2: Using Microsoft Word

  1. Open the Microsoft Word.
  2. Design the contents.
  3. Save the file as “Web Page, Filtered”.
  4. Open that file using an HTML Editor or Notepad and copy the contents.
<html>

<head>
	<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
	<meta name=Generator content="Microsoft Word 15 (filtered)">
	<style>
		<!--
		/* Font Definitions */
		@font-face {
			font-family: "Cambria Math";
			panose-1: 2 4 5 3 5 4 6 3 2 4;
		}

		@font-face {
			font-family: Calibri;
			panose-1: 2 15 5 2 2 2 4 3 2 4;
		}

		@font-face {
			font-family: "Calibri Light";
			panose-1: 2 15 3 2 2 2 4 3 2 4;
		}

		/* Style Definitions */
		p.MsoNormal,
		li.MsoNormal,
		div.MsoNormal {
			margin-top: 0cm;
			margin-right: 0cm;
			margin-bottom: 8.0pt;
			margin-left: 0cm;
			line-height: 107%;
			font-size: 11.0pt;
			font-family: "Calibri", sans-serif;
		}

		h1 {
			mso-style-link: "Heading 1 Char";
			margin-top: 12.0pt;
			margin-right: 0cm;
			margin-bottom: 0cm;
			margin-left: 0cm;
			line-height: 107%;
			page-break-after: avoid;
			font-size: 16.0pt;
			font-family: "Calibri Light", sans-serif;
			color: #2F5496;
			font-weight: normal;
		}

		span.Heading1Char {
			mso-style-name: "Heading 1 Char";
			mso-style-link: "Heading 1";
			font-family: "Calibri Light", sans-serif;
			color: #2F5496;
		}

		.MsoChpDefault {
			font-family: "Calibri", sans-serif;
		}

		.MsoPapDefault {
			margin-bottom: 8.0pt;
			line-height: 107%;
		}

		@page WordSection1 {
			size: 595.3pt 841.9pt;
			margin: 72.0pt 72.0pt 72.0pt 72.0pt;
		}

		div.WordSection1 {
			page: WordSection1;
		}
		-->
	</style>

</head>

<body lang=EN-IN style='word-wrap:break-word'>

	<div class=WordSection1>

		<p class=MsoNormal align=center style='text-align:center'><img width=200 height=200 id="Picture 1"
				src="Word-HTML_files/image001.png" alt="Icon&#10;&#10;Description automatically generated"></p>

		<h1 align=center style='text-align:center'>Kannan Balasubramanian</h1>

		<p class=MsoNormal align=center style='text-align:center'>2</p>

	</div>

</body>

</html>

Create an action to initialise a variable and paste the contents. Replace the image source with “LogoUri” variable, Title & ID from the trigger “When an item is created or modified”.

variables('LogoUri')
triggerOutputs()?['body/Title']
triggerOutputs()?['body/ID']

Now the HTML contents should be saved to a HTML file. We are going to use OneDrive’s “Create file” action and will use the same “Dev” folder to create the file and use the ID as file name to uniquely generate a file for each item and the file content as the “HTMLContent” variable.

triggerOutputs()?['body/ID']
variables('HTMLContent')

The created HTML file now can be converted to a PDF file and we will use OneDrive’s “Convert file using path” action. The “File Path” will rely on the “Create HTML file” action’s “Path” property.

Converting HTML Content to PDF

This action is in preview as of February 2021.

outputs('Create_HTML_file')?['body/Path']

Once converted the PDF content will be saved as a file using OneDrive’s “Create file” action.

triggerOutputs()?['body/ID']
outputs('Convert_HTML_file_to_PDF_using_path')?['body']

Deleting the HTML File

If required we will use OneDrive’s “Delete file” action to delete the HTML file which was generated previously to avoid wasting the space.

outputs('Create_HTML_file')?['body/Path']

Testing

Now save the Power Automate and test it once to check if it’s working fine.

Create a new item in SharePoint and save it.

Go to OneDrive and check if the file is generated.

Open the file to check if it has been created.

Method 2: Using Word Online’s “Convert Word Document to PDF”

The trigger is when a SharePoint List item is created or modified.

The next action would be to fetch the image of the logo located in the OneDrive.

Now we have to convert the logo into a Uri format using the expression editor.

dataUri(outputs('Get_logo_file_content')?['body'])

Creating Word template

Open a word and if the developer tab is not available, configure the word to make it visible as shown below.

  • Click on the tab “File.
  • Click on the menu “Options”
  • Click on the tab “Customize Ribbon”
  • Check the item “Developer” if not already checked.

Now you should have a developer tab in the ribbon.

Now use the “Picture Control Content” to add a place holder for the logo.

Once added, click on the placed “Picture Control Content” and then click on “Properties” in the ribbon to set the “Title” as “Logo” & “Tag” as “Logo”

Repeat the same for Title & ID using the “Rich Text Content Control”

Once added, click on the properties to set a “Title” as “Title” & “Tag” as “Title” for the title place holder and “Title” as “Id” & “Tag” as “Id” for ID place holder and use formats like alignment and text styles in the “Home tab”.

The word document should look like below.

Now save the file as a normal Word document with .docx extension. Upload the word document into OneDrive as “Invite-Template.docx”

Now lets go back to the Power Automate and add an action “Populate a Microsoft Word template” of “Word Online”. Choose the location of “File” where the template file was uploaded. For Logo use the “File Content” from the “Get logo file content” (Note: We are not using the “LogoUri” variable here). For “Title” & “Id”, use the “Title” & “ID” from the trigger “When an item is created or modified”.

This is a premium action so a premium license is required and is in preview as of February 2021.

outputs('Get_logo_file_content')?['body']
triggerOutputs()?['body/Title']
triggerOutputs()?['body/ID']

Now add OneDrive’s “Create File” action. Choose the “Folder Path” from OneDrive, where the filled Word document should be saved, along with the “File Name” being ID of the SharePoint item and “File Content” from the action “Populate a Microosft Word template”.

triggerOutputs()?['body/ID']
outputs('Populate_a_Microsoft_Word_template')?['body']

Converting Word Content to PDF

Now lets convert the Word document into PDF by creating the action “Convert Word Document to PDF” of “Word Online” pointing the “File” to the path returned by “Create Word file via Word template”.

This is a premium action so a premium license is required and is in preview as of February 2021.

outputs('Create_Word_file_via_Word_template')?['body/Path']

Now let’s use OneDrive’s “Create file” action to create the PDF file in OneDrive.

triggerOutputs()?['body/ID']
outputs('Convert_Word_Document_to_PDF')?['body']

Deleting the Word File

If required we will use OneDrive’s “Delete file” action to delete the Word file which was generated previously to avoid wasting the space.

outputs('Create_Word_file_via_Word_template')?['body/Path']

Testing

Now save the Power Automate and test it once to check if it’s working fine.

Create a new item in SharePoint and save it.

Go to OneDrive and check if the file is generated.

Open the file to check if it has been created.

Item level permission in SharePoint using REST and Power Automate

Sometimes when an item is created we might need to set item level permission for those items. Fortunately, SharePoint’s REST API can help with this and Power Automate / Flow supports SharePoint HTTP calls.

For this to work, make sure the Power Automate is created with an account having site collection administrator access.

First the basics of how this works

Step 1 is to identify to whom the permissions should be granted to. It can be either a person or a group.

Step 2 is to identify what kind of permission i.e. role should be granted.

Step 3 is breaking the inheritance.

Step 4 is assigning the permission.

Second is knowing the supporting APIs to gather the information

Step 1: To whom the permission should be granted?

Individual user

To identify the individual user the following API can be used. Commonly everyone relies on e-mail ID so lets take that as an example

URL: _api/web/SiteUsers/getByEmail('email@domain.com')
Method: Get

When you use Power Automate, make sure to extract the ID and place it in a variable.

body('Get_User_Id')['d']['Id']

Site Group

To identify the site group the following API can be used.

URL: _api/web/sitegroups/getbyname('Group Name')
Method: Get

When you use Power Automate, make sure to extract the ID and place it in a variable.

body('Get_Group_Id')['d']['Id']

Step 2: What kind of permission?

This is defined by the role definitions available in the site. The following API will help in identifying the role definitions and their ID.

URL: _api/roledefinitions/getbyname('Full Control')
Method: Get

When you use Power Automate, make sure to extract the ID and place it in a variable.

body('Get_Role_Definition_Id')['d']['Id']

Step 3: Breaking the inheritance

For this first thing is we need to identify the target for which the inheritance should be broken. In the following example it’s a list item.

URL: _api/lists/getByTitle('<List Name>')/items(<Item ID>)/breakroleinheritance(copyRoleAssignments=false,clearSubscopes=true)
Method: POST

Example:

URL: _api/lists/getByTitle('Test List')/items(1)/breakroleinheritance(copyRoleAssignments=false,clearSubscopes=true)

Step 4: Assigning permission

As said before permission can be assigned to an individual or a group. The following API will help with that

URL: _api/lists/getByTitle('<List Name>')/items(<Item ID>)/roleassignments/addroleassignment(principalid=<User ID or Group ID>,roledefid=<Role ID>)
Method: POST

Example:

URL: _api/lists/getByTitle('Test List')/items(1)/roleassignments/addroleassignment(principalid=10,roledefid=1073741829)

Following is the list of out of the box role definitions which I came across in the internet

Role Definition NameRole Definition Id
Full Control1073741829
Design1073741828
Edit1073741830
Contribute1073741827
Read1073741826
View Only1073741924
Limited Access1073741825

Useful URL

You can refer the following URL which has code example to use REST api.

Set custom permissions on a list by using the REST interface

Hide JSON column formatting for folder content type in SharePoint Online

In SharePoint online, sometimes we need to hide the JSON Column formatting.
For this a visibility condition can be added based on the folder content type.

Following is a simple JSON which can help.

{
    "$schema": "https://developer.microsoft.com/json-schemas/sp/column-formatting.schema.json",
    "elmType": "a",
    "txtContent": "Navigate to home page",
    "style": {
        "cursor": "pointer",
        "visibility": "=if(((indexOf([$ContentTypeId],'0x0120')) == 0),'hidden', 'visible')"
    },
    "attributes": {
        "target": "_self",
        "href": "= @currentWeb"
    }
}
Hide JSON column formatting for folder content type in SharePoint Online

View unpublished pages or draft pages or published pages in SharePoint

Microsoft SharePoint Logo Sometimes it’s necessary to know the status of all the pages before a site is made live. It becomes especially difficult when a team works together on multiple pages and there are number of pages which might have not been published and site owner has to make sure all the pages are published.

We will create a view which can help a site owner to view unpublished pages or draft pages or published pages in SharePoint.

The technique is using the “Version” column to determine the decimal part of the “Version” by subtracting the integer part from the “Version”. So if there is any decimal value in the “Version” then it’s in unpublished or draft state.

Do note that this technique depends upon the “Document Version History” settings being “Create major and minor (draft) versions” for that library.

Document Version History
Document Version History settings

This involves two steps

  1. Add a calculated column which helps to determine the page state using version value.
  2. Create a new view or update an existing view to display the created calculated column.

Create column to know the page status

  1. Create a new column and name it “PageStatus” (We will later rename it to “Page Status”).
  2. Set the type to “Calculated”.
  3. Add the below formula and save the column settings. (Note: The “Version” column will not be available in “Insert Column:” pane so just copy paste the formula.)
=If((Version-INT(Version))<>0,"Draft","Published")
  1. In the library settings, click on the column to edit.
  2. Change the column name to “Page Status” and click “OK” button.
Create a column to show page status.
“Page Status” column creation

Library view to show the page status

We can either create a new view or modify an existing view to show the “Page Status”. For this all that needs to be done is add the “Page Status” column to the view.

Library view to show the “Page Status”

Prevent file download in SharePoint

Microsoft SharePoint Logo

Microsoft SharePoint LogoMicrosoft SharePoint Logo Sometimes in SharePoint there will be a scenario where users shouldn’t download documents, but yet should be able to view the documents. In many of the sites it’s mentioned that this is not possible. But in reality as of March 2020, this is possible.

Generally the permission level “View Only: Can view pages, list items, and documents. Document types with server-side file handlers can be viewed in the browser but not downloaded.” is not available by default. But the site collection feature “SharePoint Server Enterprise Site Collection features” when activated will enable this permissions level.

Note that this will work only for Microsoft Office files like Word, Excel, PowerPoint etc. Still users will be able to download other file type. The reason is SharePoint uses handler for viewing and editing Microsoft Office files which can prevent download.

Perform the following steps to enable the permission level

  1. Launch “Site collection features” under “Site Settings”.
  2. Activate “SharePoint Server Enterprise Site Collection features”.
  3. Go to the library’s settings and launch “Permissions for this document library”.
  4. Enable unique permissions.
  5. Then select the specific “SharePoint group” and click “Edit User Permissions”.
  6. Now you should be able to see the permission level ” View Only: Can view pages, list items, and documents. Document types with server-side file handlers can be viewed in the browser but not downloaded.”
  7. Check that permission and uncheck all other permissions.
  8. Now all the users within that group will only be able to view the document in web-viewer and will not be able to download.

Before applying permission

The “Download” menu is visible. Clicking “Open” will open the file in web viewer.

After applying permissions

The “Download” menu is not visible. Clicking “Open” will open the file in web viewer.

SharePoint Online theme error – There was an error while attempting to get the themes

Microsoft SharePoint Logo Recently when I was trying to change the theme of a SharePoint online site collection, it threw an error “There was an error while attempting to get the themes”

The error looks like the one shown below (Taken from Microsoft Tech Community)

There was an error while attempting to get the themes

To fix this error, the easiest method as of March 2020 is do the following.

  1. Click on “Classic change the look options” menu item shown in the screenshot above.
  2. Choose one of the theme.
  3. Preview it by clicking on “Try it out”.
  4. Then click on “Yes, keep it”
  5. Again load the home page
  6. Try changing the theme, and the error should be gone.

Thanks to Rob for providing the work around here.

Change SharePoint Wiki Page Title

Microsoft SharePoint Logo At the time of writing this article, Microsoft has already rolled out the modern experience to all the lists and libraries.

In the old classic sites, there was a possibility to change the the title of Wiki pages and now that is almost gone, but still there is a way to change the title.

Follow the steps below to change the wiki page title.

  1. In the SitePages/Pages switch to “Return to classic SharePoint” at the bottom left.
  2. Edit the views of “By Author” or “All Pages”.
    1. Add the column “Title”.
    2. Save the changes to the view.
  3. Go back to the view.
  4. Click on the ribbon and expand tab “Library”.
  5. Click on the “Quick Edit”.
  6. Make the changes to the respective page’s title column.
  7. Exit “Quick Edit” to save the changes.

Do please note that for now this works but not sure how long Microsoft will keep this option open.

Enabling SharePoint App catalogue at site collection level in SharePoint Online

Microsoft SharePoint Logo Sometimes we require to deploy SharePoint apps to a development site collection instead of tenant app catalogue. During those scenarios the following PowerShell command can be used to enable the app catalogue at site collection level.

Please note that you will require SharePoint Online Management Shell for this PowerShell to work. Please refer here for installation.

Enabling site collection app catalogue

Connect-SPOService -Url https://yourtenant-admin.sharepoint.com

# Reference of the site collection where the site collection app catalogue should reside
$site = Get-SPOSite https://yourtenant.sharepoint.com/sites/yoursitecollection
 
# Create app catalogue in the site collection
Add-SPOSiteCollectionAppCatalog -Site $site

Disabling site collection app catalogue

Connect-SPOService -Url https://yourtenant-admin.sharepoint.com

# Reference of the site collection where the site collection app catalogue should reside
$site = Get-SPOSite https://yourtenant.sharepoint.com/sites/yoursitecollection
 
# Remove app catalogue from the site collection
Remove-SPOSiteCollectionAppCatalog -Site $site 

Remove the title banner from SharePoint modern page

Microsoft SharePoint Logo The title banner in the modern pages of SharePoint takes a lot of space.

Even if you try to switch to “Plain” title layout, the title area still will take some space.

To completely remove the space, you can run the following PnP PowerShell command with the ID of the page.

For more about PnP PowerShell, visit this link.

Set-PnPListItem -List SitePages –Identity <id> -Values @{"PageLayoutType"="Home"}

First connect to the site using the following command

Connect-PnPOnline https://tenant.sharepoint.com/sites/site-where-the-page-exists  

Then find out the ID of the page using the following command. This command assumes that the page is located within “SitePage” library.

Get-PnPListItem -List SitePages

Finally set the page’s layout type to “Home” by running the following command.

Set-PnPListItem -List SitePages –Identity <id> -Values @{"PageLayoutType"="Home"}

Now the title area is totally gone.