I investigated the source code (the most credible source!!) of XsltListViewWebPart in dotPeek and it turns out there can be two reasons for this behavior:
- Check that you have Contributor permissions on the web (in particular, "AddAndCustomizePages" permission is needed)
- If you have, I'm afraid you should contact MSFT and tell them that the web application that you're running your tenant on has wrong value set for "Scriptable Web Parts" setting: https://technet.microsoft.com/en-us/library/hh272821(v=office.14).aspx
Also, if you hit the former case, please check out Workarounds section below.
If you're interested of how I came up with such results, then here's the story:
In a galaxy far, far away...
XsltListViewWebPart has 5 custom web part properties:
private static List<CustomWebPartProperty> customXlvProps = new List<CustomWebPartProperty>()
{
new CustomWebPartProperty()
{
PropertyName = "ServerRender",
PropertyDescription = "ServerRenderDescription",
Catetory = "Miscellaneous",
RequiresDesignerPermission = false,
IsCSROnly = false,
V14Hidden = true
},
new CustomWebPartProperty()
{
PropertyName = "DisableViewSelectorMenu",
PropertyDescription = "DisableViewSelectorMenu",
Catetory = "Miscellaneous",
RequiresDesignerPermission = false,
IsCSROnly = true
},
new CustomWebPartProperty()
{
PropertyName = "DisableSaveAsNewViewButton",
PropertyDescription = "DisableSaveAsNewViewButton",
Catetory = "Miscellaneous",
RequiresDesignerPermission = false,
IsCSROnly = true
},
new CustomWebPartProperty()
{
PropertyName = "InplaceSearchEnabled",
PropertyDescription = "InplaceSearchEnabled",
Catetory = "Miscellaneous",
RequiresDesignerPermission = false,
IsCSROnly = true
},
new CustomWebPartProperty()
{
PropertyName = "JSLink",
PropertyDescription = "JSLinkDescription",
Catetory = "Miscellaneous",
RequiresDesignerPermission = true,
propertyType = SPClientWebPartElement.ClientWebPartPropertyType.String,
V14Hidden = true
}
};
As you see, each property has some parameters, in particular we're interested in parameters that can lead to webpart not being displayed. There're three of those:
- RequiresDesignerPermission
- IsCSROnly
- V14Hidden
On your screenshot, however, I can see that all properties are shown except of JSLink. From this I can infer that IsCSROnly and V14Hidden are not what we need, because ServerRender has V14Hidden=true - and it is shown, and other properties have IsCSROnly=true and they're shown.
This leaves us with RequiresDesignerPermission.
But I don't quite trust SharePoint, and can't rely on nice property names, as they can be misleading. Thus I double-checked the code. Just in case :)
So the customXlvProps
field is only used in one place, here:
List<SPEditorPartProperty> IWebPartToolPaneCustomProperties.GetToolPaneCustomProperties(bool excludeSharedProperties)
{
return new CustomWebpartPropertyHelper((WebPart) this, XsltListViewWebPart.customXlvProps, this.ClientRender)
.GetToolPaneCustomProperties(excludeSharedProperties);
}
CustomWebpartPropertyHelper is a short class. Constructor doesn't do anything intelligent, just assigns parameters to local class fields.
Now, the GetToolPaneCustomProperties contains the following code:
List<SPEditorPartProperty> list1 = new List<SPEditorPartProperty>();
foreach (CustomWebPartProperty customWebPartProperty in this._customWebPartProps)
{
if ((!customWebPartProperty.IsCSROnly || this._bClientRender) && (!customWebPartProperty.V14Hidden || SPUtility.IsCompatibilityLevel15Up))
{
// skipped for clarity...
// if property type is string, the following code is run:
editorPartProperty = (SPEditorPartProperty)
new SPEditorPartStringProperty(
customWebPartProperty.PropertyName,
@string,
customWebPartProperty.RequiresDesignerPermission);
// skipped for clarity...
editorPartProperty.Description = WebPartPageResource.GetString(customWebPartProperty.PropertyDescription);
editorPartProperty.Category = WebPartPageResource.GetString(customWebPartProperty.Catetory);
editorPartProperty.SyncChanges += new SPEditorPartProperty.SyncChangesHandler(this.ToolPane_OnSyncChanges);
editorPartProperty.ApplyChanges += new SPEditorPartProperty.ApplyChangesHandler(this.ToolPane_OnApply);
list1.Add(editorPartProperty);
}
}
return list1;
So I can infer that JSLink property is actually added to this particular list, and RequiresDesignerPermission is checked on some later stage.
Let's follow it and peek into the SPEditorPartStringProperty
class.
This class is a very small thing that is nothing interesting by itself, but it derives from SPEditorPartProperty
, which has the RequiresDesignerPermission property!
After some more digging I found, that this property is used only in one place in Microsoft.SharePoint assembly: in CreateChildControls method of the CustomPropertyToolPart class. This method contains the following code:
foreach (ExtendedPropertyInfo propInfo in this.m_propsCol.Values)
{
SPEditorPartProperty propertySheetProperty = PropertySheetProperty.CreatePropertySheetProperty(this.TargetWebPart, propInfo, true, (string) null, (SPEditorPartChoicePropertyItem[]) null);
propertySheetProperty.SyncChanges += new SPEditorPartProperty.SyncChangesHandler(this.OnSyncChanges);
propertySheetProperty.ApplyChanges += new SPEditorPartProperty.ApplyChangesHandler(this.OnApply);
if (SPWebPartManager.CanUserScript(this.Web) || !propertySheetProperty.RequiresDesignerPermission)
list.Add(propertySheetProperty);
}
So as you can see, the property is NOT added if it has RequiresDesignerPermission==true AND SPWebPartManager.CanUserScript(this.Web)==true
.
Ok, let's see what CanUserScript does:
internal static bool CanUserScript(SPWeb web)
{
return web.AllowContributorsToEditScriptableParts ||
((SPSecurableObject) web).DoesUserHavePermissions(SPBasePermissions.AddAndCustomizePages);
}
Aha! So here is the first reason: check for AddAndCustomizePages permission.
And finally, let's see what is this AllowContributorsToEditScriptableParts:
internal bool AllowContributorsToEditScriptableParts
{
get
{
return this.Site.WebApplication.AllowContributorsToEditScriptableParts;
}
}
Alright, so it gets the value from WebApplication properties. Based on my investigation, there isn't any possibility to access or change this property for a tenant. Of course, O365 code is different from On-Premise code, so I cannot say this with 100 percent certainty, but tenant administrator portal is not that big, and I intently went through all the settings in there, and there isn't anything similar there except of the Custom Script setting, which only applies for self-service and personal sites, and which you reported that you already tried.
Workarounds
If you have the permissions, then you'll have to deal with MSFT to resolve the issue, and unfortunately this often is just a waste of time. So if you need a solution for this problem, please try workarounds that I explain below.
Use SharePoint Designer for changing JSLink
Open your list in SharePoint Designer, then click to the view, and in the page editor you should be able to find the JSLink tag. Change its contents and that's it.
Use JSOM or CSOM for changing JSLink
JSOM code is something like this:
var wpId = // please put GUID of your webpart here.
// you should be able to find this GUID by inspecting the page
var jsLinkString = // please put the path to your js file here, same as you
// would put it into JSLink webpart property
var context = SP.ClientContext.get_current();
var page = context.get_web().getFileByServerRelativeUrl(_spPageContextInfo.serverRequestPath);
var wpm = page.getLimitedWebPartManager(SP.WebParts.PersonalizationScope.shared);
var webpartDef = wpm.get_webParts().getById(new SP.Guid(wpId));
var webpart = webpartDef.get_webPart();
var properties = webpart.get_properties();
context.load(properties);
context.executeQueryAsync(function () {
properties.set_item("JSLink", jsLinkString);
webpartDef.saveWebPartChanges();
context.executeQueryAsync(function () {
alert('done');
},
function() {
alert('error on step 2');
});
},
function() {
alert('error');
});
Also similar code can be used for CSOM or PowerShell (also via CSOM, of course). And consider setting JSLink of Field or ContentType, as the code for this will be much simpler.
Use any other method to deploy script to the page
CSR customizations can be of course deployed to page using any other method, as they actually don't depend on JSLink anyhow. If you didn't know about this, I recommend this article:
(Disclaimer: I'm the author of this article)
So actually you can deploy CSR customizations using even ScriptEditorWebPart or CEWP, although in this case Minimal Download Strategy may not work. Best way probably would be to use ScriptLink custom action, although it means that script will be deployed everywhere throughout the site of course. Custom action can be added using No-code Sandbox Solution, JSOM or CSOM.
Use Cisar
Cisar is a tool I wrote for creating CSR customizations fast. It is a Live Edit for CSR: so you write code, and instantly see how it your list form or list view transforms according to what you write. The tool is opensource and available on GitHub (technically it is a Chrome extension).
If you write CSR customizations a lot, as do I, it may be of help. And it attaches files to webparts on page via JSLink automatically, using JSOM, so you don't need to care about opening that.