In the CRM 2011 SDK, there is a Visual Studio 2010 Project called JavaScriptRESTRetrieveMultiple.
There is also a managed solution that was generated from the Visual Studio 2010 Project called JavaScriptRESTRetrieveMultiple.
I imported the managed solution into CRM and tested it. I can confirm that it works.
The managed solution, once inside CRM, contains four files.
- JavaScriptRESTRetrieveMultiple.htm
- JavaScriptRESTRetrieveMultiple.css
- Json2.js
- SDK.REST.js
The JavaScriptRESTRetrieveMultiple.htm is the main page that contains paths to other resources.
- /Scripts/Json2.js
- /Scripts/SDK.REST.js
- /Styles/JavaScriptRESTRetrieveMultiple.css
I took note that the managed solution uses “/Sample_” for its root path or parent location.
Then all of the files that are part of the managed solution are placed in the respective sub-paths based off the parent location.
- /Sample_/Scripts/Json2.js
- /Sample_/Scripts/SDK.REST.js
- /Sample_/Styles/JavaScriptRESTRetrieveMultiple.css
However this is not important because the code in the visual studio project starts at the current location and uses relative path info so the actual path to the current location is not relevant. The project only needs to know what comes beneath the current path such as the /Scripts or /Styles directories.
After testing it and verifying that it works, I removed the managed solution from CRM.
Next I manually created a solution in CRM called JavaScriptRESTRetrieveMultiple and performed the following steps:
- 1. I created a new html web resource named JavaScriptRESTRetrieveMultiple.htm and imported the JavaScriptRESTRetrieveMultiple.htm file into it directly from the SDK
- 2. I created a new css web resource named JavaScriptRESTRetrieveMultiple.css and imported the JavaScriptRESTRetrieveMultiple.css file into it directly from the SDK
- 3. I created a new jscript web resource named Json2.js and imported the Json2.js file into it directly from the SDK
- 4. I created a new jscript web resource named SDK.REST.js and imported the SDK.REST.js file into it directly from the SDK
When I proceeded to test it, it did not work. No errors were generated, but no records were returned. It seems as if the page does not have its functionality.
When I looked at the path of the web resource objects in the customization area, I saw that they sit in the root instead of being in a /Sample_ location.
So I updated the JavaScriptRESTRetrieveMultiple.htm file so that the absolute path does not refer to any sub directories since the three other files sit at the same level as the JavaScriptRESTRetrieveMultiple.htm file does.
I then saved and published them and re-tested but still experience the same result as if the page has no functionality.
My objective is to determine if something is failing, breaking, or causing the four files I am importing to be changed or corrupted when I manually import them OR to determine if there is something additional is happening when the managed solution is imported, that is not included in the Visual Studio Project. Clearly, something is different and I need to know what is different.
In the screen results comparison below, look and see how the CRM 2011 SDK Visual Studio 2010 Project called JavaScriptRESTRetrieveMultiple (\SDK\SampleCode\JS\RESTEndpoint.sln) is different than the CRM 2011 SDK Managed Solution ((\SDK\SampleCode\JS\RESTEndpoint.zip) in the same SDK that is supposedly “the same”.
What is Microsoft doing differently between the two?
The Visual Studio Code is supposed to be identical to what’s in the managed solution.
Microsoft provided both side by side.
I just don’t understand why the visual studio project won’t work when it’s brought inside CRM.
Using Visual Studio Project Code | Using Managed Solution |
If I compare the code in the managed solution to the code I manually imported, it is identical as shown below
Code on the Managed Solution Objects as seen inside CRM JavaScriptRESTRetrieveMultiple.htm <html lang="en-us"><head></head><body> <!--<snippetJavaScriptRESTRetrieveMultipleHTML>--> <title>REST Endpoint Paging with JScript</title> <meta http-equiv="X-UA-Compatible" content="IE=8"> <script src="../ClientGlobalContext.js.aspx" type="text/javascript"></script> <script src="Scripts/SDK.REST.js" type="text/javascript"></script> <script src="Scripts/json2.js" type="text/javascript"></script> <link href="Styles/JavaScriptRESTRetrieveMultiple.css" rel="stylesheet" type="text/css"> <script type="text/javascript"> var accountsGrid; //The tbody element of the accountsTable var numberOfAccountsToRetrieve; // The select control with options for the number of records to retrieve. var btnRetrieveAccounts; //The button to retrieve accounts var accountsRetrieved; //The span displaying the number of account records retrieved. var successMessage; // The message displayed when records are returned. var totalAccountCount = 0; document.onreadystatechange = function () { if (document.readyState == "complete") { btnRetrieveAccounts = document.getElementById("btnRetrieveAccounts"); accountsGrid = document.getElementById("accountsGrid"); numberOfAccountsToRetrieve = document.getElementById("numberOfAccountsToRetrieve"); accountsRetrieved = document.getElementById("accountsRetrieved"); successMessage = document.getElementById("successMessage"); btnRetrieveAccounts.onclick = retrieveAccounts; btnRetrieveAccounts.click(); } } function retrieveAccounts() { ///<summary> /// Retrieves accounts by passing a filter to the SDK.RestEndpointPaging.RetrieveRecords function ///</summary> clearaccountsGrid(); var number = parseInt(numberOfAccountsToRetrieve.options[numberOfAccountsToRetrieve.selectedIndex].value, 10); var options = "$select=Name,Telephone1&$top=" + number; //The retrieveAccountsCallBack function is passed through as the successCallBack. SDK.REST.retrieveMultipleRecords("Account", options, retrieveAccountsCallBack, function (error) { alert(error.message); }, accountsRetrieveComplete); } function retrieveAccountsCallBack(retrievedAccounts) { ///<summary> /// This function is passed through the request and is iterated for each page of data /// This function appends rows to the accountsGrid. ///</summary> totalAccountCount = totalAccountCount + retrievedAccounts.length; for (var i = 0; i < retrievedAccounts.length; i++) { var account = retrievedAccounts[i]; var row = document.createElement("tr"); var nameCell = document.createElement("td"); setElementText(nameCell, account.Name); row.appendChild(nameCell); var mainPhoneCell = document.createElement("td"); setElementText(mainPhoneCell, (account.Telephone1 == null) ? "" : account.Telephone1); mainPhoneCell.className = "rightColumn"; row.appendChild(mainPhoneCell); accountsGrid.appendChild(row); } } function accountsRetrieveComplete() { ///<summary> /// This function is called after all the records have been returned to update the actual total number of records. ///</summary> accountsRetrieved.innerText = totalAccountCount; successMessage.style.display = "block"; } function clearaccountsGrid() { ///<summary> /// This function initializes the totalAccountCount and clears all the rows from the accountsGrid /// in preparation for adding a new set of rows. ///</summary> successMessage.style.display = "none"; totalAccountCount = 0; for (var i = accountsGrid.rows.length - 1; i >= 0; i--) { accountsGrid.deleteRow(i); } } function setElementText(element, text) { ///<summary> /// This function mitigates the fact that IE uses innerText and other browsers use textContent. ///</summary> if (typeof (element.innerText) != "undefined") { element.innerText = text; } else { element.textContent = text; } } </script> <table id="tableHeadings" summary="This table provides the headings for the list of accounts displayed in a grid."> <thead> <tr> <th class="leftColumn"> Account Name </th> <th class="rightColumn"> Main Phone </th> </tr> </thead> </table> <div id="tableContainer"> <table id="accountsTable" rules="groups" summary="This table displays the accounts retrieved."> <tbody id="accountsGrid"> </tbody></table> </div> <div id="controlsContainer"> <div> <span>Maximum Number of Accounts to Retrieve: <select id="numberOfAccountsToRetrieve"> <option selected="selected" value="100">100</option> <option value="300">300</option> <option value="600">600</option> <option value="900">900</option> </select> <button id="btnRetrieveAccounts"> Retrieve Accounts</button> </span> </div> <div id="successMessage" style="display: none;"> Total Number of Accounts Retrieved : <span id="accountsRetrieved"></span> </div> </div> </body></html> | Code on the Manually Imported Objects JavaScriptRESTRetrieveMultiple.htm <html lang="en-us"><head></head><body> <!--<snippetJavaScriptRESTRetrieveMultipleHTML>--> <title>REST Endpoint Paging with JScript</title> <meta http-equiv="X-UA-Compatible" content="IE=8"> <script src="../ClientGlobalContext.js.aspx" type="text/javascript"></script> <script src="SDK.REST.js" type="text/javascript"></script> <script src="json2.js" type="text/javascript"></script> <link href="JavaScriptRESTRetrieveMultiple.css" rel="stylesheet" type="text/css"> <script type="text/javascript"> var accountsGrid; //The tbody element of the accountsTable var numberOfAccountsToRetrieve; // The select control with options for the number of records to retrieve. var btnRetrieveAccounts; //The button to retrieve accounts var accountsRetrieved; //The span displaying the number of account records retrieved. var successMessage; // The message displayed when records are returned. var totalAccountCount = 0; document.onreadystatechange = function () { if (document.readyState == "complete") { btnRetrieveAccounts = document.getElementById("btnRetrieveAccounts"); accountsGrid = document.getElementById("accountsGrid"); numberOfAccountsToRetrieve = document.getElementById("numberOfAccountsToRetrieve"); accountsRetrieved = document.getElementById("accountsRetrieved"); successMessage = document.getElementById("successMessage"); btnRetrieveAccounts.onclick = retrieveAccounts; btnRetrieveAccounts.click(); } } function retrieveAccounts() { ///<summary> /// Retrieves accounts by passing a filter to the SDK.RestEndpointPaging.RetrieveRecords function ///</summary> clearaccountsGrid(); var number = parseInt(numberOfAccountsToRetrieve.options[numberOfAccountsToRetrieve.selectedIndex].value, 10); var options = "$select=Name,Telephone1&$top=" + number; //The retrieveAccountsCallBack function is passed through as the successCallBack. SDK.REST.retrieveMultipleRecords("Account", options, retrieveAccountsCallBack, function (error) { alert(error.message); }, accountsRetrieveComplete); } function retrieveAccountsCallBack(retrievedAccounts) { ///<summary> /// This function is passed through the request and is iterated for each page of data /// This function appends rows to the accountsGrid. ///</summary> totalAccountCount = totalAccountCount + retrievedAccounts.length; for (var i = 0; i < retrievedAccounts.length; i++) { var account = retrievedAccounts[i]; var row = document.createElement("tr"); var nameCell = document.createElement("td"); setElementText(nameCell, account.Name); row.appendChild(nameCell); var mainPhoneCell = document.createElement("td");
setElementText(mainPhoneCell, (account.Telephone1 == null) ? "" : account.Telephone1); mainPhoneCell.className = "rightColumn"; row.appendChild(mainPhoneCell); accountsGrid.appendChild(row); } } function accountsRetrieveComplete() { ///<summary> /// This function is called after all the records have been returned to update the actual total number of records. ///</summary> accountsRetrieved.innerText = totalAccountCount; successMessage.style.display = "block"; } function clearaccountsGrid() { ///<summary> /// This function initializes the totalAccountCount and clears all the rows from the accountsGrid /// in preparation for adding a new set of rows. ///</summary> successMessage.style.display = "none"; totalAccountCount = 0; for (var i = accountsGrid.rows.length - 1; i >= 0; i--) { accountsGrid.deleteRow(i); } } function setElementText(element, text) { ///<summary> /// This function mitigates the fact that IE uses innerText and other browsers use textContent. ///</summary> if (typeof (element.innerText) != "undefined") { element.innerText = text; } else { element.textContent = text; } } </script> <table id="tableHeadings" summary="This table provides the headings for the list of accounts displayed in a grid."> <thead> <tr> <th class="leftColumn"> Account Name </th> <th class="rightColumn"> Main Phone </th> </tr> </thead> </table> <div id="tableContainer"> <table id="accountsTable" rules="groups" summary="This table displays the accounts retrieved."> <tbody id="accountsGrid"> </tbody></table> </div> <div id="controlsContainer"> <div> <span>Maximum Number of Accounts to Retrieve: <select id="numberOfAccountsToRetrieve"> <option selected="selected" value="100">100</option> <option value="300">300</option> <option value="600">600</option> <option value="900">900</option> </select> <button id="btnRetrieveAccounts"> Retrieve Accounts</button> </span> </div> <div id="successMessage" style="display: none;"> Total Number of Accounts Retrieved : <span id="accountsRetrieved"></span> </div> </div> </body></html> |
Code on the Managed Solution Objects JavaScriptRESTRetrieveMultiple.css
/*<snippetJavaScriptRESTRetrieveMultipleCSS>*/ html, body { font-family: Segoe UI; background-color:White; } #tableContainer { overflow: scroll; max-height: 300px; width: 600px; position: absolute; top: 35px; border: 1px solid black; } #tableHeadings { width: 602px; position: absolute; top: 20; height: 25px; border: 1px solid black; border-bottom: 0px none; background-color:ButtonFace; }
#accountsTable { overflow: scroll; width: 583px; table-layout: fixed; border-collapse: collapse; } #controlsContainer { position: absolute; top: 350px; } tr { border-bottom: 1px solid black; } td { padding-left: 5px; }
.rightColumn { border-left: 1px solid black; } .leftColumn { width:285px; } /*</snippetJavaScriptRESTRetrieveMultipleCSS>*/
| Code on the Manually Imported Objects JavaScriptRESTRetrieveMultiple.css
/*<snippetJavaScriptRESTRetrieveMultipleCSS>*/ html, body { font-family: Segoe UI; background-color:White; } #tableContainer { overflow: scroll; max-height: 300px; width: 600px; position: absolute; top: 35px; border: 1px solid black; } #tableHeadings { width: 602px; position: absolute; top: 20; height: 25px; border: 1px solid black; border-bottom: 0px none; background-color:ButtonFace; }
#accountsTable { overflow: scroll; width: 583px; table-layout: fixed; border-collapse: collapse; } #controlsContainer { position: absolute; top: 350px; } tr { border-bottom: 1px solid black; } td { padding-left: 5px; }
.rightColumn { border-left: 1px solid black; } .leftColumn { width:285px; } /*</snippetJavaScriptRESTRetrieveMultipleCSS>*/
|
Code on the Managed Solution Objects Json2.js
if (!this.JSON) { this.JSON = {}; } (function () { function f(n) { return n < 10 ? '0' + n : n; } if (typeof Date.prototype.toJSON !== 'function') { Date.prototype.toJSON = function (key) { return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z' : null; }; String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) { return this.valueOf(); }; } var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"': '\\"', '\\': '\\\\' }, rep; function quote(string) { escapable.lastIndex = 0; return escapable.test(string) ? '"' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }) + '"' : '"' + string + '"'; } function str(key, holder) { var i, k, v, length, mind = gap, partial, value = holder[key]; if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); } if (typeof rep === 'function') { value = rep.call(holder, key, value); } switch (typeof value) { case 'string': return quote(value); case 'number': return isFinite(value) ? String(value) : 'null'; case 'boolean': case 'null': return String(value); case 'object': if (!value) { return 'null'; } gap += indent; partial = []; if (Object.prototype.toString.apply(value) === '[object Array]') { length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || 'null'; } v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; gap = mind; return v; } if (rep && typeof rep === 'object') { length = rep.length; for (i = 0; i < length; i += 1) { k = rep[i]; if (typeof k === 'string') { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } else { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; gap = mind; return v; } } if (typeof JSON.stringify !== 'function') { JSON.stringify = function (value, replacer, space) { var i; gap = ''; indent = ''; if (typeof space === 'number') { for (i = 0; i < space; i += 1) { indent += ' '; } } else if (typeof space === 'string') { indent = space; } rep = replacer; if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) { throw new Error('JSON.stringify'); } return str('', { '': value }); }; } if (typeof JSON.parse !== 'function') { JSON.parse = function (text, reviver) { var j; function walk(holder, key) { var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } text = String(text); cx.lastIndex = 0; if (cx.test(text)) { text = text.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { j = eval('(' + text + ')'); return typeof reviver === 'function' ? walk({ '': j }, '') : j; } throw new SyntaxError('JSON.parse'); }; } } ());
| Code on the Manually Imported Objects Json2.js
if (!this.JSON) { this.JSON = {}; } (function () { function f(n) { return n < 10 ? '0' + n : n; } if (typeof Date.prototype.toJSON !== 'function') { Date.prototype.toJSON = function (key) { return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z' : null; }; String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) { return this.valueOf(); }; } var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"': '\\"', '\\': '\\\\' }, rep; function quote(string) { escapable.lastIndex = 0; return escapable.test(string) ? '"' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }) + '"' : '"' + string + '"'; } function str(key, holder) { var i, k, v, length, mind = gap, partial, value = holder[key]; if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); } if (typeof rep === 'function') { value = rep.call(holder, key, value); } switch (typeof value) { case 'string': return quote(value); case 'number': return isFinite(value) ? String(value) : 'null'; case 'boolean': case 'null': return String(value); case 'object': if (!value) { return 'null'; } gap += indent; partial = []; if (Object.prototype.toString.apply(value) === '[object Array]') { length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || 'null'; } v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; gap = mind; return v; } if (rep && typeof rep === 'object') { length = rep.length; for (i = 0; i < length; i += 1) { k = rep[i]; if (typeof k === 'string') { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } else { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; gap = mind; return v; } } if (typeof JSON.stringify !== 'function') { JSON.stringify = function (value, replacer, space) { var i; gap = ''; indent = ''; if (typeof space === 'number') { for (i = 0; i < space; i += 1) { indent += ' '; } } else if (typeof space === 'string') { indent = space; } rep = replacer; if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) { throw new Error('JSON.stringify'); } return str('', { '': value }); }; } if (typeof JSON.parse !== 'function') { JSON.parse = function (text, reviver) { var j; function walk(holder, key) { var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } text = String(text); cx.lastIndex = 0; if (cx.test(text)) { text = text.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { j = eval('(' + text + ')'); return typeof reviver === 'function' ? walk({ '': j }, '') : j; } throw new SyntaxError('JSON.parse'); }; } } ());
|
Code on the Managed Solution Objects SDK.REST.js
// ===================================================================== // This file is part of the Microsoft Dynamics CRM SDK code samples. // // Copyright (C) Microsoft Corporation. All rights reserved. // // This source code is intended only as a supplement to Microsoft // Development Tools and/or on-line documentation. See these other // materials for detailed information regarding Microsoft code samples. // // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // ===================================================================== // <snippetSDKRESTJS> if (typeof (SDK) == "undefined") { SDK = { __namespace: true }; } SDK.REST = { _context: function () { ///<summary> /// Private function to the context object. ///</summary> ///<returns>Context</returns> if (typeof GetGlobalContext != "undefined") { return GetGlobalContext(); } else { if (typeof Xrm != "undefined") { return Xrm.Page.context; } else { throw new Error("Context is not available."); } } }, _getServerUrl: function () { ///<summary> /// Private function to return the server URL from the context ///</summary> ///<returns>String</returns> var serverUrl = this._context().getServerUrl() if (serverUrl.match(/\/$/)) { serverUrl = serverUrl.substring(0, serverUrl.length - 1); } return serverUrl; }, _ODataPath: function () { ///<summary> /// Private function to return the path to the REST endpoint. ///</summary> ///<returns>String</returns> return this._getServerUrl() + "/XRMServices/2011/OrganizationData.svc/"; }, _errorHandler: function (req) { ///<summary> /// Private function return an Error object to the errorCallback ///</summary> ///<param name="req" type="XMLHttpRequest"> /// The XMLHttpRequest response that returned an error. ///</param> ///<returns>Error</returns> //Error descriptions come from http://support.microsoft.com/kb/193625 if (req.status == 12029) { return new Error("The attempt to connect to the server failed."); } if (req.status == 12007) { return new Error("The server name could not be resolved."); } var errorText; try { errorText = JSON.parse(req.responseText).error.message.value; } catch (e) { errorText = req.responseText }
return new Error("Error : " + req.status + ": " + req.statusText + ": " + errorText); }, _dateReviver: function (key, value) { ///<summary> /// Private function to convert matching string values to Date objects. ///</summary> ///<param name="key" type="String"> /// The key used to identify the object property ///</param> ///<param name="value" type="String"> /// The string value representing a date ///</param> var a; if (typeof value === 'string') { a = /Date\(([-+]?\d+)\)/.exec(value); if (a) { return new Date(parseInt(value.replace("/Date(", "").replace(")/", ""), 10)); } } return value; }, _parameterCheck: function (parameter, message) { ///<summary> /// Private function used to check whether required parameters are null or undefined ///</summary> ///<param name="parameter" type="Object"> /// The parameter to check; ///</param> ///<param name="message" type="String"> /// The error message text to include when the error is thrown. ///</param> if ((typeof parameter === "undefined") || parameter === null) { throw new Error(message); } }, _stringParameterCheck: function (parameter, message) { ///<summary> /// Private function used to check whether required parameters are null or undefined ///</summary> ///<param name="parameter" type="String"> /// The string parameter to check; ///</param> ///<param name="message" type="String"> /// The error message text to include when the error is thrown. ///</param> if (typeof parameter != "string") { throw new Error(message); } }, _callbackParameterCheck: function (callbackParameter, message) { ///<summary> /// Private function used to check whether required callback parameters are functions ///</summary> ///<param name="callbackParameter" type="Function"> /// The callback parameter to check; ///</param> ///<param name="message" type="String"> /// The error message text to include when the error is thrown. ///</param> if (typeof callbackParameter != "function") { throw new Error(message); } }, createRecord: function (object, type, successCallback, errorCallback) { ///<summary> /// Sends an asynchronous request to create a new record. ///</summary> ///<param name="object" type="Object"> /// A JavaScript object with properties corresponding to the Schema name of /// entity attributes that are valid for create operations. ///</param> this._parameterCheck(object, "SDK.REST.createRecord requires the object parameter."); ///<param name="type" type="String"> /// The Schema Name of the Entity type record to create. /// For an Account record, use "Account" ///</param> this._stringParameterCheck(type, "SDK.REST.createRecord requires the type parameter is a string."); ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// This function can accept the returned record as a parameter. /// </param> this._callbackParameterCheck(successCallback, "SDK.REST.createRecord requires the successCallback is a function."); ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._callbackParameterCheck(errorCallback, "SDK.REST.createRecord requires the errorCallback is a function."); var req = new XMLHttpRequest(); req.open("POST", this._ODataPath() + type + "Set", true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 201) { successCallback(JSON.parse(this.responseText, SDK.REST._dateReviver).d); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(JSON.stringify(object)); }, retrieveRecord: function (id, type, select, expand, successCallback, errorCallback) { ///<summary> /// Sends an asynchronous request to retrieve a record. ///</summary> ///<param name="id" type="String"> /// A String representing the GUID value for the record to retrieve. ///</param> this._stringParameterCheck(id, "SDK.REST.retrieveRecord requires the id parameter is a string."); ///<param name="type" type="String"> /// The Schema Name of the Entity type record to retrieve. /// For an Account record, use "Account" ///</param> this._stringParameterCheck(type, "SDK.REST.retrieveRecord requires the type parameter is a string."); ///<param name="select" type="String"> /// A String representing the $select OData System Query Option to control which /// attributes will be returned. This is a comma separated list of Attribute names that are valid for retrieve. /// If null all properties for the record will be returned ///</param> if (select != null) this._stringParameterCheck(select, "SDK.REST.retrieveRecord requires the select parameter is a string."); ///<param name="expand" type="String"> /// A String representing the $expand OData System Query Option value to control which /// related records are also returned. This is a comma separated list of of up to 6 entity relationship names /// If null no expanded related records will be returned. ///</param> if (expand != null) this._stringParameterCheck(expand, "SDK.REST.retrieveRecord requires the expand parameter is a string."); ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// This function must accept the returned record as a parameter. /// </param> this._callbackParameterCheck(successCallback, "SDK.REST.retrieveRecord requires the successCallback parameter is a function."); ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._callbackParameterCheck(errorCallback, "SDK.REST.retrieveRecord requires the errorCallback parameter is a function.");
var systemQueryOptions = "";
if (select != null || expand != null) { systemQueryOptions = "?"; if (select != null) { var selectString = "$select=" + select; if (expand != null) { selectString = selectString + "," + expand; } systemQueryOptions = systemQueryOptions + selectString; } if (expand != null) { systemQueryOptions = systemQueryOptions + "&$expand=" + expand; } }
var req = new XMLHttpRequest(); req.open("GET", this._ODataPath() + type + "Set(guid'" + id + "')" + systemQueryOptions, true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 200) { successCallback(JSON.parse(this.responseText, SDK.REST._dateReviver).d); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(); }, updateRecord: function (id, object, type, successCallback, errorCallback) { ///<summary> /// Sends an asynchronous request to update a record. ///</summary> ///<param name="id" type="String"> /// A String representing the GUID value for the record to retrieve. ///</param> this._stringParameterCheck(id, "SDK.REST.updateRecord requires the id parameter."); ///<param name="object" type="Object"> /// A JavaScript object with properties corresponding to the Schema Names for /// entity attributes that are valid for update operations. ///</param> this._parameterCheck(object, "SDK.REST.updateRecord requires the object parameter."); ///<param name="type" type="String"> /// The Schema Name of the Entity type record to retrieve. /// For an Account record, use "Account" ///</param> this._stringParameterCheck(type, "SDK.REST.updateRecord requires the type parameter."); ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// Nothing will be returned to this function. /// </param> this._callbackParameterCheck(successCallback, "SDK.REST.updateRecord requires the successCallback is a function."); ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._callbackParameterCheck(errorCallback, "SDK.REST.updateRecord requires the errorCallback is a function."); var req = new XMLHttpRequest();
req.open("POST", this._ODataPath() + type + "Set(guid'" + id + "')", true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("X-HTTP-Method", "MERGE"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 204 || this.status == 1223) { successCallback(); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(JSON.stringify(object)); }, deleteRecord: function (id, type, successCallback, errorCallback) { ///<summary> /// Sends an asynchronous request to delete a record. ///</summary> ///<param name="id" type="String"> /// A String representing the GUID value for the record to delete. ///</param> this._stringParameterCheck(id, "SDK.REST.deleteRecord requires the id parameter."); ///<param name="type" type="String"> /// The Schema Name of the Entity type record to delete. /// For an Account record, use "Account" ///</param> this._stringParameterCheck(type, "SDK.REST.deleteRecord requires the type parameter."); ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// Nothing will be returned to this function. /// </param> this._callbackParameterCheck(successCallback, "SDK.REST.deleteRecord requires the successCallback is a function."); ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._callbackParameterCheck(errorCallback, "SDK.REST.deleteRecord requires the errorCallback is a function."); var req = new XMLHttpRequest(); req.open("POST", this._ODataPath() + type + "Set(guid'" + id + "')", true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("X-HTTP-Method", "DELETE"); req.onreadystatechange = function () {
if (this.readyState == 4 /* complete */) { if (this.status == 204 || this.status == 1223) { successCallback(); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send();
}, retrieveMultipleRecords: function (type, options, successCallback, errorCallback, OnComplete) { ///<summary> /// Sends an asynchronous request to retrieve records. ///</summary> ///<param name="type" type="String"> /// The Schema Name of the Entity type record to retrieve. /// For an Account record, use "Account" ///</param> this._stringParameterCheck(type, "SDK.REST.retrieveMultipleRecords requires the type parameter is a string."); ///<param name="options" type="String"> /// A String representing the OData System Query Options to control the data returned ///</param> if (options != null) this._stringParameterCheck(options, "SDK.REST.retrieveMultipleRecords requires the options parameter is a string."); ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called for each page of records returned. /// Each page is 50 records. If you expect that more than one page of records will be returned, /// this function should loop through the results and push the records into an array outside of the function. /// Use the OnComplete event handler to know when all the records have been processed. /// </param> this._callbackParameterCheck(successCallback, "SDK.REST.retrieveMultipleRecords requires the successCallback parameter is a function."); ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._callbackParameterCheck(errorCallback, "SDK.REST.retrieveMultipleRecords requires the errorCallback parameter is a function."); ///<param name="OnComplete" type="Function"> /// The function that will be called when all the requested records have been returned. /// No parameters are passed to this function. /// </param> this._callbackParameterCheck(OnComplete, "SDK.REST.retrieveMultipleRecords requires the OnComplete parameter is a function.");
var optionsString; if (options != null) { if (options.charAt(0) != "?") { optionsString = "?" + options; } else { optionsString = options; } } var req = new XMLHttpRequest(); req.open("GET", this._ODataPath() + type + "Set" + optionsString, true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 200) { var returned = JSON.parse(this.responseText, SDK.REST._dateReviver).d; successCallback(returned.results); if (returned.__next != null) { var queryOptions = returned.__next.substring((SDK.REST._ODataPath() + type + "Set").length); SDK.REST.retrieveMultipleRecords(type, queryOptions, successCallback, errorCallback, OnComplete); } else { OnComplete(); } } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(); }, associateRecords: function (parentId, parentType, relationshipName, childId, childType, successCallback, errorCallback) { this._stringParameterCheck(parentId, "SDK.REST.associateRecords requires the parentId parameter is a string."); ///<param name="parentId" type="String"> /// The Id of the record to be the parent record in the relationship /// </param> this._stringParameterCheck(parentType, "SDK.REST.associateRecords requires the parentType parameter is a string."); ///<param name="parentType" type="String"> /// The Schema Name of the Entity type for the parent record. /// For an Account record, use "Account" /// </param> this._stringParameterCheck(relationshipName, "SDK.REST.associateRecords requires the relationshipName parameter is a string."); ///<param name="parentType" type="String"> /// The Schema Name of the Entity Relationship to use to associate the records. /// To associate account records as a Parent account, use "Referencedaccount_parent_account" /// </param> this._stringParameterCheck(childId, "SDK.REST.associateRecords requires the childId parameter is a string."); ///<param name="childId" type="String"> /// The Id of the record to be the child record in the relationship /// </param> this._stringParameterCheck(childType, "SDK.REST.associateRecords requires the childType parameter is a string."); ///<param name="childType" type="String"> /// The Schema Name of the Entity type for the child record. /// For an Account record, use "Account" /// </param> this._callbackParameterCheck(successCallback, "SDK.REST.associateRecords requires the successCallback parameter is a function."); ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// Nothing will be returned to this function. /// </param> this._callbackParameterCheck(errorCallback, "SDK.REST.associateRecords requires the errorCallback parameter is a function."); ///<param name="OnComplete" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> var req = new XMLHttpRequest(); req.open("POST", this._ODataPath() + parentType + "Set(guid'" + parentId + "')/$links/" + relationshipName, true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 204 || this.status == 1223) { successCallback(); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; var childEntityReference = {} childEntityReference.uri = this._ODataPath() + "/" + childType + "Set(guid'" + childId + "')"; req.send(JSON.stringify(childEntityReference)); }, disassociateRecords: function (parentId, parentType, relationshipName, childId, successCallback, errorCallback) { this._stringParameterCheck(parentId, "SDK.REST.disassociateRecords requires the parentId parameter is a string."); ///<param name="parentId" type="String"> /// The Id of the record to be the parent record in the relationship /// </param> this._stringParameterCheck(parentType, "SDK.REST.disassociateRecords requires the parentType parameter is a string."); ///<param name="parentType" type="String"> /// The Schema Name of the Entity type for the parent record. /// For an Account record, use "Account" /// </param> this._stringParameterCheck(relationshipName, "SDK.REST.disassociateRecords requires the relationshipName parameter is a string."); ///<param name="parentType" type="String"> /// The Schema Name of the Entity Relationship to use to disassociate the records. /// To disassociate account records as a Parent account, use "Referencedaccount_parent_account" /// </param> this._stringParameterCheck(childId, "SDK.REST.disassociateRecords requires the childId parameter is a string."); ///<param name="childId" type="String"> /// The Id of the record to be disassociated as the child record in the relationship /// </param> this._callbackParameterCheck(successCallback, "SDK.REST.disassociateRecords requires the successCallback parameter is a function."); ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// Nothing will be returned to this function. /// </param> this._callbackParameterCheck(errorCallback, "SDK.REST.disassociateRecords requires the errorCallback parameter is a function."); ///<param name="OnComplete" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> var req = new XMLHttpRequest(); req.open("POST", this._ODataPath() + parentType + "Set(guid'" + parentId + "')/$links/" + relationshipName + "(guid'" + childId + "')", true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("X-HTTP-Method", "DELETE"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 204 || this.status == 1223) { successCallback(); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(); }, __namespace: true }; // </snippetSDKRESTJS>
| Code on the Manually Imported Objects SDK.REST.js
// ===================================================================== // This file is part of the Microsoft Dynamics CRM SDK code samples. // // Copyright (C) Microsoft Corporation. All rights reserved. // // This source code is intended only as a supplement to Microsoft // Development Tools and/or on-line documentation. See these other // materials for detailed information regarding Microsoft code samples. // // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // ===================================================================== // <snippetSDKRESTJS> if (typeof (SDK) == "undefined") { SDK = { __namespace: true }; } SDK.REST = { _context: function () { ///<summary> /// Private function to the context object. ///</summary> ///<returns>Context</returns> if (typeof GetGlobalContext != "undefined") { return GetGlobalContext(); } else { if (typeof Xrm != "undefined") { return Xrm.Page.context; } else { throw new Error("Context is not available."); } } }, _getServerUrl: function () { ///<summary> /// Private function to return the server URL from the context ///</summary> ///<returns>String</returns> var serverUrl = this._context().getServerUrl() if (serverUrl.match(/\/$/)) { serverUrl = serverUrl.substring(0, serverUrl.length - 1); } return serverUrl; }, _ODataPath: function () { ///<summary> /// Private function to return the path to the REST endpoint. ///</summary> ///<returns>String</returns> return this._getServerUrl() + "/XRMServices/2011/OrganizationData.svc/"; }, _errorHandler: function (req) { ///<summary> /// Private function return an Error object to the errorCallback ///</summary> ///<param name="req" type="XMLHttpRequest"> /// The XMLHttpRequest response that returned an error. ///</param> ///<returns>Error</returns> //Error descriptions come from http://support.microsoft.com/kb/193625 if (req.status == 12029) { return new Error("The attempt to connect to the server failed."); } if (req.status == 12007) { return new Error("The server name could not be resolved."); } var errorText; try { errorText = JSON.parse(req.responseText).error.message.value; } catch (e) { errorText = req.responseText }
return new Error("Error : " + req.status + ": " + req.statusText + ": " + errorText); }, _dateReviver: function (key, value) { ///<summary> /// Private function to convert matching string values to Date objects. ///</summary> ///<param name="key" type="String"> /// The key used to identify the object property ///</param> ///<param name="value" type="String"> /// The string value representing a date ///</param> var a; if (typeof value === 'string') { a = /Date\(([-+]?\d+)\)/.exec(value); if (a) { return new Date(parseInt(value.replace("/Date(", "").replace(")/", ""), 10)); } } return value; }, _parameterCheck: function (parameter, message) { ///<summary> /// Private function used to check whether required parameters are null or undefined ///</summary> ///<param name="parameter" type="Object"> /// The parameter to check; ///</param> ///<param name="message" type="String"> /// The error message text to include when the error is thrown. ///</param> if ((typeof parameter === "undefined") || parameter === null) { throw new Error(message); } }, _stringParameterCheck: function (parameter, message) { ///<summary> /// Private function used to check whether required parameters are null or undefined ///</summary> ///<param name="parameter" type="String"> /// The string parameter to check; ///</param> ///<param name="message" type="String"> /// The error message text to include when the error is thrown. ///</param> if (typeof parameter != "string") { throw new Error(message); } }, _callbackParameterCheck: function (callbackParameter, message) { ///<summary> /// Private function used to check whether required callback parameters are functions ///</summary> ///<param name="callbackParameter" type="Function"> /// The callback parameter to check; ///</param> ///<param name="message" type="String"> /// The error message text to include when the error is thrown. ///</param> if (typeof callbackParameter != "function") { throw new Error(message); } }, createRecord: function (object, type, successCallback, errorCallback) { ///<summary> /// Sends an asynchronous request to create a new record. ///</summary> ///<param name="object" type="Object"> /// A JavaScript object with properties corresponding to the Schema name of /// entity attributes that are valid for create operations. ///</param> ///<param name="type" type="String"> /// The Schema Name of the Entity type record to create. /// For an Account record, use "Account" ///</param> ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// This function can accept the returned record as a parameter. /// </param> ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._parameterCheck(object, "SDK.REST.createRecord requires the object parameter."); this._stringParameterCheck(type, "SDK.REST.createRecord requires the type parameter is a string."); this._callbackParameterCheck(successCallback, "SDK.REST.createRecord requires the successCallback is a function."); this._callbackParameterCheck(errorCallback, "SDK.REST.createRecord requires the errorCallback is a function."); var req = new XMLHttpRequest(); req.open("POST", encodeURI(this._ODataPath() + type + "Set"), true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 201) { this.onreadystatechange = null; //avoids memory leaks successCallback(JSON.parse(this.responseText, SDK.REST._dateReviver).d); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(JSON.stringify(object)); }, retrieveRecord: function (id, type, select, expand, successCallback, errorCallback) { ///<summary> /// Sends an asynchronous request to retrieve a record. ///</summary> ///<param name="id" type="String"> /// A String representing the GUID value for the record to retrieve. ///</param> ///<param name="type" type="String"> /// The Schema Name of the Entity type record to retrieve. /// For an Account record, use "Account" ///</param> ///<param name="select" type="String"> /// A String representing the $select OData System Query Option to control which /// attributes will be returned. This is a comma separated list of Attribute names that are valid for retrieve. /// If null all properties for the record will be returned ///</param> ///<param name="expand" type="String"> /// A String representing the $expand OData System Query Option value to control which /// related records are also returned. This is a comma separated list of of up to 6 entity relationship names /// If null no expanded related records will be returned. ///</param> ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// This function must accept the returned record as a parameter. /// </param> ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._stringParameterCheck(id, "SDK.REST.retrieveRecord requires the id parameter is a string."); this._stringParameterCheck(type, "SDK.REST.retrieveRecord requires the type parameter is a string."); if (select != null) this._stringParameterCheck(select, "SDK.REST.retrieveRecord requires the select parameter is a string."); if (expand != null) this._stringParameterCheck(expand, "SDK.REST.retrieveRecord requires the expand parameter is a string."); this._callbackParameterCheck(successCallback, "SDK.REST.retrieveRecord requires the successCallback parameter is a function."); this._callbackParameterCheck(errorCallback, "SDK.REST.retrieveRecord requires the errorCallback parameter is a function.");
var systemQueryOptions = "";
if (select != null || expand != null) { systemQueryOptions = "?"; if (select != null) { var selectString = "$select=" + select; if (expand != null) { selectString = selectString + "," + expand; } systemQueryOptions = systemQueryOptions + selectString; } if (expand != null) { systemQueryOptions = systemQueryOptions + "&$expand=" + expand; } }
var req = new XMLHttpRequest(); req.open("GET", encodeURI(this._ODataPath() + type + "Set(guid'" + id + "')" + systemQueryOptions), true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 200) { this.onreadystatechange = null; //avoids memory leaks successCallback(JSON.parse(this.responseText, SDK.REST._dateReviver).d); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(); }, updateRecord: function (id, object, type, successCallback, errorCallback) { ///<summary> /// Sends an asynchronous request to update a record. ///</summary> ///<param name="id" type="String"> /// A String representing the GUID value for the record to retrieve. ///</param> ///<param name="object" type="Object"> /// A JavaScript object with properties corresponding to the Schema Names for /// entity attributes that are valid for update operations. ///</param> ///<param name="type" type="String"> /// The Schema Name of the Entity type record to retrieve. /// For an Account record, use "Account" ///</param> ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// Nothing will be returned to this function. /// </param> ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._stringParameterCheck(id, "SDK.REST.updateRecord requires the id parameter."); this._parameterCheck(object, "SDK.REST.updateRecord requires the object parameter."); this._stringParameterCheck(type, "SDK.REST.updateRecord requires the type parameter."); this._callbackParameterCheck(successCallback, "SDK.REST.updateRecord requires the successCallback is a function."); this._callbackParameterCheck(errorCallback, "SDK.REST.updateRecord requires the errorCallback is a function."); var req = new XMLHttpRequest();
req.open("POST", encodeURI(this._ODataPath() + type + "Set(guid'" + id + "')"), true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("X-HTTP-Method", "MERGE"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 204 || this.status == 1223) { this.onreadystatechange = null; //avoids memory leaks successCallback(); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(JSON.stringify(object)); }, deleteRecord: function (id, type, successCallback, errorCallback) { ///<summary> /// Sends an asynchronous request to delete a record. ///</summary> ///<param name="id" type="String"> /// A String representing the GUID value for the record to delete. ///</param> ///<param name="type" type="String"> /// The Schema Name of the Entity type record to delete. /// For an Account record, use "Account" ///</param> ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// Nothing will be returned to this function. /// </param> ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._stringParameterCheck(id, "SDK.REST.deleteRecord requires the id parameter."); this._stringParameterCheck(type, "SDK.REST.deleteRecord requires the type parameter."); this._callbackParameterCheck(successCallback, "SDK.REST.deleteRecord requires the successCallback is a function."); this._callbackParameterCheck(errorCallback, "SDK.REST.deleteRecord requires the errorCallback is a function."); var req = new XMLHttpRequest(); req.open("POST", encodeURI(this._ODataPath() + type + "Set(guid'" + id + "')"), true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("X-HTTP-Method", "DELETE"); req.onreadystatechange = function () {
if (this.readyState == 4 /* complete */) { if (this.status == 204 || this.status == 1223) { this.onreadystatechange = null; //avoids memory leaks successCallback(); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send();
}, retrieveMultipleRecords: function (type, options, successCallback, errorCallback, OnComplete) { ///<summary> /// Sends an asynchronous request to retrieve records. ///</summary> ///<param name="type" type="String"> /// The Schema Name of the Entity type record to retrieve. /// For an Account record, use "Account" ///</param> ///<param name="options" type="String"> /// A String representing the OData System Query Options to control the data returned ///</param> ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called for each page of records returned. /// Each page is 50 records. If you expect that more than one page of records will be returned, /// this function should loop through the results and push the records into an array outside of the function. /// Use the OnComplete event handler to know when all the records have been processed. /// </param> ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> ///<param name="OnComplete" type="Function"> /// The function that will be called when all the requested records have been returned. /// No parameters are passed to this function. /// </param> this._stringParameterCheck(type, "SDK.REST.retrieveMultipleRecords requires the type parameter is a string."); if (options != null) this._stringParameterCheck(options, "SDK.REST.retrieveMultipleRecords requires the options parameter is a string."); this._callbackParameterCheck(successCallback, "SDK.REST.retrieveMultipleRecords requires the successCallback parameter is a function."); this._callbackParameterCheck(errorCallback, "SDK.REST.retrieveMultipleRecords requires the errorCallback parameter is a function."); this._callbackParameterCheck(OnComplete, "SDK.REST.retrieveMultipleRecords requires the OnComplete parameter is a function.");
var optionsString; if (options != null) { if (options.charAt(0) != "?") { optionsString = "?" + options; } else { optionsString = options; } } var req = new XMLHttpRequest(); req.open("GET", this._ODataPath() + type + "Set" + optionsString, true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 200) { this.onreadystatechange = null; //avoids memory leaks var returned = JSON.parse(this.responseText, SDK.REST._dateReviver).d; successCallback(returned.results); if (returned.__next != null) { var queryOptions = returned.__next.substring((SDK.REST._ODataPath() + type + "Set").length); SDK.REST.retrieveMultipleRecords(type, queryOptions, successCallback, errorCallback, OnComplete); } else { OnComplete(); } } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(); }, associateRecords: function (parentId, parentType, relationshipName, childId, childType, successCallback, errorCallback) { this._stringParameterCheck(parentId, "SDK.REST.associateRecords requires the parentId parameter is a string."); ///<param name="parentId" type="String"> /// The Id of the record to be the parent record in the relationship /// </param> ///<param name="parentType" type="String"> /// The Schema Name of the Entity type for the parent record. /// For an Account record, use "Account" /// </param> ///<param name="relationshipName" type="String"> /// The Schema Name of the Entity Relationship to use to associate the records. /// To associate account records as a Parent account, use "Referencedaccount_parent_account" /// </param> ///<param name="childId" type="String"> /// The Id of the record to be the child record in the relationship /// </param> ///<param name="childType" type="String"> /// The Schema Name of the Entity type for the child record. /// For an Account record, use "Account" /// </param> ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// Nothing will be returned to this function. /// </param> ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._stringParameterCheck(parentType, "SDK.REST.associateRecords requires the parentType parameter is a string."); this._stringParameterCheck(relationshipName, "SDK.REST.associateRecords requires the relationshipName parameter is a string."); this._stringParameterCheck(childId, "SDK.REST.associateRecords requires the childId parameter is a string."); this._stringParameterCheck(childType, "SDK.REST.associateRecords requires the childType parameter is a string."); this._callbackParameterCheck(successCallback, "SDK.REST.associateRecords requires the successCallback parameter is a function."); this._callbackParameterCheck(errorCallback, "SDK.REST.associateRecords requires the errorCallback parameter is a function.");
var req = new XMLHttpRequest(); req.open("POST", encodeURI(this._ODataPath() + parentType + "Set(guid'" + parentId + "')/$links/" + relationshipName), true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 204 || this.status == 1223) { this.onreadystatechange = null; //avoids memory leaks successCallback(); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; var childEntityReference = {} childEntityReference.uri = this._ODataPath() + "/" + childType + "Set(guid'" + childId + "')"; req.send(JSON.stringify(childEntityReference)); }, disassociateRecords: function (parentId, parentType, relationshipName, childId, successCallback, errorCallback) { this._stringParameterCheck(parentId, "SDK.REST.disassociateRecords requires the parentId parameter is a string."); ///<param name="parentId" type="String"> /// The Id of the record to be the parent record in the relationship /// </param> ///<param name="parentType" type="String"> /// The Schema Name of the Entity type for the parent record. /// For an Account record, use "Account" /// </param> ///<param name="relationshipName" type="String"> /// The Schema Name of the Entity Relationship to use to disassociate the records. /// To disassociate account records as a Parent account, use "Referencedaccount_parent_account" /// </param> ///<param name="childId" type="String"> /// The Id of the record to be disassociated as the child record in the relationship /// </param> ///<param name="successCallback" type="Function"> /// The function that will be passed through and be called by a successful response. /// Nothing will be returned to this function. /// </param> ///<param name="errorCallback" type="Function"> /// The function that will be passed through and be called by a failed response. /// This function must accept an Error object as a parameter. /// </param> this._stringParameterCheck(parentType, "SDK.REST.disassociateRecords requires the parentType parameter is a string."); this._stringParameterCheck(relationshipName, "SDK.REST.disassociateRecords requires the relationshipName parameter is a string."); this._stringParameterCheck(childId, "SDK.REST.disassociateRecords requires the childId parameter is a string."); this._callbackParameterCheck(successCallback, "SDK.REST.disassociateRecords requires the successCallback parameter is a function."); this._callbackParameterCheck(errorCallback, "SDK.REST.disassociateRecords requires the errorCallback parameter is a function.");
var req = new XMLHttpRequest(); req.open("POST", encodeURI(this._ODataPath() + parentType + "Set(guid'" + parentId + "')/$links/" + relationshipName + "(guid'" + childId + "')"), true); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("X-HTTP-Method", "DELETE"); req.onreadystatechange = function () { if (this.readyState == 4 /* complete */) { if (this.status == 204 || this.status == 1223) { this.onreadystatechange = null; //avoids memory leaks successCallback(); } else { errorCallback(SDK.REST._errorHandler(this)); } } }; req.send(); }, __namespace: true }; // </snippetSDKRESTJS>
|