Showing posts with label SPFx. Show all posts
Showing posts with label SPFx. Show all posts

December 12, 2019

SPFx: Changing Folder Content Type using PnPjs

Task

Needed to create Folders with custom Content Type in SharePoint document library from my SPFx web part, as there was a need to add some custom fields, such as Description, to the Folder item.

Solution

This one took a few hours to figure out, you need to do it in few steps as you cannot change the content type of a folder using sp.web.folders…update as REST API doesn’t allow ContentTypeId parameter when updating Folder content types, and you will get error:

“The property 'ContentTypeId' does not exist on type 'SP.Folder’. Make sure to only use property names that are defined by the type”

Also if you would use …folder.getItem(), it will fail if folder has special characters.

  1. Create folder as normal Folder
  2. Get list item ID of the folder
  3. Update folder as a list item
let etfn = await sp.web.getList(listUrl).getListItemEntityTypeFullName();

// first create folder
let far: FolderAddResult = await sp.web.folders.add(listUrl + '/' + targetParentFolderName + targetFolderName);

// then get list item ID of the folder
let fData: any = await sp.web.getFolderById(far.data.UniqueId).select('ID').listItemAllFields.get();            

// then get folder as list item
let item: Item = sp.web.getList(listUrl).items.getById(fData['ID']);

await item.update({
    ContentTypeId: 'CUSTOM_FOLDER_CONTENTTYPE',
    PF_FolderDescription: 'Some description...'
}, '*', etfn);

September 4, 2019

SharePoint Online: Hiding "Shared with Us" link in Modern Menu

Problem

For apparently nearly 3 years, people have wanted to hide the “Shared with Us” menu item that is displayed in the Current navigation on modern SharePoint list views. The menu item is injected as 4th item on the menu on sites that are Group based. Item doesn’t exist on traditional Team sites although they would be modern.



Thoughts

There is no way to hide it by modifying the Current navigation, nor by disabling any feature.

Solution

Best I came up with was to inject CSS on all tenant sites, and hide it with simple CSS style. It’s not perfect solution, as the CSS is injected using JavaScript meaning when page is loaded, it will momentarily display the “Shared with us” link before the JavaScript is loaded and CSS is injected.

Good thing, though, is that it does work across all sites with just one deploy and can be easily modified.

Let’s do this

  1. Clone and build my fork (https://github.com/jpalo/react-application-injectcss) of the handy CSS injection SPFx extension made originally by hugoabernier, thanks Hugo!
    - Hugo’s latest version is for SPFx 1.8.0, mine is 1.9.1, so in case you want to use the latest (as of writing) SPFx version, use my fork.
    - My code also assumes the custom.css is in /sites/cdn/Style%20Library/custom.css, but that is easily modified in case you want to use another location.
  2. Before deploying the .sspkg to the tenant, ensure /sites/cds site collection exists, and upload the custom.css from the of the SPFx project to /sites/cdn/Style%20Library/custom.css
  3. Depending on the user base of your tenant, you will need to assign proper Read permissions to the /sites/cdn site collection for all users (and possibly Guests) to be able to read the custom.css file

May 20, 2019

SharePoint: Update List Content Type via REST from SPFx web part

Task

I needed to set ReadOnly property of a SPList Content Type from my SPFx web part. I’m using @pnp/sp library, but it doesn’t support modifying existing Content Types.

Solution

Changing the ReadOnly property of an existing list content type is possible using REST, but I had some troubles finding out correct set of HTTP body and header payloads. Working code can be found below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const spOpts: ISPHttpClientOptions = {
  headers: { 'Accept': 'application/json;odata=verbose', 'X-HTTP-Method': 'MERGE', 'odata-version': '3.0' },
  body: JSON.stringify({
    __metadata: {
      type: 'SP.ContentType'
    },            
    ReadOnly: false
  })
};

let oldCt: ContentType = list.contentTypes.getById('0x01CONTENTTYPEID');

await this.props.context.spHttpClient.post(
  oldCt.toUrlAndQuery(),
  SPHttpClient.configurations.v1,
  spOpts
);


Thoughts

For later reference when investigating similar issues, here’s a collection of error messages depending what Header parameter is missing or invalid.

Without this header propertyYou got error
'Accept': 'application/json;odata=verbose' The property '__metadata' does not exist on type 'SP.ContentType'. Make sure to only use property names that are defined by the type.

Note: This is not required, as odata will be verbose by default unless you have manually set it to, e.g., nometadata. I usually set it to nometadata to improve performance as verbose metadata results of REST calls are not usually required. odata=minimalmetadata is not enough.
'X-HTTP-Method': 'MERGE' The parameter __metadata does not exist in method GetById.
'odata-version': ‘3.0’ Parsing JSON Light feeds or entries in requests without entity set is not supported. Pass in the entity set as a parameter to ODataMessageReader.CreateODataEntryReader or ODataMessageReader.CreateODataFeedReader method.

Note: By default, odata-version will be 4.0, and it doesn’t work here.

September 6, 2018

openssl config failed: error:02001003 when building SharePoint Framework (SPFx) web part

Problem

When building SharePoint Framework (SPFx) web part, you get errors related to openssl, such as

openssl config failed: error:02001003:system library:fopen:No such process

openssl

Also, if you run commands such as “npn -v", you will get same warnings. Depending where you run the commands from, you get the error in PowerShell command line, or classic CMD prompt, or both.

These errors/warnings do not, however, break anything in usual development scenarions, so SharePoint Workbench (local and hosted) work fine.

Solution

Error is due to missing environment variable pointing to OpenSSL config file. You can find the config file from OpenSSL installation folder under bin folder, e.g., "C:\OpenSSL-Win64\bin\openssl.cfg".

For PowerShell (=if you run the commands in Visual Studio Code Terminal), run:

$Env:OPENSSL_CONF = "C:\OpenSSL-Win64\bin\openssl.cfg"

For CMD prompt, run:

SET OPENSSL_CONF=C:\OpenSSL-Win64\bin\openssl.cfg

However

I prefer instead just installing 32 bit version of OpenSSL and not having to worry about these things.

March 22, 2018

Adding divider when programmatically creating Office UI Fabric IContextualMenuItem[]

Question

When declaratively creating Context menu items, you can add divider using

  <li class="ms-ContextualMenu-item ms-ContextualMenu-item--divider"></li>

How to add it when programmatically creating array of IContextualMenuItems?

Solution

Use itemType: ContextualMenuItemType.Divider, like this

const items: IContextualMenuItem[] = [];
items.push( {
    key: "divider1",
    itemType: ContextualMenuItemType.Divider
} );

March 21, 2017

SharePoint: Getting list items with SPFx and CamlQuery

Problem

When fetching SPList items using SPFx and REST combined with CAMLQuery, you need to use spHttpClient.post. However, the following code wasn’t working:

const options: ISPHttpClientOptions = {
	body: `{'query': {
		'__metadata': {'type': 'SP.CamlQuery'},
		'ViewXml': '<View><Query><OrderBy><FieldRef Name="ID"" /></OrderBy></Query></View>'
	}}`
};

return this.context.spHttpClient.post(window.location.protocol + '//' + window.location.hostname + (this.properties.webUrl +
	`/_api/web/lists/GetByTitle('Pages')/items?$select=Title`),
	SPHttpClient.configurations.v1,
	options)
	.then((response: SPHttpClientResponse) => {
		return response.json();
});

But instead it was throwing errors such as:

The property 'query' does not exist on type 'SP.Data.PagesItem'. Make sure to only use property names that are defined by the type.

or

An entry without a type name was found, but no expected type was specified. To allow entries without type information, the expected type must also be specified when the model is specified.

Solution

First of all make sure you use the “odata-version: 3.0”, but more importantly, as you’re using POST, change the REST URL from …/items to …/GetItems.

Final working code:

const options: ISPHttpClientOptions = {
	headers: {'odata-version':'3.0'},
	body: `{'query': {
		'__metadata': {'type': 'SP.CamlQuery'},
		'ViewXml': '<View><Query><OrderBy><FieldRef Name="ID"" /></OrderBy></Query></View>'
	}}`
};

return this.context.spHttpClient.post(window.location.protocol + '//' + window.location.hostname + (this.properties.webUrl +
	`/_api/web/lists/GetByTitle('Pages')/GetItems?$select=Title`),
	SPHttpClient.configurations.v1,
	options)
	.then((response: SPHttpClientResponse) => {
		return response.json();
});

Oh, and no need to use JSON.stringify() when building the ISPHttpClientOptions body query, just use ` around the code and it will already be a string.