EndlessScroll using KendoUI Mobile + Azure Mobile Services + SQL Azure - azure

I have been struggling for the past few days with Endless Scrolling on a mobile listview. I have set up my datasource and listview as the demo suggests. I have not been able to successfully get it to work (or 'press to load more' for that matter) on server-side data. The local data works as expected. I have used many different KendoUI core builds and the results are pretty much the same.
One difference I did notice though, is the type: "odata" part in the demo that refuses to work for me (500 Internal Server Error). I therefore tried a normal "GET" type on the datasource. The "GET" was odata-style (https://myserviceapi.azure-mobile.net/tables/EventTypes?$filter=businessID%20eq%2053) which is supported out of the box on Azure Tables, but endless scrolling did not work. I also tried a normal "GET" of an Azure Mobile Services api method that is basically a RESTful method that returns the same data as the odata table query in SQL Azure. None of the things I have tried work. The following code is what I have and tested with many Kendo UI Core builds.
App JavaScript:
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: 'https://myserviceapi.azure-mobile.net/tables/EventTypes?$filter=businessID%20eq%20' + busID,
dataType: "json"
}
},
serverPaging: true,
pageSize: 12
});
$("#photoHolder").kendoMobileListView({
dataSource: dataSource,
template: "<p>#: eventName #</p>",
endlessScrolling: true,
filterable:{
field: "eventName",
operator: "contains",
ignoreCase: true,
placeholder: "search products..."
}
});
HTML:
<ul id="photoHolder" data-role="listview">
</ul>
Azure JavaScript:
exports.get = function(request, response) {
var mssql = request.service.mssql;
var cnt = request.query.pageSize;
var pnm = request.query.page;
var sql = "SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY zOrder) AS RowNum, * FROM myschema.EventTypes where (businessID = " + request.query.busID + ") and active = 1) AS E " +
"WHERE RowNum BETWEEN ((" + pnm + " - 1) * cnt + 1) AND (" + pnm + " * " + cnt + ") ORDER BY zOrder";
mssql.query(sql, {
success: function(results) {
response.send(200, results);
},
error: function(err) {
console.log(err);
response.send(530, { error: err });
}
});
};

I found the answer to this when I was playing around on my own "pet" app. I just had to make sure that there were enough items in the list to actually give that endless scroll experience. In the Kendo UI forums, they suggest a pageSize of at least 30. {http://docs.telerik.com/kendo-ui/mobile/listview/endless-scrolling}

Related

Delete Documents from CosmosDB based on condition through Query Explorer

What's the query or some other quick way to delete all the documents matching the where condition in a collection?
I want something like DELETE * FROM c WHERE c.DocumentType = 'EULA' but, apparently, it doesn't work.
Note: I'm not looking for any C# implementation for this.
This is a bit old but just had the same requirement and found a concrete example of what #Gaurav Mantri wrote about.
The stored procedure script is here:
https://social.msdn.microsoft.com/Forums/azure/en-US/ec9aa862-0516-47af-badd-dad8a4789dd8/delete-multiple-docdb-documents-within-the-azure-portal?forum=AzureDocumentDB
Go to the Azure portal, grab the script from above and make a new stored procedure in the database->collection you need to delete from.
Then right at the bottom of the stored procedure pane, underneath the script textarea is a place to put in the parameter. In my case I just want to delete all so I used:
SELECT c._self FROM c
I guess yours would be:
SELECT c._self FROM c WHERE c.DocumentType = 'EULA'
Then hit 'Save and Execute'. Viola, some documents get deleted. After I got it working in the Azure Portal I switched over the Azure DocumentDB Studio and got a better view of what was happening. I.e. I could see I was throttled to deleting 18 a time (returned in the results). For some reason I couldn't see this in the Azure Portal.
Anyway, pretty handy even if limited to a certain amount of deletes per execution. Executing the sp is also throttled so you can't just mash the keyboard. I think I would just delete and recreate the Collection unless I had a manageable number of documents to delete (thinking <500).
Props to Mimi Gentz #Microsoft for sharing the script in the link above.
HTH
I want something like DELETE * FROM c WHERE c.DocumentType = 'EULA'
but, apparently, it doesn't work.
Deleting documents this way is not supported. You would need to first select the documents using a SELECT query and then delete them separately. If you want, you can write the code for fetching & deleting in a stored procedure and then execute that stored procedure.
I wrote a script to list all the documents and delete all the documents, it can be modified to delete the selected documents as well.
var docdb = require("documentdb");
var async = require("async");
var config = {
host: "https://xxxx.documents.azure.com:443/",
auth: {
masterKey: "xxxx"
}
};
var client = new docdb.DocumentClient(config.host, config.auth);
var messagesLink = docdb.UriFactory.createDocumentCollectionUri("xxxx", "xxxx");
var listAll = function(callback) {
var spec = {
query: "SELECT * FROM c",
parameters: []
};
client.queryDocuments(messagesLink, spec).toArray((err, results) => {
callback(err, results);
});
};
var deleteAll = function() {
listAll((err, results) => {
if (err) {
console.log(err);
} else {
async.forEach(results, (message, next) => {
client.deleteDocument(message._self, err => {
if (err) {
console.log(err);
next(err);
} else {
next();
}
});
});
}
});
};
var task = process.argv[2];
switch (task) {
case "listAll":
listAll((err, results) => {
if (err) {
console.error(err);
} else {
console.log(results);
}
});
break;
case "deleteAll":
deleteAll();
break;
default:
console.log("Commands:");
console.log("listAll deleteAll");
break;
}
And if you want to do it in C#/Dotnet Core, this project may help: https://github.com/lokijota/CosmosDbDeleteDocumentsByQuery. It's a simple Visual Studio project where you specify a SELECT query, and all the matches will be a) backed up to file; b) deleted, based on a set of flags.
create stored procedure in collection and execute it by passing select query with condition to delete. The major reason to use this stored proc is because of continuation token which will reduce RUs to huge extent and will cost less.
##### Here is the python script which can be used to delete data from Partitioned Cosmos Collection #### This will delete documents Id by Id based on the result set data.
Identify the data that needs to be deleted before below step
res_list = "select id from id_del"
res_id = [{id:x["id"]}
for x in sqlContext.sql(res_list).rdd.collect()]
config = {
"Endpoint" : "Use EndPoint"
"Masterkey" : "UseKey",
"WritingBatchSize" : "5000",
'DOCUMENTDB_DATABASE': 'Database',
'DOCUMENTDB_COLLECTION': 'collection-core'
};
for row in res_id:
# Initialize the Python DocumentDB client
client = document_client.DocumentClient(config['Endpoint'], {'masterKey': config['Masterkey']})
# use a SQL based query to get documents
## Looping thru partition to delete
query = { 'query': "SELECT c.id FROM c where c.id = "+ "'" +row[id]+"'" }
print(query)
options = {}
options['enableCrossPartitionQuery'] = True
options['maxItemCount'] = 1000
result_iterable = client.QueryDocuments('dbs/Database/colls/collection-core', query, options)
results = list(result_iterable)
print('DOCS TO BE DELETED : ' + str(len(results)))
if len(results) > 0 :
for i in range(0,len(results)):
# print(results[i]['id'])
docID = results[i]['id']
print("docID :" + docID)
options = {}
options['enableCrossPartitionQuery'] = True
options['maxItemCount'] = 1000
options['partitionKey'] = docID
client.DeleteDocument('dbs/Database/colls/collection-core/docs/'+docID,options=options)
print ('deleted Partition:' + docID)

Creating a cascading dropdown in sharepoint

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);
}
});
}

How to keep previous data in Leaflet Realtime

I am trying to use Leaflet realtime plugin (https://github.com/perliedman/leaflet-realtime), they mentioned in the documentation that we can keep previous updates by adding start:false in the constructor.
var map = L.map('map'),
realtime = L.realtime({
url: 'https://wanderdrone.appspot.com/',
crossOrigin: true,
type: 'json'
}, {
interval: 3 * 1000, start:false
}).addTo(map);
Anyone have better idea on how to do that ?
plnkr has a good demo:
http://plnkr.co/edit/NmtcUa?p=preview
If you set start: false, automatic updates will be disabled. This means you will have to call the layer's update method yourself, providing any GeoJSON data you want to add or update; you can also remove added features with the remove method. These methods can be used if you want to use something other than server polling.
You can use the following code that I copied from plnkr while changed a little bit, because L.realtime inherit L.geoJson. And L.geoJson have 'layeradd'.
realtime.on('layeradd', function(e) {
var coordPart = function(v, dirs) {
return dirs.charAt(v >= 0 ? 0 : 1) +
(Math.round(Math.abs(v) * 100) / 100).toString();
},
popupContent = function(fId) {
var feature = e.features[fId],
c = feature.geometry.coordinates;
return 'Wander drone at ' +
coordPart(c[1], 'NS') + ', ' + coordPart(c[0], 'EW');
},
bindFeaturePopup = function(fId) {
realtime.getLayer(fId).bindPopup(popupContent(fId));
},
updateFeaturePopup = function(fId) {
realtime.getLayer(fId).getPopup().setContent(popupContent(fId));
};
map.fitBounds(realtime.getBounds(), {maxZoom: 3});
Object.keys(e.enter).forEach(bindFeaturePopup);
Object.keys(e.update).forEach(updateFeaturePopup);
});

SharePoint 2013 - Get SPListItem versions via REST

I have a SharePoint 2013 List with versioning enabled.
I need to to get SPListItem versions list via REST.
I can get SPListItem by that request: http://spbreportportal/Projects/_api/lists/getbytitle('Projects')/Items(1)
But I can't find in documentation and in response how to retrieve all versions of this item.
Is it possible?
It does not seem possible to get versions for a List Item via REST/CSOM APIs, but there are alternative options
Using Versions.aspx application page
The idea is to perform a get request to Versions page: http://<server>/<site>/_layouts/versions.aspx?list={litsID}&ID=<itemID>
function getItemVersions(url,listId,itemId,success)
{
var versionsUrl = url + '/_layouts/versions.aspx?list=' + listId + '&ID=' + itemId;
$.get( versionsUrl, function( data ) {
var versionEntries = parseVersionList(data);
success(versionEntries);
});
}
function parseVersionList(data){
var entries = {};
var versionList = $(data).find('table.ms-settingsframe');
versionList.find('tbody > tr').each(function(i){
if(i > 0 && (i-1) % 2 == 0) {
var verRow = $(this); //get version row
var propsRow = verRow.next(); //get properties row
var versionLabel = verRow.find('td:first').html().trim();
entries[versionLabel] = {};
//extract item properties from propsRow goes here
//...
}
});
return entries;
}
//Usage
var webUrl = _spPageContextInfo.webAbsoluteUrl;
var listId = _spPageContextInfo.pageListId;
var listItemId = 1;
getItemVersions(webUrl,listId,listItemId,function(versionEntries){
console.log(versionEntries);
});
Using Lists SharePoint Web Services
Another option would be to utilize Lists SharePoint Web Services that exposes Lists.GetVersionCollection Method to return version information for the specified field in a SharePoint list
SPServices example:
$().SPServices({
operation: "GetVersionCollection",
async: false,
strlistID: "Projects",
strlistItemID: 1,
strFieldName: "Description",
completefunc: function (xData, Status) {
$(xData.responseText).find("Version").each(function(i) {
console.log("Name: " + $(this).attr("Description") + " Modified: " + $(this).attr("Modified"));
});
}
});
Note: This doesn't seem to work in 2013. I have verified this working in SharePoint Online and it may work in 2016+ but I have not verified the latter.
The situation may have changed since this question was originally posted, but it is now possible to use the REST API to get version history for any list/library item:
https://url/to/site/_api/web/Lists/getbytitle('MyListName')/items(ITEMID)/versions
This will return a series of results for the current version and all past versions, with the item's column values from each version.
As with other REST endpoints, you can use $select, $filter, etc. to further manipulate the results.
In the REST API, you can select the property OData__UIVersionString. It also supports OData__ModerationStatus
Ex:
GET http://site url/_api/web/lists/GetByTitle(‘Test')/items(item id)?$select=OData__UIVersionString,OData__ModerationStatus
More infos : https://msdn.microsoft.com/en-us/library/office/dn292552.aspx
It's not a solution to get all the versions or a specific version, but it's more info on the version.
To add to #Vadim Gremyachev's Excellent answer to use "GetversionCollection": This interface can also be reached using old school SOAP. Unfortunately it only returns one field at the time (so we use a lot of calls ...). The C# snippet is below.
//https://blogs.msdn.microsoft.com/pinch-perfect/2016/06/04/sharepoint-web-services-read-version-history-for-column-changes/
//http://www.indy.gov/eGov/City/DCE/Permits/Signs/_vti_bin/lists.asmx?op=GetVersionCollection
//https://www.codeproject.com/Articles/26338/Using-the-GetListItems-GetVersionCollection-and-Up
string strSite =
string strListGuid =
string strListItemID =
string strFieldName = "Title" // or some other field name
string requestXML = "<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>" +
"<GetVersionCollection xmlns='http://schemas.microsoft.com/sharepoint/soap/'>" +
"<strlistID>"+ strListGuid + "</strlistID><strlistItemID>" + strListItemID + "</strlistItemID>" +
"<strFieldName>"+ strFieldName +"</strFieldName>" +
"</GetVersionCollection>" +
"</soap:Body>" +
"</soap:Envelope>";
object xmlRequestObj = Activator.CreateInstance(Type.GetTypeFromProgID("Microsoft.XMLHTTP"));
MSXML2.XMLHTTP xmlRequest = (MSXML2.XMLHTTP)xmlRequestObj;
xmlRequest.open("Get", strSite + "/_vti_bin/Lists.asmx", false, null, null);
xmlRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlRequest.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/GetVersionCollection");
xmlRequest.send(requestXML);
string responseText = xmlRequest.responseText;
To add more information reagrding on how to obtain all version history from a SharePoint list:
//Get ID of the Dossier in SP list
strID = items(i - 1).getAttribute("ows_ID")
Debug.Print strID
//Get all Versions of the ID in SP list as a XML
URL1: https://path to site collection/_vti_bin/owssvr.dll?Cmd=Display&List={LIstID}&XMLDATA=TRUE&Query=*&IncludeVersions=TRUE
XDoc3.Load (URL1 & "&FilterField1=ID&FilterOp1=eq&FilterValue1=" & strID)
Set Item = XDoc3.SelectNodes("//rs:data/*")
Set temp3 = XDoc3.SelectNodes("//rs:data/*")

CRM 2011 - setting a default value with JScript

We have CRM 2011 on premise. The Contact entity was customized to use a lookup to a custom entity Country instead of just a text field. When creating a new Contact we would like the country field to be set to Canada by default. I have the following function that does that:
function SetDefaultCountryCode(countryFieldId) {
var _canadaId = "{FC167B4D-1C3B-E111-8904-F2EA3FE25706}";
var countryControl = Xrm.Page.getAttribute(countryFieldId);
// only attempt the code if the control exists on the form
if (countryControl != null) {
var currentCountry = countryControl.getValue();
// if country is not specified, then set it to the default one (Canada)
if (currentCountry == null) {
var defaultCountry = new Object();
defaultCountry.entityType = "cga_country";
defaultCountry.id = _canadaId;
defaultCountry.name = "Canada";
var countryLookupValue = new Array();
countryLookupValue[0] = defaultCountry;
countryControl.setValue(countryLookupValue);
}
}
}
On the form OnLoad I invoke the function like that:
// set Country fields to Canada if not set
SetDefaultCountryCode('cga_address1country');
We have two servers - DEV and TEST. This JScript works fine in DEV. When I run it in TEST it does not work because the Canada in TEST has different id (GUID) - when I create it manually. I was hoping I could export the Country entity values from DEV and import them in TEST preserving their GUIDs. Unfortunately this did not work. I export the data to Excel file and it has the GUIDs of the countries. I also delete any existing Country records in TEST before importing. When I try to import it the import succeeds but does not create any records. If I add a new row in the excel file without specifing a Guid it will import it. It seems to me the import functionality was not meant to preserve the GUIDs of the records. But this also means my script will not work because it depends on the GUIDs.
I have two questions here:
Is it possible to export / import entity data preserving the GUIDs ?
If I cannot have the same GUIDs in DEV and TEST how I can make the JScript to work properly?
Thank you in advance for any help / feedback.
It's very bad practice to hard code your GUIDs and you discovered the problems of it.
As you stated above, we cannot have the same GUIDs but we have the same name. So, we have to query the name of the country using JScript and jQuery to retrieve the GUID.
In order to retireve information from client-side (or Entity Form):
We will use/consume REST Endpoint (testing in browser).
Upload jQuery lib.
Upload Json2 lib.
Use the AJAX function from the jQuery library.
Define your entity, columns and criteria.
Lets, look for querying REST Endpoint.
http://yourHostName/yourOrg/XRMServices/2011/OrganizationData.svc/new_CountrytSet?$select=new_Name,new_CountryId&$filter=new_Name eq 'Canada'
Take this URL, subsitute your actual values and paste it into your browser, you'll find that the response is returned in XML format. If there is any error, please ensure that the Entity name and its attribute are case senisitve.
After seeing your your results, we are going to call this URL using an AJAX call.
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
datatype: "json",
url: 'http://yourHostName/yourOrg/XRMServices/2011/OrganizationData.svc/new_CountrytSet?$select=new_Name,new_CountryId&$filter=new_Name eq 'Canada'',
beforeSend: function (XMLHttpRequest) {
//Specifying this header ensures that the results will be returned as JSON.
XMLHttpRequest.setRequestHeader("Accept", "application/json");
},
success: function (data) {
if (data.d && data.d.results) {
//var _canadaId = "{FC167B4D-1C3B-E111-8904-F2EA3FE25706}"; no longer be used
var _canadaId = data.d.results[0].ContactId;
// now we have the GUID of Canada, now I can continue my process
}
},
error: function (XmlHttpRequest) {
alert("Error : " + XmlHttpRequest.status + ": " + XmlHttpRequest.statusText + ": " + JSON.parse(XmlHttpRequest.responseText).error.message.value);
}
});
But before you copy the code to your form, you have to download the jQuery lib from here
Then upload it as a Web resource, add this web resource to the Form load libs.
Here is the complete code to be put in the form load event handler:
var context = GetGlobalContext();
// retireve the invoice record id (Opened Form)
var invoiceId = context.getQueryStringParameters().id;
var customerId;
//Retrieve the server url, which differs on-premise from on-line and
//shouldn't be hard-coded.
// this will return something like http://yourHostName/yourOrg
var serverUrl = context.getServerUrl();
//The XRM OData end-point
var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc";
var odataUri = serverUrl + ODATA_ENDPOINT;
function SetDefaultCountryCode(countryFieldId, odataUri) {
odataUri = odataUri + '/ContactSet?$select=ContactId,FullName&$filter=FullName eq \'Ahmed Shawki\'';
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
datatype: "json",
url: odataUri,
beforeSend: function (XMLHttpRequest) {
//Specifying this header ensures that the results will be returned as JSON.
XMLHttpRequest.setRequestHeader("Accept", "application/json");
},
success: function (data) {
if (data.d && data.d.results) {
//var _canadaId = "{FC167B4D-1C3B-E111-8904-F2EA3FE25706}"; no longer be used
var _canadaId = data.d.results[0].ContactId;
var countryControl = Xrm.Page.getAttribute(countryFieldId);
// only attempt the code if the control exists on the form
if (countryControl != null) {
var currentCountry = countryControl.getValue();
// if country is not specified, then set it to the default one (Canada)
if (currentCountry == null) {
var defaultCountry = new Object();
defaultCountry.entityType = "cga_country";
defaultCountry.id = _canadaId;
defaultCountry.name = "Canada";
var countryLookupValue = new Array();
countryLookupValue[0] = defaultCountry;
countryControl.setValue(countryLookupValue);
}
}
}
},
error: function (XmlHttpRequest) {
alert("Error : " + XmlHttpRequest.status + ": " + XmlHttpRequest.statusText + ": " + JSON.parse(XmlHttpRequest.responseText).error.message.value);
}
});
}
One more thing, don't forget to check "Pass execution context as first parameter" box on the form properties.
EDIT: Beside adding the jQuery library into the form load event handler, add the Json2 lib as a web resource.
For more information about the REST Endpoint.
It is indeed possible to export and import records along with their guids, just not natively. You'd have to build an app that would export the data for you, then create identical records through the CRM API in the target environment. You just have to clear out fields that aren't valid for create (createdon, statecode, etc.) and just specify the same Guid. CRM will then create the record with that Guid.
The old 4.0 Configuration Data Tool does this. I can't recall if it works against a 2011 org, but it could be a starting point.

Resources