Dynamics CRM 2016: JavaScript causes JSON Parse Error - javascript

I am trying to get the price of a product in Dynamics CRM 2016, by javascript on the onChange event for the product. This is on a custom entity I have created and is using the pricelistid and the productid.
When I use the same javascript in the console on Chrome i can get the data out but when it is executed by the CRM form I get an error:
SyntaxError: Unexpected end of JSON input at JSON.parse ()
The code is:
var pricelevelid = Xrm.Page.getAttribute("sg_pricelistid").getValue()[0].id;
pricelevelid = pricelevelid.replace(/[{}]/g, "");
var productdata = Xrm.Page.getAttribute("sg_productid").getValue();
if (productdata != null)
{
console.log("going into productdata loop");
productid = productdata[0].id;
productid = productid.replace(/[{}]/g, "");
var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.0/productpricelevels?$select=amount,_pricelevelid_value,_productid_value,productpricelevelid&$filter=_pricelevelid_value eq " + pricelevelid + " and _productid_value eq " + productid + "", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function() {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200) {
var results = JSON.parse(this.response);
for (var i = 0; i < results.value.length; i++) {
var amount = results.value[i]["amount"];
var amount_formatted = results.value[i]["amount#OData.Community.Display.V1.FormattedValue"];
}
} else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send();
data = JSON.parse(req.responseText);
var amount = data.value[0]["amount"];
Xrm.Page.getAttribute("sg_unitprice").setValue(amount);
}

You are performing an asynchronous request and then attempting to parse the response, before it has been set to anything.
This happens at the bottom of your code block at data = JSON.parse(req.responseText), right after you send the request.
All code that relies on the response should be executed in the req.onreadystatechange callback function.

Related

Dynamics 365 Javascript - Return Value Is Undefined

I am trying to discern if a user is a member of a certain team in Dynamics 365. I am using the following JavaScript functions to attempt this. My issue is that even though the getUserTeams is finding the user in the team when the result gets passed back to the calling function (UserHasTeam) the value is undefined. I feel like I am missing something here but for the life of me I don't know what. Can anyone help me?
function UserHasTeam(teamName) {
///<summary>
/// Checks to see if the current user is a member of a team with the passed in name.
///</summary>
///<param name="teamName" type="String">
/// A String representing the name of the team to check if the user is a member of.
///</param>
var res;
if (teamName != null && teamName != "") {
// build endpoint URL
var serverUrl = Xrm.Page.context.getClientUrl();
var oDataEndpointUrl = serverUrl + "/XRMServices/2011/OrganizationData.svc/";
// query to get the teams that match the name
oDataEndpointUrl += "TeamSet?$select=Name,TeamId&$filter=Name eq '" + teamName + "'";
console.log(oDataEndpointUrl);
// execute the request
var req = new XMLHttpRequest();
req.open("GET", oDataEndpointUrl, true);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.onreadystatechange = function () {
if (this.readyState == 4 /* complete */) {
req.onreadystatechange = null;
if (this.status == 200) {
console.log("Success");
result = JSON.parse(this.response);
console.log(result);
console.log(result["d"]["results"][0]["TeamId"]);
res = getUserTeams(result["d"]["results"][0]["TeamId"]);
console.log(res);
} else {
var error = JSON.parse(this.response).error;
console.log(error);
}
}
};
req.send(null);
return res;
}
}
function getUserTeams(teamToCheckId) {
// gets the current users team membership
var res;
var userId = Xrm.Page.context.getUserId().substr(1, 36);
var serverUrl = Xrm.Page.context.getClientUrl();
var oDataEndpointUrl = serverUrl + "/XRMServices/2011/OrganizationData.svc/";
oDataEndpointUrl += "TeamMembershipSet?$filter=SystemUserId eq guid' " + userId + " ' and TeamId eq guid' " + teamToCheckId + " '";
var req = new XMLHttpRequest();
req.open("GET", oDataEndpointUrl, true);
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.onreadystatechange = function () {
if (this.readyState == 4 /* complete */) {
req.onreadystatechange = null;
if (this.status == 200) {
console.log("Success");
result = JSON.parse(this.response);
console.log(result["d"]["results"].length);
if(result["d"]["results"].length == 1) {
res = true;
} else {
res = false;
}
} else {
var error = JSON.parse(this.response).error;
console.log(error);
}
}
};
req.send(null);
return res;
}
you are calling webapi request as Async and not sync.
req.open("GET", oDataEndpointUrl, true);
You should be calling it Sync like below
req.open("GET", oDataEndpointUrl, false);
In addition, if you are using Dynamics 365 you should be using up to date webapi request.
Note: new webapi calls are in build Async and you should be using promise to make it sync.
Take a look at this retrievemultiplerecords
and retrieveRecord
Please mark it as solved if it helps

Microsoft Dynamics 2016 - Javascript Banner

I would like to utilize Xrm.Page.ui.setFormNotification to display a banner at the top of a Shipment record. This banner would only appear for Shipments where the related entity Account is classified as "Service Watch".
I'm pretty new to Javascript so I'm a bit lost how to pull values from related entities of a record to use.
Xrm.Page.ui.setFormNotification("This Account is currently under Service Watch", "WARNING")
EDIT: Code working;
function checkServiceWatch() {
try{
var account = Xrm.Page.getAttribute("cmm_account").getValue();
var accountid = account[0].id;
var formattedGuid = accountid.replace("}", "");
accountid = formattedGuid.replace("{", "");
"/api/data/v8.2/accounts(" + accountid + ")?
$select=cmm_servicewatch");
var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/accounts(" + accountid + ")?$select=cmm_servicewatch", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function()
{
if (this.readyState === 4)
{
req.onreadystatechange = null;
if (this.status === 200)
{
var result = JSON.parse(this.response);
var serviceWatch = result["cmm_servicewatch"];
// alert("serviceWatch: " + serviceWatch);
if(serviceWatch) //set notification
{
Xrm.Page.ui.setFormNotification("This Account is currently under Service Watch","WARNING","1");
} // else
// {
// //Xrm.Page.ui.clearFormNotification("1");
// }
}
else
{
Xrm.Utility.alertDialog("Status: " + this.status + ", Text: " + this.statusText);
}
}
};
req.send();
}
catch (err) {
alert("ServiceWatchCheckRibbon | checkServiceWatch " + err.message);
}
}
You have to query the Account lookup record on form load to pull the extra attribute which says "Service watch" and show the notification banner if so.
You can refer this community thread & use the sample code as is or Xrm.Webapi method to do it based on your CRM version.
function checkAccount(){
var accountid = Xrm.Page.data.entity.attributes.get("new_parentaccount").getValue()[0].id;
if (accountid.startsWith("{") && accountid.endsWith("}"))
{
accountid = accountid.slice(1, accountid.length - 1);
}
var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/accounts(" + accountid + ")?$select=new_servicewatch", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function() {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200)
{
var result = JSON.parse(this.response);
var serviceWatch = result["new_servicewatch"];
if(serviceWatch) //set notification
{
Xrm.Page.ui.setFormNotification("This Account is currently under Service Watch","WARNING","1");
} else
{
//Xrm.Page.ui.clearFormNotification("1");
}
}
else
{
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send();
}

I'm trying to fetch Invoices entity linked with Invoiceline entity ,and I get no result

My fetch works fine when I use just attributes, but when I add link-entity, or filter it doesn't work. Here is the link code. Please help to find my mistake!
These two entities are connected with the name field in Invoice and invoice field in invoiceline.
var fetchInvoices = '<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">';
fetchInvoices += '<entity name="hms_invoice">';
fetchInvoices += '<attribute name="hms_name"/>';
fetchInvoices += '<attribute name="hms_customer" />';
fetchInvoices += '<link-entity name="hms_invoiceline" from="hms_invoice" to="hms_name">';
fetchInvoices += '<attribute name="hms_amount" />';
fetchInvoices += '</link-entity>';
fetchInvoices += '</entity>';
fetchInvoices += '</fetch>';
var invoices = XrmServiceToolkit.Soap.Fetch(fetchInvoices);
alert(invoices.length);
I need to get name and customer from Invoice, and amount from invoice lines.
I would refrain form using XrmServiceToolkit.Soap.Fetch as you will have to add third party library for using it and SOAP is unsupported in latest version, Instead I would advice using Webapi as this is the supported way and simplest way fetching data.
Here is the link which will provide you more details w.r.t Webserevice calls in D365 crm.
Below I have tried fetching All contacts for a particular Account Id,
For example: Account A has 3 contacts linked to it and I am fetching all the 3 contacts.
Here is the sample code for it.
var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v9.1/contacts?$select=_accountid_value,contactid,fullname&$filter=_accountid_value eq 4930FC98-5F75-E911-A83C-000D3A385DD4", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
req.onreadystatechange = function() {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200) {
var results = JSON.parse(this.response);
for (var i = 0; i < results.value.length; i++) {
var _accountid_value = results.value[i]["_accountid_value"];
var _accountid_value_formatted = results.value[i]["_accountid_value#OData.Community.Display.V1.FormattedValue"];
var _accountid_value_lookuplogicalname = results.value[i]["_accountid_value#Microsoft.Dynamics.CRM.lookuplogicalname"];
var contactid = results.value[i]["contactid"];
var fullname = results.value[i]["fullname"];
}
} else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send();
There is one more out of box new way of calling webapi with smaller code as below
Xrm.WebApi.online.retrieveMultipleRecords("contact", "?$select=_accountid_value,contactid,fullname&$filter=_accountid_value eq 4930FC98-5F75-E911-A83C-000D3A385DD4").then(
function success(results) {
for (var i = 0; i < results.entities.length; i++) {
var _accountid_value = results.entities[i]["_accountid_value"];
var _accountid_value_formatted = results.entities[i]["_accountid_value#OData.Community.Display.V1.FormattedValue"];
var _accountid_value_lookuplogicalname = results.entities[i]["_accountid_value#Microsoft.Dynamics.CRM.lookuplogicalname"];
var contactid = results.entities[i]["contactid"];
var fullname = results.entities[i]["fullname"];
}
},
function(error) {
Xrm.Utility.alertDialog(error.message);
}
);

Entity Type not defined when Customer Field Code is run

I've been working on this code. When I run it and some fields don't exist, the error of Entity Type not defined pops up. I tried If statements but it still isn't working. I've read it may have something to do with the currency but I can't seem to figure out what. I'm a beginner and most of this isn't my code. Help! Thanks.
function customerSelected() {
var customerID = Xrm.Page.getAttribute("customerid").getValue();
var custID = customerID[0].id.substr(1, 36);
var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/accounts?$select=_defaultpricelevelid_value,paymenttermscode,shippingmethodcode&$filter=accountid eq " + custID + "&$orderby=name asc", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
req.onreadystatechange = function () {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200) {
var results = JSON.parse(this.response);
for (var i = 0; i < results.value.length; i++) {
var _defaultpricelevelid_value = results.value[i]["_defaultpricelevelid_value"];
var _defaultpricelevelid_value_formatted = results.value[i]["_defaultpricelevelid_value#OData.Community.Display.V1.FormattedValue"];
var _defaultpricelevelid_value_lookuplogicalname = results.value[i]["_defaultpricelevelid_value#Microsoft.Dynamics.CRM.lookuplogicalname"];
var paymenttermscode = results.value[i]["paymenttermscode"];
var paymenttermscode_formatted = results.value[i]["paymenttermscode#OData.Community.Display.V1.FormattedValue"];
var shippingmethodcode = results.value[i]["shippingmethodcode"];
var shippingmethodcode_formatted = results.value[i]["shippingmethodcode#OData.Community.Display.V1.FormattedValue"];
var _defaultpricelevelid_lookupVal = new Array();
_defaultpricelevelid_lookupVal[0] = new Object();
_defaultpricelevelid_lookupVal[0].id = _defaultpricelevelid_value;
_defaultpricelevelid_lookupVal[0].name = _defaultpricelevelid_value_formatted;
_defaultpricelevelid_lookupVal[0].entityType = _defaultpricelevelid_value_lookuplogicalname;
if ("pricelevelid" != null)
{
Xrm.Page.getAttribute("pricelevelid").setValue(_defaultpricelevelid_lookupVal);
}
if ("paymenttermscode" != null)
{
Xrm.Page.getAttribute("paymenttermscode").setValue(_defaultpricelevelid_lookupVal);
}
if ("shippingmethodcode" != null)
{
Xrm.Page.getAttribute("shippingmethodcode").setValue(_defaultpricelevelid_lookupVal);
}
}
} else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send();
};
Your query will always return exactly one record, so it does not make sense to use a loop to iterate the results.
Condition ("pricelevelid" != null) will always be true. It probably should be (_defaultpricelevelid_value != null). The same goes for the lines below it.
Your code is assigning _defaultpricelevelid_lookupVal to three separate attributes, which cannot be correct. Apparently this object is supposed to represent a lookup ID value referencing entity pricelevel. Therefore it only makes sense to assign it to attribute pricelevelid. paymenttermscode and shippingmethodcode are option set attributes and apparently need to be filled with the values of the equally named variables.
Replace the for loop with this code:
if (results.value[0]._defaultpricelevelid_value != null) {
var priceLevelId = [{
id = results.value[0]._defaultpricelevelid_value,
name = results.value[0]["_defaultpricelevelid_value#OData.Community.Display.V1.FormattedValue"],
entityType = "pricelevel"
}];
Xrm.Page.getAttribute("pricelevelid").setValue(priceLevelId);
}
if (results.value[0].paymenttermscode != null) {
Xrm.Page.getAttribute("paymenttermscode").setValue(results.value[0].paymenttermscode);
}
if (results.value[0].shippingmethodcode != null) {
Xrm.Page.getAttribute("shippingmethodcode").setValue(results.value[0].shippingmethodcode);
}

update function on ajaxObject

When a button is clicked on the webpage a table of data is displayed. I want to scrape that data but I can't find where it comes from in the website source code.
This is the tag for the button:
<button type="submit" onclick="divChangeStateOn('load-raw-0062294377Amazon.com'); getRaw('0062294377', 'Amazon.com', 'lr-0062294377Amazon.com',this);"style="margin-bottom: 4px; width: 120px; text-align: left;" name="load-raw"><img src='images/workstation.png'/> raw data</button>
I believe that the getRaw function is where the data comes from (I'm not positive about this) so I looked at the javascript code for the getRaw function
function getRaw(asin, store, res, caller)
{ document.getElementById(res).innerHTML = '<p align="center" valign="top"><img align="center" src="phpmy_loading.gif"></p>';
var poststr = "raw=" + encodeURI(asin) +
"&site=" + encodeURI(store);
var updateResults = new ajaxObject(res, 'extra.php', caller);
updateResults.update(poststr);
}
I have been having a hard time finding any documentation about ajaxObject and can't find any information about the update function. What is ajaxObject.update doing and is it possible for me to access the data that appears when the button is clicked?
function divChangeStateOn(divID)
{ var divElem = document.getElementById(divID);
divElem.style.display = 'block';
}
EDIT: The link to the source code view-source:http://www.ranktracer.com/account_workstation.php it might be password protected but I was just using the demo version
EDIT 2:
I am basically trying to write a script that replicates the Ajax http request. This where I am at, it doesn't work and I am especially concerned about where data = uri
x = time.time()
print x
timestamp = datetime.fromtimestamp(x/1000.0)
print timestamp
uri = "raw=0062294377&site=Amazon.com&timestamp="+str(timestamp);
url = "lr-0062294377Amazon.com"
length = str(len(uri))
headers = {'X-Requested-With': 'XMLHttpRequest',
"Content-type": "application/x-www-form-urlencoded",
"Content-length": length,
"Connection" : "close"}
s = Session()
r = s.post(url= url, data= uri, headers= headers)
The entire code for ajaxObject is present in the link you provided. Please let us know what help you are expecting here?
function ajaxObject(layer, url, caller) {
if (caller) {
disableButton(caller, 'disable');
}
var that = this;
var updating = false;
this.callback = function() {}
var LayerID = document.getElementById(layer);
this.update = function(passData) {
if (updating == true) {
return false;
}
updating = true;
var AJAX = null;
if (window.XMLHttpRequest) {
AJAX = new XMLHttpRequest();
} else {
AJAX = new ActiveXObject("Microsoft.XMLHTTP");
}
if (AJAX == null) {
alert("Your browser doesn't support AJAX.");
return false
} else {
AJAX.onreadystatechange = function() {
if (AJAX.readyState == 4 || AJAX.readyState == "complete") {
if (caller) {
disableButton(caller, 'enable');
}
LayerID.innerHTML = AJAX.responseText;
delete AJAX;
updating = false;
that.callback();
}
}
var timestamp = new Date();
var uri = passData + '&timestamp=' + (timestamp * 1);
AJAX.open("POST", url, true);
AJAX.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
AJAX.setRequestHeader("Content-length", uri.length);
AJAX.setRequestHeader("Connection", "close");
AJAX.send(uri);
return true;
}
}
}

Categories