We have
a SharePoint 2013 document library
a custom content type added to the library, based on standard "Folder" content type; a new "DisplayName" text field added to the content type
a few folders of that custom content type were created in the document library
I try to make a JavaScript control to visualize folder structure from the library. But I can't get the custom "DisplayName" field value
this.clientContext = SP.ClientContext.get_current();
var web = this.clientContext.get_web();
this.clientContext.load(web);
this.clientContext.executeQueryAsync(function(sender, args) {
for (var i = 0; i < this.topLevelFoldersUrl.length; i++) {
var contextParams = {};
contextParams.folderUrl = web.get_serverRelativeUrl() + "/" + this.topLevelFoldersUrl[i];
// folder
contextParams.topLevelFolder = web.getFolderByServerRelativeUrl(contextParams.folderUrl);
this.clientContext.load(contextParams.topLevelFolder, 'Include(DisplayName)');
// folder list item
contextParams.folderListItem = contextParams.topLevelFolder.get_listItemAllFields();
this.clientContext.load(contextParams.folderListItem);
// subfolders
contextParams.folderCollection = contextParams.topLevelFolder.get_folders();
this.clientContext.load(contextParams.folderCollection);
this.clientContext.executeQueryAsync(
function (sender, args) {
var folderName = contextParams.topLevelFolder.get_name();
// EXCEPTION goes here: "property has not been initialized"
var folderDisplayName = contextParams.folderListItem.get_item("DisplayName");
// visualization code...
},
this.onQueryFailed
);
}
}, this.onQueryFailed);
Is there a special technique to get folder custom fields? I've googled all the code samples to get list items and their custom fields, but the samples don't work in my case.
"DisplayName" seems to be a reserved identifier in SharePoint 2013 JSOM. After changing field's name to "ShownName" my code worked:
this.clientContext = SP.ClientContext.get_current();
var web = this.clientContext.get_web();
this.clientContext.load(web);
this.clientContext.executeQueryAsync(function (sender, args) {
for (var i = 0; i < this.topLevelFoldersUrl.length; i++) {
var contextParams = {};
contextParams.folderUrl = web.get_serverRelativeUrl() + "/" + this.topLevelFoldersUrl[i];
contextParams.topLevelFolder = web.getFolderByServerRelativeUrl(contextParams.folderUrl);
this.clientContext.load(contextParams.topLevelFolder);
contextParams.folderListItem = contextParams.topLevelFolder.get_listItemAllFields();
this.clientContext.load(contextParams.folderListItem, 'ShownName');
contextParams.folderCollection = contextParams.topLevelFolder.get_folders();
this.clientContext.load(contextParams.folderCollection);
this.clientContext.executeQueryAsync(
function(sender, args) {
var folderName = folder.get_name();
var folderDisplayName = folderItem.get_item("ShownName");
// visualization code...
},
this.onQueryFailed
);
}
}, this.onQueryFailed);
Related
So far I can retrieve the list based on a string I pass and even the column names but I can't figure out how to get the values of a specific column. Here is what I have so far.
function GetFieldList()
{
var listname = document.getElementById("ListName").value;
var ctx = SP.ClientContext.get_current();
this.web = ctx.get_web();
ctx.load(this.web);
this.list = web.get_lists().getByTitle(listname);
ctx.load(this.list);
this.fields = this.list.get_fields();
ctx.load(this.fields);
ctx.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}
Btw I'm using SharePoint 2010.
I think your code is not full the client Context must run async method to load the values
If you want correct way to get the values from SharePoint read the this documentation :
https://msdn.microsoft.com/en-us/library/office/hh185007(v=office.14).aspx
or you can use another library such as rest api or spservice .
Anyway the get_fields() return the fields list name not values.
As you said SP.ClientContext.get_current(); is an Javascript Object, so first of all you need to check if the property that you want to know if is null or empty, exists.
var ctx = SP.ClientContext.get_current();
isPropertyEmptyOrNull = ctx.hasOwnProperty('myProperty') && (prop.myProperty === null or prop.myProperty === '' or prop.myProperty === undefined)
You found more details abour hasOwnProperty here
Refer below code. This shows how to retrieve items from SharePoint list.
function GetItems() {
var context = new SP.ClientContext.get_current();
var list = context.get_web().get_lists().getByTitle('ListName');
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("");
collItems = list.getItems(camlQuery);
context.load(collItems);
context.executeQueryAsync(GetItemsSuccess, GetItemsFail);
}
function GetItemsSuccess() {
var listItemEnumerator = collItems.getEnumerator();
if (collItems.get_count() > 0) {
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
/*
retrieve specific fields (e.g. Title, FirstName...)
Here 'Title' and 'FirstName' will be the internal name of the field you want to retrieve
*/
var title = oListItem.get_item('Title');
var firstName = oListItem.get_item('FirstName');
}
}
}
function GetItemsFail(sender, args) {
// Error handler code
}
I am on a double learning curve with SharePoint 2013 development and JavaScript.
Please refer to below.
function GetListFields(listname, viewname, ResultCallBackFunction)
{
var clientContext = new SP.ClientContext.get_current();
var web = clientContext.get_web();
var list = web.get_lists().getByTitle(listname);
if (viewname == "")
{
var view = list.get_views().getByTitle(viewname);
var listFields = view.get_viewFields();
}
else
{
this.listFields = list.get_fields().getByInternalNameOrTitle("Title");
}
clientContext.load(this.listFields);
clientContext.executeQueryAsync(onListFieldsQuerySucceeded, onListFieldsQueryFailed);
function onListFieldsQuerySucceeded()
{
console.log(listFields.get_fields().getByInternalNameOrTitle("Title").get_internalName());
var fldArray = new Array();
var fieldEnumerator = listFields.getEnumerator();
while (fieldEnumerator.moveNext())
{
var oField = fieldEnumerator.get_current();
fldArray.push(oField);
}
ResultCallBackFunction(fldArray);
}
function onListFieldsQueryFailed()
{
alert("Something went wrong. The End is Nigh.");
}
}
The intent is to call GetListFields to return an array with the list's fieldnames. This returns an error "Unable to get property 'get_fields' of undefined or null reference" at the line "console.log....". Please note that this is for my debugging.
If I change the code for function GetListFields as follows:
var clientContext = new SP.ClientContext.get_current();
var web = clientContext.get_web();
var list = web.get_lists().getByTitle(listname);
if (viewname == "")
viewname = "All Items";
var view = list.get_views().getByTitle(viewname);
this.listFields = view.get_viewFields();
I DO get a result but this contains a field named 'LinkTitle' which I do not have in my list because I have renamed this. What am I missing?
Further to the above, I got an error when using
var listFields = ...
which fixed by doing
this.listFields = ...
but do not understand the difference.
Thanks for any help or pointers.
I took a moment to test your code in my Sharepoint 2013 environment.
I made some changes and now it works.
You can see the resulting script bellow.
Here is some important information about the field names in the result array.
The names of the fields in the view returned by Sharepoint are the internal names and not the title of the field.
This is the reason why you get LinkTitle instead of the real title of your field.
When you create a field in the Sharepoint interface, Sharepoint create a title for the field and also an internal name based on the title.
For example, if I create a field named « my test field », Sharepoint will say the title of the field is « my test field » and the internal name is « my_x0020_test_x0020_field ».
<script>
function GetListFields(listname, viewname, ResultCallBackFunction)
{
var clientContext = new SP.ClientContext.get_current();
var web = clientContext.get_web();
var list = web.get_lists().getByTitle(listname);
var listFields;
var view;
var defaultViewName = 'All Items';
if (viewname === "")
{
viewname = defaultViewName;
}
view = list.get_views().getByTitle(viewname);
listFields = view.get_viewFields();
clientContext.load(listFields);
clientContext.executeQueryAsync(onListFieldsQuerySucceeded, onListFieldsQueryFailed);
function onListFieldsQuerySucceeded()
{
var fldArray = new Array();
var fieldEnumerator = listFields.getEnumerator();
while (fieldEnumerator.moveNext())
{
var oField = fieldEnumerator.get_current();
fldArray.push(oField);
}
ResultCallBackFunction(fldArray);
}
function onListFieldsQueryFailed()
{
alert("Something went wrong. The End is Nigh.");
}
}
function MyCallBack(fieldArray) {
for (var x=0;x<fieldArray.length;x++) {
console.log(fieldArray[x]);
}
}
</script>
<a id="callGetListFields" href="#" onclick="GetListFields('MyListName','MyViewName', MyCallBack);">Call function GetListFields</a>
Hope this help!
I am developing a project with the Kendo UI Framework, using more specically the Scheduler widget and I have the current issue:
On my database I have two tables one called Events and the other one called TypeOfEvents. Each type of event has got a specific color, a specific title plus defined values for startHour and endHour fields.
When the pop-up window to create an event is called, I can choose on two kendoMultiSelect the correspondent user and the type of event.
I can also choose the startDate and endDate. The default behavior of a Scheduler widget has got two datetimepickers also, however, I don't want that option on my pop-up window because the events will have defined hours that an user can't change.
My idea would be the following one:
Once I click save after choosing a specific event on my MultiSelectList, there would be some way to concatenate the startHour and endHour values I have defined in my database with the startDate and endHour field that I choosed on the pop-up window.
Right now, all my events startDate/endDate fields are saved on my DB with this format: 2015-03-01 00:00:00.000
I would like to substitute all those zeros with the values I defined in advance in my startHour/endHour fields of my TypeOfEvents table.
Here's my current CREATE script:
create: function (createEvent) {
var typeOfEventID = $("#selectEvent").val();
var usernameID = $("#selectUsername").val();
var dataStartTemp = $("#dataStart").val();
var dataEndTemp = $("#dataEnd").val();
var note = $("#note").val();
var res = $("#customViewScheduler").data("kendoScheduler");
var res1 = res.resources[1].dataSource.data();
var dataStart = convertToJSONDate(dataStartTemp);
var dataEnd = convertToJSONDate(dataEndTemp);
var changeSet = [];
var id = 0;
usernameID.forEach(function (userID) {
typeOfEventID.forEach(function (eventID) {
var titletemp = $.grep(res1, function (elem) {
if (elem.TypeOfEventID == eventID) {
return true;
}
})
if (titletemp.length > 0) {
note = titletemp[0].title;
}
var entityChange = {};
entityChange.Id = id;
entityChange.Entity = {
'__type': "Events:#BlahBlahWeb",
'UsernameID': userID,
'TypeOfEventID': eventID,
'startDate': dataStart,
'endDate': dataEnd,
'Title': note
};
entityChange.Operation = 2;
changeSet.push(entityChange);
id++
})
})
var changesetPayload = JSON.stringify({
"changeSet": changeSet
});
//Create jQuery ajax request
var Params = {}
Params.type = "POST";
Params.url = "./../Services/BlahBlahWeb-BlahDomainService.svc/JSON/SubmitChanges";
Params.dataType = "json";
Params.data = changesetPayload;
Params.contentType = "application/json";
Params.error = function (httpRequest, textStatus, errorThrown) {
//SendErrorByEmail(errorThrown, httpRequest.responseText)
}
Params.success = function (data) {
//createEvent.success(data);
var scheduler = $("#customViewScheduler").data("kendoScheduler");
var elem = tratanewelem(data.SubmitChangesResult[0].Entity)
scheduler.dataSource.read();
}
//Make the ajax request
$.ajax(Params);
},
Any idea of how can I accomplish that?
I need to print only the column that has been created by me.
function retrieveFieldsOfListView(listTitle,viewName){
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle(listTitle);
var listFields = list.get_fields();
context.load(listFields);
context.executeQueryAsync(printFieldNames,onError);
function printFieldNames() {
var e = listFields.getEnumerator();
while (e.moveNext()) {
var fieldName = e.get_title();
console.log(fieldName);
}
}
function onError(sender,args)
{
console.log(args.get_message());
}
}
But this code is printing all the pre-defined fields along with my field. I don't want the pre-defined fields like 'modified,created,etc'. I want only the coding changes. UI changes are not upto me.
How to determine whether field is system or user-defined
Probably the most reliable way to determine whether field is system or user-defined is to utilize SourceId property of a Field. For system fields it's value is set to http://schemas.microsoft.com/sharepoint/v3
Note: SP.Field object does not expose SourceId property, but it could be extracted from SP.Field.schemaXml property as demonstrated below:
function getListFields(listTitle,success,error){
var context = SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle(listTitle);
var fields = list.get_fields();
context.load(fields);
context.executeQueryAsync(
function(){
success(fields);
},
error);
}
//Usage
getListFields('Pages',
function(fields) {
//get only user defined fields
var userDefinedFields = fields.get_data().filter(function(f){
var schema = f.get_schemaXml();
if (schema.indexOf('SourceID="http://schemas.microsoft.com/sharepoint/v3"') === -1){
return f;
}
});
//print user defined fields title
userDefinedFields.forEach(function(f){
console.log(f.get_title());
});
},
function(sender,args)
{
console.log(args.get_message());
});
Like a said SourceId property is not available for Field object, the below example demonstrates a different approach for getting field properties
function getListFields(listTitle,success,error){
var context = SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle(listTitle);
var fields = list.get_fields();
context.load(fields,'Include(SchemaXml)');
context.executeQueryAsync(
function(){
var result = [];
fields.get_data().forEach(function(f){
var schema = f.get_schemaXml();
result.push(schemaXml2Json(schema));
});
success(result);
},
error);
}
function schemaXml2Json(schemaXml)
{
var jsonObject = {};
var schemaXmlDoc = $.parseXML(schemaXml);
$(schemaXmlDoc).find('Field').each(function() {
$.each(this.attributes, function(i, attr){
jsonObject[attr.name] = attr.value;
});
});
return jsonObject;
}
Then you could use SourceId property:
getListFields('Pages',
function(fields) {
//get only user defined fields
var userDefinedFields = fields.filter(function(f){
if (f.SourceID !== "http://schemas.microsoft.com/sharepoint/v3"){
return f;
}
});
//print user defined fields title
userDefinedFields.forEach(function(f){
console.log(f.DisplayName);
});
},
function(sender,args)
{
console.log(args.get_message());
});
I am trying to access list data from site and several levels of sub-sites in one page.
I have searched the web and tried to apply few solutions found here on Stack Overflow but to no avail.
This is the simplified code I am using.
// parent-level
var clientCtx = new SP.ClientContext.get_current();
getListItems(listName, camlView,fields, clientCtx);
//sub-site level
clientCtx = new SP.ClientContext(subSiteUrl);
getListItems((listName, camlView,fields, clientCtx);
This code works for the parent site but not for sub-sites.
The client context passed inside getListItems function for sub-site contains the right URL and seems to instantiate all objects: web, list, listItems, etc., but fails to enumerate list items with the "Unknown error". The same thing happens for both sub-sites i have tried.
function getListItems(listName, queryString, fields, clientCtx)
{
web = clientCtx.get_web();
var list = web.get_lists().getByTitle(listName);
var query = new SP.CamlQuery();
query.set_viewXml(queryString);
var listItems = list.getItems(query);
query.set_viewXml(queryString);
var listItems = list.getItems(query);
var fieldList = fields.join(",");
clientCtx.load(listItems);
clientCtx.executeQueryAsync(function () {
var resultItems = [];
var listItemEnumerator = listItems.getEnumerator();
while (listItemEnumerator.moveNext()) {
var listItem = listItemEnumerator.get_current();
var fieldValues = listItem.get_fieldValues();
var resultItem = {};
for (var i = 0; i < fields.length; i++) {
resultItem[fields[i]] = listItem.get_item(fields[i]);
}
resultItems.push(resultItem);
}
return resultItems;
}
...
}