I have a column which type is SPGroup in a list. I want to get items via SharePoint REST API, and I only need the items which SPGroup contains the current user. So what's the URL? Thank you for your advice!
You can use the $expand parameter in your REST query to include related entities of data in your query, but since the SharePoint REST service implements the OData protocol, the $filter method can only be invoked on the top level item, thus making it impossible to use on an expanded field.
Depending on how many items your list contains, I'd suggest that you either try to filter it on something other than the current user, or fetch everything and filters the result in your code instead.
A REST query would look something like this:
http://sp/_api/web/lists/getbytitle('MyList')/items?$select=Id,Title,Members/Id&$expand=Members where Members is the SPGroup to be expanded.
In each item that is returned, you will get something like
<content type="application/xml">
<m:properties>
<d:Id m:type="Edm.Int32">60</d:Id>
</m:properties>
</content>
with the Id value of the member. From this, you should be able to write some custom code to filter out only the items that contain the current logged in user.
You can still do what you're looking to do with good old fashioned SOAP with less of headache. I use this method to get Tasks assigned to a user's account or a group they're a member of.
function getAssignedToMe(){
var viewFields = '<ViewFields><FieldRef Name="ID" /><FieldRef Name="Title" /><FieldRef Name="Created" /><FieldRef Name="FileRef" />'
+'<FieldRef Name="AssignedTo" /><FieldRef Name="Status" /></ViewFields>';
// filter by AssignedTo is current user ID or assigned to the current user's group;
var camlQuery = '' +
'<Query>' +
'<Where>' +
'<And>' +
'<Or>' +
'<Membership Type="CurrentUserGroups"><FieldRef Name="AssignedTo"/></Membership>' +
'<Eq><FieldRef Name="AssignedTo"/><Value Type="Integer"><UserID/></Value></Eq>' +
'</Or>' +
'<And>' +
'<Neq><FieldRef Name="Status"/><Value Type="Text">Completed</Value></Neq>' +
'<Geq><FieldRef Name="Created" /><Value Type="DateTime"><Today OffsetDays="-60" /></Value></Geq>' +
'</And>' +
'</And>' +
'</Where>' +
'<OrderBy><FieldRef Name="Created" Ascending="TRUE"/></OrderBy>' +
'</Query>';
getListItems('/mysite', 'Tasks', viewFields, camlQuery, callback, 50);
// transform the returned XML to JSON
function callback(xmlDoc){
var data = [];
$(xmlDoc).find('*').filter(function () {
return this.nodeName.toLowerCase() == 'z:row';
}).each(function (i, el) {
// do something with the data
var id = parseInt($(el).attr('ows_ID'));
data.push({
Id: id
});
/* ... */
});
};
};
function getListItems(siteUrl, listName, viewFields, query, callback, rowLimit) {
if (rowLimit === void 0) { rowLimit = 25; }
var packet = '<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' +
'<soap:Body>' +
'<GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">' +
'<listName>' + listName + '</listName>' +
'<query>' + query + '</query>' +
'<viewFields>' + viewFields + '</viewFields>' +
'<rowLimit>' + rowLimit + '</rowLimit>' +
'</GetListItems>' +
'</soap:Body>' +
'</soap:Envelope>';
var $jqXhr = $.ajax({
url: siteUrl + '/_vti_bin/lists.asmx',
type: 'POST',
dataType: 'xml',
data: packet,
headers: {
"SOAPAction": "http://schemas.microsoft.com/sharepoint/soap/GetListItems",
"Content-Type": "text/xml; charset=utf-8"
}
}).done(function (xmlDoc, status, error) {
callback(xmlDoc);
}).fail(function (jqXhr, status, error) {
callback(null, status + ': ' + error);
});
};
Related
I've looked at as many examples as possible and tried different combinations to what looks like a simple problem - I want to check if an O365 modern list item exists based on a URL (Hyperlink) field. My CAML is as below but returns no results - the list item URL field is a full url and the url variable is a text field containing the full URL also. I've also tried Eq and Contains.
"<View>
<Query>
<Where>
<BeginsWith>
<FieldRef Name='URL'/><Value Type='URL'>" + url + "
</Value>
</BeginsWith>
</Where>
</Query>
</View>"
Thanks,
John.
Full code
var OnePlaceURL = TenantBaseURL + "/sites/" + "oneplacesolutions";
var clientSiteRelativePath = "/sites/" + alias; //Even though the list has the full URL the CAML query has to give a relative path - oddity of SP URL field
var registerList = "DMS Clients";
try
{
using (var context = new ClientContext(OnePlaceURL))
{
context.Credentials = SPOCredentials;
Web web = context.Web;
context.Load(context.Web, w => w.Url);
context.ExecuteQueryRetry();
AddLogMessage(MessageLevel.Info, "AddSiteToOnePlaceSolutionsCentralRegister - loaded web" + context.Web.Url);
var targetList = context.Web.Lists.GetByTitle(registerList);
context.Load(targetList);
context.Load(targetList.Fields);
context.Load(targetList.GetItemById(1));
context.ExecuteQueryRetry();
AddLogMessage(MessageLevel.Info, "AddSiteToOnePlaceSolutionsCentralRegister - loaded list and fields, itemCount:" + targetList.ItemCount);
CamlQuery query = new CamlQuery();
query.ViewXml = "<View><Query><Where><Eq><FieldRef Name='URL'/><Value Type='URL'>" + url + "</Value></Eq></Where></Query></View>";
AddLogMessage(MessageLevel.Info, "ViewXML:" + query.ViewXml);
var itemList = targetList.GetItems(query);
context.Load(itemList); // loading all the fields
context.ExecuteQueryRetry();
As I test,if we add external web site url in list,we could use caml like this:
<View><Query><Where><Eq><FieldRef Name='link' /><Value Type='URL'>http://www.google.com</Value></Eq></Where></Query></View>
If we add some internal site url in list,we need to create the caml like this:
<View><Query><Where><Eq><FieldRef Name='link' /><Value Type='URL'>/sites/dev/subsite</Value></Eq></Where></Query></View>
We do not need to add our tenant url.
More reference:
https://social.msdn.microsoft.com/Forums/office/en-US/2dc874ed-3a3d-4f26-b932-afb25c0142c8/caml-query-on-url-field?forum=sharepointdevelopmentlegacy
Updated:
<script type="text/javascript">
SP.SOD.executeOrDelayUntilScriptLoaded(ValidateForm,"sp.js");
function ValidateForm(){
var clientContext = new SP.ClientContext();
var list = clientContext.get_web().get_lists().getByTitle("test3");
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml(
"<View><Query> <Where><Eq><FieldRef Name='link' /><Value Type='Url'>/sites/dev/subsite</Value></Eq></Where></Query></View>");
var items = list.getItems(camlQuery);
clientContext.load(items);
clientContext.executeQueryAsync(Function.createDelegate(this,onSuccess),Function.createDelegate(this, onFail));
function onSuccess(){
var ListEnumerator = items.getEnumerator();
while (ListEnumerator.moveNext()) {
var currentItem = ListEnumerator.get_current();
var link= currentItem.get_item("link");
console.log(link);
}
}
function onFail(sender,args){
console.log(args.get_message());
}
}
</script>
How do I go about creating a cascading drop-down within a list in Office 365 SharePoint?
For instance, if you have a country drop-down and you select United States, you get the 50 states listed. Then if you select Maryland, you get the cities within that state.
You can use Info Path form which make very easy for cascading and if you do not want to use Infopath you have to use Jquery CSOM or REST API in the form where you want to use cascading.
Please go through below link for more information :
http://www.markrackley.net/2014/05/20/cascading-drop-down-lists-in-sharepoint-office-365-using-rest/
https://spservices.codeplex.com/wikipage?title=%24%28%29.SPServices.SPCascadeDropdowns
You can use REST API to implement Cascading Drop down in SharePoint. Step by step article link: Cascading drop down in SharePoint using REST API
//Function to filter the values of Drink Types
function loadDrinkTypes(selectedDrink) {
var drinkTypeListName = "Drink Type";
var drinkTypeListURL = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('" + drinkTypeListName + "')/items?$select=Title,Drink/Title,Drink/Id&$expand=Drink&$filter=Drink/Title eq '" + selectedDrink + "'";
getReqData(drinkTypeListURL, function (data) {
var items = data.d.results;
if (items.length > 0) {
var optionsAsString = '<option value=""></option>';
for (var i = 0; i < items.length; i++) {
optionsAsString += "<option value='" + items[i].Title + "'>" + items[i].Title + "</option>";
}
$('select[title="Drink Type"]').html(optionsAsString);
}
},
function (data) {
//alert("Some error occurred in getting Drink Types");
});
}
//JQuery AJAX to access REST API JSON data
function getReqData(reqUrl, success, failure) {
$.ajax({
url: reqUrl,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
success(data);
},
error: function (data) {
failure(data);
}
});
}
I'm getting this to work if I choose a specific list to add the action to. Is there an easy way to enable this custom action on all document libraries in the whole sitecollection?
Code sample:
function createUserCustomActionList() {
var cmd = "<CommandUIExtension><CommandUIDefinitions><CommandUIDefinition Location=\"Ribbon.Documents.Manage.Controls._children\">" +
"<Button Id=\"DiaryAction.Button\" TemplateAlias=\"o1\" Command=\"DiaryCommand\" CommandType=\"General\" LabelText=\"Dela flera\" Image32by32=\"https://eolusvind.sharepoint.com/sites/intranet/_layouts/15/1033/Images/formatmap32x32.png?rev=23\"" +
" Image32by32Top=\"-271\" Image32by32Left=\"-109\" />" +
"</CommandUIDefinition></CommandUIDefinitions><CommandUIHandlers>" +
"<CommandUIHandler Command =\"DiaryCommand\" CommandAction=\"javascript:alert('Hej');\" EnabledScript=\"javascript:SP.ListOperation.Selection.getSelectedItems().length > 1;\" />" +
"</CommandUIHandlers></CommandUIExtension>";
var ctx = new SP.ClientContext.get_current();
var list = ctx.get_web().get_lists().getByTitle('Dokument');
var uca = list.get_userCustomActions();
var oUserCustomAction = uca.add();
oUserCustomAction.set_location('CommandUI.Ribbon.ListView');
oUserCustomAction.set_commandUIExtension(cmd);
oUserCustomAction.set_sequence(100);
oUserCustomAction.set_title('Dela flera');
oUserCustomAction.update();
ctx.load(list, 'Title' ,'UserCustomActions');
ctx.executeQueryAsync(function () {
alert('Custom action created for ' + list.get_title())
}, function (sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
});
}
I would suggest the following approach for registering custom button in Documents libraries across site collection:
use RegistrationType set to 2(ContentType) and RegistrationId set to 0x0101 (for Document content type) to register custom action via content type
use site scope user custom action to apply changes across all site
collection
Example
var cmd = "<CommandUIExtension>" +
"<CommandUIDefinitions>" +
"<CommandUIDefinition Location=\"Ribbon.Documents.Manage.Controls._children\">" +
"<Button Id=\"ClickAction.Button\" TemplateAlias=\"o1\" Command=\"ViewCustomPropertiesCommand\" CommandType=\"General\" LabelText=\"View Custom Properties\" Image32by32=\"/_layouts/15/1033/Images/formatmap32x32.png?rev=23\" Image32by32Top=\"-1\" Image32by32Left=\"-171\" />" +
"</CommandUIDefinition></CommandUIDefinitions><CommandUIHandlers>" +
"<CommandUIHandler Command =\"ViewCustomPropertiesCommand\" CommandAction=\"javascript:console.log('View Custom Properties');\" EnabledScript=\"javascript:SP.ListOperation.Selection.getSelectedItems().length > 0;\" />" +
"</CommandUIHandlers>" +
"</CommandUIExtension>";
var ctx = new SP.ClientContext.get_current();
var customAction = ctx.get_site().get_userCustomActions().add(); //1. apply via site scope user custom action
customAction.set_location('CommandUI.Ribbon.ListView');
customAction.set_commandUIExtension(cmd);
customAction.set_sequence(112);
customAction.set_registrationType(2); //2.set to ContentType
customAction.set_registrationId("0x0101"); //2.set Document content type
//customAction.set_title('Document custom button');
customAction.update();
ctx.executeQueryAsync(function () {
console.log('Button has been registered');
}, function (sender, args) {
console.log('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
});
I have created a SharePoint Hosted App(Javascript Object Model) that creates lists on the host web.
I need to put some javascript into new and edit forms in order to create the cascaded drop down effect on 2 lookup fields.
Here is how I create the lists and the fields for it:
// Create a new list on host web
var createList = function (listTitle, onSuccess, onFieldsReady) {
var listCreationInfo = new SP.ListCreationInformation();
listCreationInfo.set_title(listTitle);
listCreationInfo.set_templateType(SP.ListTemplateType.genericList);
var lists = hostWeb.get_lists();
var newList = lists.add(listCreationInfo);
currentContext.load(newList);
currentContext.executeQueryAsync(onSuccess(newList, onFieldsReady), onListCreationFail);
}
// Create a new field on a list
var createField = function (list, fieldType, fieldName, fieldDisplayName, fieldRequired, onSuccess) {
var fields = list.get_fields();
var fieldXml = "<Field Type='" + fieldType + "' Required='" + fieldRequired + "' DisplayName='" + fieldDisplayName + "' Name='" + fieldName + "'></Field>";
var createdField = fields.addFieldAsXml(fieldXml, true, SP.AddFieldOptions.addFieldInternalNameHint | SP.AddFieldOptions.addFieldToDefaultView);
currentContext.load(createdField);
currentContext.executeQueryAsync(onSuccess, onProvisionFieldFail);
}
Can you please give me some advise?
Regards,
Marian
You should consider ditching the idea of using NewForm and Editform.aspx. Just write your own form and use the JSOM or WebApi to add/edit list items.
Sample code for adding item to a list:
jQuery.ajax({
url: "http://<site url>/_api/web/lists/GetByTitle('Test')",
type: "POST",
data: JSON.stringify({ '__metadata': { 'type': 'SP.List' }, 'Title': 'New title' }),
headers: {
"X-HTTP-Method":"MERGE",
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"content-length": <length of post body>,
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"IF-MATCH": "*"
},
success: doSuccess,
error: doError
});
Reference: http://msdn.microsoft.com/en-us/library/office/jj164022(v=office.15).aspx
Try this.
var clientContext = new SP.ClientContext.get_current();
var list = clientContext.get_web().get_lists().getByTitle('ListName');
if(list) {
var fldCollection = list.get_fields();
var fieldLookup1 = clientContext.castTo(
fldCollection.addFieldAsXml('<Field Name="FieldName1" Type="Lookup" DisplayName="My Lookup Field 1" List="Lists/MyLookupList" ShowField="Title" />', true, SP.AddFieldOptions.addToDefaultContentType),
SP.FieldLookup
);
fieldLookup1.set_title("MyLookupField1");
fieldLookup1.set_description("Lookup field 1 description");
fieldLookup1.update();
list.update();
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
}
Please let me know if it works ;)
Have a nice day!
I am using Calendar List for some room bookings everything is fine but only struggling with Overlapp or double booking of a room on the same day and time.
I am trying to figure out by passing the data entered by the user in the form to CAML Query and check whether this entry is existing or not
If the entry is already existing Cancel Booking or if not proceed.
For example: if From: 10:00 AM To 11:00 AM is already booked.
the overlapping scenarios may be:
if user enters in the form From: 10:00 AM To 10:30 AM
From: 9:00 AM To 11:00 AM..
I am assuming The date is same and only time matters for me.
How to get the CAML query if the date is same and only time varies and check the user input From & To time with in the range exists in already Booked items.
using query something below but not validating for all scenarios
<Where><And><Geq><FieldRef Name='EventDate' /><Value IncludeTimeValue='TRUE' Type='DateTime'>" + strSPEventDateFormat + "</Value></Geq><And><Leq><FieldRef Name='EndDate' /><Value IncludeTimeValue='TRUE' Type='DateTime'>" + strSPEndDateFormat + "</Value></Leq><Eq><FieldRef Name='Room' /><Value Type='Lookup'>" + strCheckRoomAvail + "</Value></Eq></And></And></Where>
Please help me on this
Thanks in advance
Write CAML to get all rooms conflicting with the START Time. Start time must not be between start and end times selected by user
AND
write CAML to get all rooms conflicting with the END Time. END time must not be between start and end times selected by user
If the room selected by user is not in the above results returned by CAML then you can go ahead and book the room.
q.Query = "<Where><And><Geq><FieldRef Name=""StartTime"" /><Value IncludeTimeValue=""TRUE"" Type=""DateTime"">" + _
Utilities.SPUtility.CreateISO8601DateTimeFromSystemDateTime(startTime) + _
"</Value></Geq><Leq><FieldRef Name=""StartTime"" /><Value IncludeTimeValue=""TRUE"" Type=""DateTime"">" + _
Utilities.SPUtility.CreateISO8601DateTimeFromSystemDateTime(endTime) + _
"</Value></Leq></And></Where><OrderBy><FieldRef Name=""ID"" Ascending=""True"" /></OrderBy>"
q1.Query = "<Where><And><Geq><FieldRef Name=""EndTime"" /><Value IncludeTimeValue=""TRUE"" Type=""DateTime"">" + _
Utilities.SPUtility.CreateISO8601DateTimeFromSystemDateTime(startTime) + _
"</Value></Geq><Leq><FieldRef Name=""EndTime"" /><Value IncludeTimeValue=""TRUE"" Type=""DateTime"">" + _
Utilities.SPUtility.CreateISO8601DateTimeFromSystemDateTime(endTime) + _
"</Value></Leq></And></Where><OrderBy><FieldRef Name=""ID"" Ascending=""True"" /></OrderBy>"
This thread is quite old, but i just came across the same problem. So here is my working solution, may it help some one.
Note: For time relatet search-caml you need the IncludeTimeValue='TRUE' parameter of the
/**
* {Boolean} formModeEdit To determine if this form is an New or Edit form
*/
function checkDoubleBooking(formModeEdit, listId, currentItemId, startDate, endDate) {
var results = [];
var liHtml = "";
var checkOverlappingQueryArray = [];
//Construct caml query
checkOverlappingQueryArray.push("<And>");
checkOverlappingQueryArray.push("<Leq>");
checkOverlappingQueryArray.push("<FieldRef Name='EventDate' /><Value Type='DateTime' IncludeTimeValue='TRUE'>" + moment(endDate).format() + "</Value>");
checkOverlappingQueryArray.push("</Leq>");
checkOverlappingQueryArray.push("<Geq>");
checkOverlappingQueryArray.push("<FieldRef Name='EndDate' /><Value Type='DateTime' IncludeTimeValue='TRUE'>" + moment(startDate).format() + "</Value>");
checkOverlappingQueryArray.push("</Geq>");
checkOverlappingQueryArray.push("</And>");
if (formModeEdit) {
checkOverlappingQueryArray.unshift("<And>");
checkOverlappingQueryArray.push("<Neq>");
checkOverlappingQueryArray.push("<FieldRef Name='ID' /><Value Type='Integer'>" + currentItemId + "</Value>");
checkOverlappingQueryArray.push("</Neq>");
checkOverlappingQueryArray.push("</And>");
}
checkOverlappingQueryArray.unshift("<Where>");
checkOverlappingQueryArray.push("</Where>");
checkOverlappingQueryArray.unshift("<Query>");
checkOverlappingQueryArray.push("</Query>");
jQuery().SPServices({
operation: "GetListItems",
async: false,
listName: listId,
CAMLViewFields: "<ViewFields>" +
"<FieldRef Name='ID' />" +
"<FieldRef Name='Title' />" +
"<FieldRef Name='EventDate' />" +
"<FieldRef Name='EndDate' />" +
"<FieldRef Name='PeoplePickerField1' />" +
"</ViewFields>",
CAMLQuery: checkOverlappingQuery,
CAMLQueryOptions: "<QueryOptions>" +
"<ExpandUserField>True</ExpandUserField>" + //Expand People Picker values
"</QueryOptions>",
CAMLRowLimit: 10, // Override the default view rowlimit
completefunc: function(xData, Status) {
$(xData.responseXML).SPFilterNode("z:row").each(function() {
countOverlappingEvents++;
results.push({
title: $(this).attr("ows_Title"),
eventDate: $(this).attr("ows_EventDate"),
endDate: $(this).attr("ows_EndDate"),
peoplePickerField1: userToJsonObject($(this).attr("ows_PeoplePickerField1"))
});
}
}
});
return results;
}
function userToJsonObject(userObj) {
if (userObj.length === 0) {
return null;
} else {
var thisUser = userObj.split(";#");
var thisUserExpanded = thisUser[1].split(",#")
if (thisUserExpanded.length == 1) {
return {
userId: thisUser[0],
userName: thisUser[1]
}
} else {
return {
userId: thisUser[0],
userName: thisUserExpanded[0].replace(/(,,)/g, ","),
loginName: thisUserExpanded[1].replace(/(,,)/g, ","),
email: thisUserExpanded[2].replace(/(,,)/g, ","),
sipAddress: thisUserExpanded[3].replace(/(,,)/g, ","),
title: thisUserExpanded[4].replace(/(,,)/g, ",")
}
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment-with-locales.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.SPServices/2014.02/jquery.SPServices-2014.02.min.js"></script>