SDK GridRefresh Call Throwing Exception - javascript

I'm going to try to explain this as best I can, please feel free to ask for clarifications as required.
Using IE10, CRM Online with RU12.
I am playing about with subgrids and getting them to refresh. Consider the following script, which I have nicked wholesale from MSDN (and wrapped in a try/catch block)
function start() {
try {
var controls = Xrm.Page.ui.controls.get(isSubGrid);
if (controls.length > 0) {
var subGridNames = "";
for (var i in controls) {
controls[i].refresh();
subGridNames += (" - " + controls[i].getName() + "\n");
}
alert("The following subgrids were refreshed: \n" + subGridNames);
}
else {
alert("There are no subgrid controls on the current form.");
}
}
catch (ex) {
alert(ex);
}
}
function isSubGrid (control)
{
return control.getControlType() == "subgrid";
}
Nothing special going on there - get all controls of type subgrid (this returns 10 elements as expected) and call refresh() on them.
However this is consistently failing on the first call to refresh().
The exception details is fairly straightforward
TypeError: Unable to get property 'Refresh' of undefined or null reference
Which suggests that the control[i] is null when called in the loop at this point here
for (var i in controls) {
controls[i].refresh();//error thrown here - suggests controls[i] is null
subGridNames += (" - " + controls[i].getName() + "\n");
}
However I can see that it isn't null (and has the method refresh as expected).
I can make it work by using setInterval
function waitAndThenRefresh(gridname) {
var grid = Xrm.Page.ui.controls.get(gridname);
var intervalId = setInterval(function () {
if (grid === null || grid._control === null || grid._control._element === null) {
return;
}
if (grid._control._element.readyState === 'complete') {
window.clearInterval(intervalId);
if (grid != null) {
grid.refresh();
}
}
}, 1000);
}
But that is pretty hideous, not to mention does not explain with the SDK call doesn't work as expected.
So I guess the question is: has anyone else seen this issue? Or can you replicate it on another instance? Am I missing something? There is nothing in the SDK that suggests you need to defer calling refresh until the inner control's readyState is complete?

The code block you are using,
for (var i in controls) {
controls[i].refresh();
subGridNames += (" - " + controls[i].getName() + "\n");
}
should be replaced with the following:
for (var i in controls) {
i.refresh();
subGridNames += (" - " + i.getName() + "\n");
}
or:
for (var i = 0; i < controls.length; i++) {
controls[i].refresh();
subGridNames += (" - " + controls[i].getName() + "\n");
}
You are getting the exception because controls[i] is undefined in your case, i being the control (the element of the array controls).

I asked a CRM-buddy of mine. He said that the issue depends on the new refreshment Engine. According to him, it's sort of a bug but not really. If I got it right, the refresh has been reengineered to accommodate the new perpetual saving functionality.

Related

How to set the return value of a function based on a condition?

I am a beginner at Javascript and I am creating a form. The thing is I have a function that returns the value of the checkboxes (to check if they were checked or not) when the user submits his or her answer. I want to give the user a message if he / she does not select a value in the checkbox (not an error message). I have tried the following Javascript code:
function loopForm() {
var cbResults = " ";
var error = " You did not select a value";
for (var i = 0; i < myForm.elements.length; i++) {
if (myForm.elements[i].type == "checkbox") {
if (myForm.elements[i].checked == true) {
cbResults += myForm.elements[i].value + "<br />";
}
}
}
if (cbResults != undefined) {
return cbResults;
} else {
return error;
}
}
But when I submitted the results without checking the checkbox (once again this is not an error message) the message was not shown. (I stored the message in the error var). Can anyone help me solve this problem ?? Any help would be greatly appreciated. Please note that this is not my Full Code but just a portion of it.

ServiceNow: JavaScript TypeError: Cannot read property of undefined

I am writing an onChange Client Script in ServiceNow and having issues with a Javascript error on the front end client. I keep getting a TypeError: Cannot read property 'u_emp_name' of undefined. the variable seems to vary as at one point i was getting the u_pos_office undefined as well, however the data is pulling correctly and there are no performance impacts on my code functionality.
What could be causing the type error?
Script is below:
function onChange(control, oldValue, newValue, isLoading) {
var billNum = g_form.getReference('u_billet',findBilletInfo);
console.log('Emp Name: ' + billNum.u_emp_name);
console.log('OFfice: ' + billNum.u_pos_office);
console.log('Career Field: ' + billNum.u_pos_career_field);
if (isLoading || newValue == '') {
return;
}
if (oldValue != newValue){
findBilletInfo(billNum);
}
function findBilletInfo(billNum){
console.log('Bill Num' + billNum);
console.log('encumbent' + billNum.u_emp_name);
var empName = billNum.u_emp_name;
var empNameStr = empName.toString();
console.log(empName);
console.log(empNameStr);
g_form.setValue('u_organization_office',billNum.u_pos_office);
g_form.setValue('u_encumbent',billNum.u_emp_name);
g_form.setValue('u_old_career_field',billNum.u_pos_career_field);
g_form.setValue('u_old_career_specialty',billNum.u_pos_career_specialty);
g_form.setValue('u_old_occupational_series',billNum.u_pos_series);
g_form.setValue('u_old_grade',billNum.u_pos_grade);
g_form.setValue('u_old_work_category',billNum.u_pos_category);
g_form.setValue('u_old_job_title',billNum.u_pos_title);
g_form.setValue('u_losing_rater',billNum.u_emp_rater_name);
g_form.setValue('u_losing_reviewer',billNum.u_emp_reviewer_name);
}
}
It appears to be an error here
var billNum = g_form.getReference('u_billet',findBilletInfo);
==> console.log('Emp Name: ' + billNum.u_emp_name);
In this case billNum is undefined since getReference is run asynchronously. See the documentation for the function.
This means that it won't guarantee a return value immediately or at all. This is probably why you get a record sometimes and not others.
You can move these debug logs within your findBilletInfo callback to check the values
if (isLoading || newValue == '') {
return;
}
var billNum = g_form.getReference('u_billet',findBilletInfo);
function findBilletInfo(billNum) {
console.log('Bill Num' + billNum);
console.log('encumbent' + billNum.u_emp_name);
console.log('OFfice: ' + billNum.u_pos_office);
console.log('Career Field: ' + billNum.u_pos_career_field);
...
}
If you debug in Firefox or Chrome, you should be able to just log the object to the console to explore the entire object at once.
function findBilletInfo(billNum) {
console.log(billNum);
...
}
The output will look like something like this in the console and you can see all fields at once.

Array gives errors after JSON function

I'm trying to check if the twitch stream is online or offline and if so change a background colour. If i check without the array and just put in the name it works, but with the array it doesn't (I don't have a lot of knowledge of JSON).
function test() {
var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];
for (var i = 0; i < twitchChannels.length; i++) {
console.log(i + " " + twitchChannels[i]);
$.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannels[i] + '?client_id=XXXX', function(channel) {
console.log(i + " " + twitchChannels[i]);
if (channel["stream"] == null) {
console.log("Offline: " + twitchChannels[i])
document.getElementById(twitchChannels[i]).style.backgroundColor = "red";
} else {
console.log("Online: " + twitchChannels[i])
document.getElementById(twitchChannels[i]).style.backgroundColor = "green";
}
});
}
}
Error: http://prntscr.com/i6qj51 inside the red part is what happens inside of json fuction
Your code is quite weak since you didn't manage the callback of every get you make.
Also you didn't check if:
document.getElementById(twitchChannels[i])
is null, since the exception clearly stated that you can't get :
.style.backgroundColor
from nothing.
Basic check VanillaJS:
if(!document.getElementById("s"))
console.log('id ' + twitchChannels[i] + ' not found in dom')
else
console.log('id ' + twitchChannels[i] + ' found in dom')
Also consider mixing JQuery with VanillaJS extremely bad practice; use proper JQuery method to access dom element by ID .
You should pass twitchChannel to the function because the var i is changing, this is an issue like others already mentioned: Preserving variables inside async calls called in a loop.
The problem is that you made some ajax call in a cicle, but the ajax calls are async.
Whey you get the first response, the cicle is already completed, and i==4, that is outside the twitchChannels size: that's why you get "4 undefined" on your console.
You can change your code in such way:
function test() {
var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];
for (var i = 0; i < twitchChannels.length; i++) {
executeAjaxCall(twitchChannels[i]);
}
}
function executeAjaxCall(twitchChannel){
$.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannel + '?client_id=XXXX', function(channel) {
console.log(twitchChannel);
if (channel["stream"] == null) {
console.log("Offline: " + twitchChannel)
$('#'+twitchChannel).css("background-color", "red");
} else {
console.log("Online: " + twitchChannel)
$('#'+twitchChannel).css("background-color", "green");
}
});
}
}
When console.log(i + " " + twitchChannels[i]); is called inside the callback function, the variable i has already been set to 4, and accessing the 4th element of array twitchChannels gives undefined since the array has only 4 elements.
This is because $.getJSON is a shorthand Ajax function which, as the name suggests, executes your requests asynchronously. So what actually happened is, based on the output you provided,
The loop is executed 4 times, and four Ajax requests have been sent.
The loop exits; i is already set to 4 now.
The ajax requests return; the callbacks are called, but the i value they see is now 4.
You can change the console.log inside your callback to something like console.log(i + " " + twitchChannels[i] + " (inside callback)"); to see this more clearly.
The correct result can be obtained by binding the current value of i to the closure.
function test() {
var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];
function make_callback(index) {
return function (channel) {
console.log(index + " " + twitchChannels[index]);
if (channel["stream"] == null) {
console.log("Offline: " + twitchChannels[index])
document.getElementById(twitchChannels[index]).style.backgroundColor = "red";
} else {
console.log("Online: " + twitchChannels[index])
document.getElementById(twitchChannels[index]).style.backgroundColor = "green";
}
}
}
for (var i = 0; i < twitchChannels.length; i++) {
console.log(i + " " + twitchChannels[i]);
$.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannels[i] + '?client_id=XXXX', make_callback(i));
}
}

receiving deserialize position error randomly when using rangy library

I have been having some issues with rangy.
the error i recieve is:
Error: Error in Rangy Serializer module: deserializePosition() failed: node
" has no child with index 3, 5"
I get this error when i pull serialized highlights from a database and try to deserialize them onto a web page. The really strange thing is most of the time the highlights are deserialized just fine and display on the page but at times they randomly disappear and I get the above mentioned error.
I used the chrome javascript debugger to track down the issue and
function deserializePosition(serialized, rootNode, doc) {
if (!rootNode) {
rootNode = (doc || document).documentElement;
}
var parts = serialized.split(":");
var node = rootNode;
var nodeIndices = parts[0] ? parts[0].split("/") : [], i = nodeIndices.length, nodeIndex;
while (i--) {
nodeIndex = parseInt(nodeIndices[i], 10);
if (nodeIndex < node.childNodes.length) {
node = node.childNodes[nodeIndex];
} else {
throw module.createError("deserializePosition() failed: node " + dom.inspectNode(node) +
" has no child with index " + nodeIndex + ", " + i);
}
}
return new dom.DomPosition(node, parseInt(parts[1], 10));
}
in this code block for some reason at the line
var node = rootNode;
even though rootNode = html, the variable node gets assigned 'text' sometimes and this causes the node.childNodes.length to be equal to 0 and an error is thrown. Any help would be much appreciated, thanks.

localStorage boolean triggers weird behavior

I'm having really strange problems with my code using localStorage...
I would post code either here or in jsfiddle but for it to work I need a bunch of resources and for some reason won't display correctly on jsfiddle.
For an example, you can view the webpage I have it hosted at: http://spedwards.cz.cc/new.html
When you check one (can be any value but lets say 1 for this purpose) of the checkboxes for any hero, click Generate (in the last section) and hit refresh, all of the heroes have their activity checked even though only the one that was checked prior to the refresh should remain checked.
When checking localStorage in the console, only the checked one will have true and all the others will be on false as well which makes it weird. If someone can explain why it's doing this and/or explain an error that I've obviously missed.
Below I will post some of the functions.
Storing everything:
function storage() {
var username = $('#username').val();
var password = $('#password').val();
if (typeof(Storage) != "undefined") {
// Store user's data
window.localStorage.setItem("username", username);
window.localStorage.setItem("password", password);
$.each(heroes, function(index,value){
window.localStorage.setItem("heroActive" + index, $('input#isActive' + index).is(':checked') );
window.localStorage.setItem("heroLevel" + index, $('input#level' + index).val() );
window.localStorage.setItem("heroPrestige" + index, $('input#prestige' + index).val() );
});
} else {
// Browser doesn't support
alertify.alert('<b>Your browser does not support WebStorage</b>');
}
}
Loading the values:
var username, password;
username = localStorage.getItem('username');
$('#username').val(username);
$.each(heroes, function(index,value){
if( localStorage.getItem('heroActive' + index) ){
$('input#isActive' + index).attr('checked', localStorage.getItem('heroActive' + index) );
} else {
$('input#isActive' + index).removeAttr('checked');
}
$('input#level' + index).val( localStorage.getItem('heroLevel' + index) );
$('input#prestige' + index).val( localStorage.getItem('heroPrestige' + index) );
});
The list that is causing problems:
var heroes = ["Black Panther","Black Widow","Cable","Captain America","Colossus","Cyclops","Daredevil","Deadpool",/*"Doctor Strange",*/"Emma Frost",
"Gambit","Ghost Rider","Hawkeye","Hulk","Human Torch","Iron Man","Jean Grey",/*"Juggernaut",*/"Loki","Luke Cage",/*"Magneto","Moon Knight",*/"Ms Marvel",
"Nightcrawler",/*"Nova","Psylocke",*/"Punisher","Rocket Raccoon",/*"Silver Surfer",*/"Scarlet Witch","Spider-Man","Squirrel Girl",/*"Star-Lord",*/"Storm",
/*"Sue Storm",*/"Thing","Thor","Wolverine"/*,"Venom"*/];
Additionally, the last entry (Wolverine) doesn't seem to be functioning correctly. For a starter clicking the label for its activity doesn't trigger the checkbox whereas all the others do. Other problems with this entry:
Doesn't trigger my errors.js file at all
errors.js:
$.each(heroes, function(index,value){
$('input#level' + index).change(function() {
var numbers = /^[0-9]+$/;
var val = $('input#level' + index).val();
if(val > 60) {
alertify.log("Hero " + value + " cannot be above Level 60!", "", 0);
$('#level' + index).addClass('error');
} else if( isNumeric(val) ) {
if( $('#level' + index).hasClass('error') ) {
$('#level' + index).removeClass('error');
}
} else {
alertify.log("Only numbers are accepted.");
$('#level' + index).addClass('error');
}
});
});
function isNumeric(num){
return !isNaN(num);
}
Anything stored in local storage returns as a string.
So if you stored fooo = false in local storage,
if(!fooo){
bar();
}
will never execute bar();
if(fooo){
bar();
}
will always execute bar(), since a string always is true, since the variable is not empty or false.
I've banged my head against this once as well. Kinda stupid, but hey. :)

Categories

Resources