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!
Related
I came across an scenario where I have to clone my custom entity.
Then I have started doing using with JavaScript by placing a custom duplicate button in the ribbon which triggers my JavaScript.
I used the following code:
function duplicateOrder(primaryControl){
var formContext = primaryControl;
var city = formContext.getAttribute('new_city').getValue();
var country = formContext.getAttribute('new_country').getValue();
var state = formContext.getAttribute('new_state').getValue();
var postal_code = formContext.getAttribute('new_zipcodepostalcode').getValue();
// var formItem = formContext.ui.formSelector.items.get();
// alert(`the form item value is ${formItem}`);
formContext.data.entity.save('saveandnew');
sleep(3000);
var city1 = formContext.getAttribute('new_city').getValue();
var country1 = formContext.getAttribute('new_country').getValue();
var state1 = formContext.getAttribute('new_state').getValue();
var postal_code1 = formContext.getAttribute('new_zipcodepostalcode').getValue();
alert(`${city1},${country1},${state1},${postal_code1}`);
if(city1==null){
formContext.getAttribute('new_city').setValue(city);
}
if(country1==null){
formContext.getAttribute('new_country').setValue(country);
}
if(state1==null){
formContext.getAttribute('new_state').setValue(state);
}
if(postal_code1==null){
formContext.getAttribute('new_zipcodepostalcode').setValue(postal_code);
}
alert(`${city},${country},${state},${postal_code}`);
}
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
I tried using the save and new logic to open a new entity form.
The New entity form opens but the field values do not get copied in the new how.
Please help me how to solve this.
Thanks and advance!
You need to call Xrm.Navigation.openForm with your cloneid record.
// Load newly copy record
var entityFormOptions = {};
entityFormOptions["entityName"] = "stdseries";
entityFormOptions["entityId"] = cloneId;
// Open the form.
Xrm.Navigation.openForm(entityFormOptions).then(
function (success) {
formContext.data.refresh();
},
function (error) {
});
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 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());
});
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);
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;
}
...
}