Infinite recursion issue with Json object (using Java/Javascript) - javascript

I'm using Javascript/Java to query an MSSQL database, and then use the CachedRowSet received from the query to add some information to a Json object. Here's the code that's querying the database and adding the results to the object.
var sqlGetVariables = "SELECT MappingVariable.Id as Id, MappingVariable.Name AS Name, MappingVariable.Value AS Value FROM MappingGroup LEFT JOIN MappingVariable ON MappingGroup.Id = MappingVariable.MappingGroupId WHERE MappingGroup.Id = " + mappingGroupId + " AND MappingVariable.Id IS NOT NULL";
var resultVariables = uberfaceDB.executeCachedQuery(sqlGetVariables);
while (resultVariables.next()) {
var variableId = resultVariables.getObject("Id");
var variableName = resultVariables.getObject("Name");
var variableMapping = resultVariables.getObject("Value");
jsonArray["Segments"][seg]["Variables"][variableName] = {};
jsonArray["Segments"][seg]["Variables"][variableName]["Mapping"] = variableMapping;
}
The issue I'm having is that there's something goofy going on with the last line where I assign "variableMapping" to the Json object. The line of code executes just fine, but when I go to iterate through the Json object later, I get stuck in an infinite recursion that keeps cycling through "class" "package" and "specificationversion".
Here's the code I'm using to iterate through the object.
function echoJson (jsonArray, strStuff) {
var strJson = "" + strStuff;
for (var item in jsonArray) {
logger.error(strJson + " --> " + item);
echoJson(jsonArray[item], strJson + " --> " + item);
}
}
The logger.error function is built in to the application I'm coding in (called Mirth Connect). It simply outputs the message to a console for error/debugging purposes. Here's an example of what I would EXPECT to get with the echoJson function:
Segments --> MSH --> Segments --> PID --> Variables --> PatientFirstName --> Mapping --> variableMappingValue
But here's what I'm actually getting:
Segments --> MSH --> Segments --> PID --> Variables --> PatientFirstName --> Mapping --> class --> package --> specificationVersion --> class --> package --> specificationVersion --> class --> package --> specificationVersion...
It continues repeating the "class --> package --> specificationVersion" portion infinitely until I stop the application.
If I replace the following line of code:
jsonArray["Segments"][seg]["Variables"][variableName]["Mapping"] = variableMapping;
With a hard coded string, like
jsonArray["Segments"][seg]["Variables"][variableName]["Mapping"] = "test";
Then it works without any problems.
Thanks in advance for taking a look at this!!

Your function echoJson is calling itself. This is called recursion. From here, "the first thing when calling a function recursively is that you need to make sure that there is some form of exit condition where the function will not call itself recursively." It appears that your function does not have an exit condition. In other words, before calling echoJson inside echoJson, check first if you ought to.
function echoJson (jsonArray, strStuff) {
var strJson = "" + strStuff;
for (var item in jsonArray) {
logger.error(strJson + " --> " + item);
if (isGoodAndNice(jsonArray[item]))
echoJson(jsonArray[item], strJson + " --> " + item);
}
}

I found the solution, as explained on another programmer's blog.
There was an issue with the data type being stored in the CachedRowSet. I don't know the exact data type, but from what I gathered the "variableMapping" variable is a byte array, and I'm needing to add it to my Json object as a string. I had to do "new String(variableMapping)" to convert the array into a string, and that fixed my problem.
How I found the problem: I decided to try using JSON.stringify() to output my Json object, and received the following error:
Java class "[B" has no public instance field or method named "toJSON"
Googling that led me to the blog post I linked to above.

Related

foreach Statements with a function

ok I am trying to answer a question and learning to code. regarding an array and using foreach statements the function must remain as this "function animalNames" must stay somewhere but apparently, I am doing something wrong because I get it returned as undefined. even through it produces the correct array back could someone look at it and let me know what i have done wrong.
attached is a picture of the code and array and question that i answered. this is how i wrote my function.
const displayNames = [];
zooAnimals.forEach(function animalNames(element){
var display = "name: " + element.animal_name + ", " + "scientific: " + element.scientific_name
displayNames.push(display);
})
console.log(displayNames);
again i get the correct array back and the data looks correct...but animalNames comes back as undefined...i cannot remove this portion i am to keep it there but i do not know what to do with it.
try this, it defines a function animalNames as separate function
const displayNames = [];
const zooAnimals = [
{animal_name:"Jackel",scientific_name:"Canine"}
]
function animalNames({animal_name, scientific_name}){
return `name: ${animal_name}, scientific: ${scientific_name}`
}
zooAnimals.forEach((element)=>{
displayNames.push(animalNames(element));
})
console.log(displayNames);
I believe you are following this challenge. In this case, make sure to read the instructions properly:
The zoos want to display both the scientific name and the animal name in front of the habitats.
Use animalNames to populate and return the displayNames array with only the animal name and scientific name of each animal.
displayNames will be an array of strings, and each string should follow this pattern: "name: {name}, scientific: {scientific name}"
So from the instructions you are expected to create a function animalNames() that creates an array named displayNames and returns this array from within your function animalNames(). The array displayNames contains strings of the sturcture name: animal_name, scientific: scientific_name.
// you could set zooAnimals as a required parameter in your function
// but as it is defined in the same file you can access it directly as well
function animalNames() {
const displayNames = [];
// you have to do the forEach on zooAnimals here
zooAnimals.forEach(animal => displayNames.push(`name: ${animal.animal_name}, scientific: ${animal.scientific_name}`))
// return an array
return displayNames;
}
The way you did it, the function animalsName() is an anonymous function that only exists within the zooAnimals.forEach() call. Therefore, it is undefined.

Cannot add custom fields to a contact using Google App Scripts

I'm trying to teach myself Google app scripts and I've run into a problem I can't figure out. I have a script that gets data from a user form in google sheets and uses that data to create contact.
I am able to create contact and put it in the right group.
The trouble begins when I try and put a custom field on the contact and populate the custom field with data.
I get the following error:
TypeError: Cannot read property 'setLabel' of undefined
at createPrimaryContact(Code:82:9)
at createContacts(Code:27:24)
I've tried following along with the documentation at:
https://developers.google.com/apps-script/reference/contacts/custom-field without any success.
function createPrimaryContact(contactsApp, data, group, groupName) {
var contact = contactsApp.getContact(data.emailAddy);
if (contact == null) {
var contact = contactsApp.createContact(
data.fName,
data.lName,
data.emailAddy
);
if (data.tel !== "") {
contact.addPhone(ContactsApp.Field.MOBILE_PHONE, data.tel);
}
if (data.addy !== "") {
var addyString =
data.addy + " , " + data.cty + " , " + data.st + " " + data.postcode;
contact.addAddress(ContactsApp.Field.HOME_ADDRESS, addyString);
}
}
var group = contactsApp.getContactGroup(groupName);
group.addContact(contact);
var searchName = data.fName + " " + data.lName;
var contacts = contactsApp.getContactsByName(searchName);
var field = contacts[0].getCustomFields()[0];
field.setLabel("Opportunity Name"); //this is line 82 that is generating the error mentioned above.
field.setValue(data.oName);
return { addyString };
}
I can't figure out what the problem is, even after many web searches later.
Can you see what I'm doing wrong ?
Any links or recommendations would be appreciated.
If you are trying to .getCustomFields() and set a label, it implies that there are already custom fields present in your contact. If there are no custom fields available, the .getCustomFields() method will return an empty array. If you are trying to access the empty array as you do it here:
var field = contacts[0].getCustomFields()[0];
The var field will be equal to undefined, because there is no entry at position 0. That's why it is throwing the TypeError.
To solve this issue, just use the .addCustomField(label, content)method to create a custom field.
Applying it to your case:
var searchName = data.fName + " " + data.lName;
var contacts = contactsApp.getContactsByName(searchName);
contacts[0].addCustomField("Opportunity Name", data.oName)
Documentaion can be found here.

"The property or field 'Id' has not been initialized. It has not been requested..." when trying to access GUID of Library in SharePoint via JavaScript

I am trying to access the ID of Library using client-side object model in SharePoint 2013. But I am getting error as:
The property or field 'Id' has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
Below is my code:
var context = SP.ClientContext.get_current();
var web = context.get_web();
var items = SP.ListOperation.Selection.getSelectedItems(context);
var currentLibrary = web.get_lists().getById(SP.ListOperation.Selection.getSelectedList(context));
context.load(currentLibrary, 'id'); // Tried with 'Id' but still throws error
console.log(currentLibrary);
console.log("currentLibrary.get_id = " + currentLibrary.get_id()); // THROWS ERROR!
What am I doing wrong here?
The error:
The property or field 'Id' has not been initialized. It has not been
requested…
occurs since List object has not been requested.
Use SP.ClientContext.executeQueryAsync method to execute the current pending request asynchronously on the server
A working example:
var context = SP.ClientContext.get_current();
var web = context.get_web();
var listId = SP.ListOperation.Selection.getSelectedList(context);
var list = web.get_lists().getById(listId);
context.load(list, 'Id'); //tell SharePoint to load List Id property
context.executeQueryAsync( //submit query to the server
function(){
console.log("ID:" + list.get_id()); //process result in success callback
},
function(sender,args){
console.log(args.get_message()); //handle error in error callback
}
);
my issue happened to be a silly one, the column I was returning was originally created with the name Requestor_DisplayName, and later changed to Employee_DisplayName so when using:
oListItem.get_item('Employee_DisplayName');
I got the >
"The property or field 'Id' has not been initialized. It has not been requested…" error
The issue had nothing to do with the SP.ClientContext.executeQueryAsync method itself...
When I changed the code to:
oListItem.get_item('Requestor_DisplayName');
It ran with out issue. You can use SP CAML Query Helper Online to inspect your your list and columns (as well as build CAML Queries) this is how I discovered my issue:
Hope this helps someone in the future!
Thanks.
SG.
Well back again editing this answer as today made another discovery about this error message similar in concept, I did not realize SharePoint will trim your column names after 32 Characters in length...
I got the exact same error message as before in the Developers Tool > debug console (IE f12) but about a different column of course.
"The property or field 'Operations_Approver1_Display_Name' has not been initialized. It has not been requested…"
I was left scratching my head after checking column names in list settings as I had in my JSOM, the column name was "Operations_Approver1_Display_Name" (Yes I was once a COBOL developer so I like long and Meaningful Names LOL)
oListItem.get_item('Operations_Approver1_Display_Name');
All seemed to check out, I thought "Well maybe I have a type in original column name and don't remeber fixing it" So of course I naturally opened up, SP CAML Query Helper Online (man I lobe this tool, yes the b was on purpose LOL).
This is how I discovered that SharePoint has a limit of 32 Characters for column names, just wanted to update this answer since it is highly ranked on search. As you can see in the screenshot below that the InternalName name of the column has been cut short by one character from its "Title" column name (Leave it to me to make this Name 33 characters long just 1 over the limit)
using Vadim answer:
var oItem ='';
function retrieveWebSite() {
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function(){
var clientContext = new SP.ClientContext.get_current();
this.oWebsite = clientContext.get_web();
clientContext.load(this.oWebsite);
var lstObject = oWebsite.get_lists().getByTitle('Listname');
oItem = lstObject.getItemById(5);
clientContext.load(oItem);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);
});
}
function onQuerySucceeded(sender, args) {
var look = oItem.get_item('LookupColumnName').get_lookupValue();
var title = oItem.get_item('Title');
var id = oItem.get_id();
alert("Loook up column value: "+look);
alert("Title column: "+title);
alert("Id column value: "+id);
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
you are looking for ids then do like this:-
var context = SP.ClientContext.get_current();
var web = context.get_web();
var items = SP.ListOperation.Selection.getSelectedItems(context);
for (var i = 0; i < items.length; i++) {
var id= items[i].id;
}
Thanks :)

Javascript 2D Array Not Returning Results as Expected

I have an array of arrays declared as the following:
var rangeValues = [[0.001, 0.01], [0.0000001, 0.000001]];
This array is used to fill the values of a drop down, since I essentially need a tuple for each drop down item's value. I proceed to access the values of the drop down with the following:
rangeTuple = document.getElementById('rangeSelection').value;
console.log(rangeTuple);
selectedMinRange = rangeTuple[0];
selectedMaxRange = rangeTuple[1];
console.log(selectedMinRange + " | " + selectedMaxRange[1]);
And I receive the following output:
0.001,0.01
0 | .
In my understanding (albeit limited with JS :) ), rangeTuple should be an array with two items in it. When rangeTuple is logged, it looks correct. However, when I try and assign the items in this tuple to a pair global variables, the values are not the ones I expect.
Any help is appreciated,
The value of an input is always a string. You will need to split that string to use it in the way you want:
rangeTuple = document.getElementById('rangeSelection').value;
console.log(rangeTuple);
// split it
rangeTuple = rangeTuple.split(",");
selectedMinRange = rangeTuple[0];
selectedMaxRange = rangeTuple[1];
console.log(selectedMinRange + " | " + selectedMaxRange);

How to access a Django many-to-many model, from Javascript?

Given a Django template variable with a many-to-many model, is it possible to pass that to a Javascript function, and access it?
(What I'm trying to get, is a list of the groups, including pk, that the current user belongs to).
For example, if I have a user jsmith that belongs to two groups, alpha and beta:
<html>
<script type="text/javascript">
mangle_data("{{ user.name }}", "{{ user.groups }}", "{{ user.groups.all }"");
</script>
</html>
function mangle_data(username, groups, all) {
alert("username = " + username); // works. output = "jsmith"
alert("user.groups = " + groups); // output = "django.db.models.fields.related.ManyRelatedManager object"
alert("all = " + all); // output = "[Group alpha; Group beta;]"
}
In all cases, the parameter passed to Javascript, is a single flattened string. Ideally, I'd get an object, or even a list that contained both group names, and group pk.
Granted, I could find the pk of a group, given its name - but that's a lot more steps. If I can get the data from the Django template directly into Javascript, it would be much cleaner.
What about serializing user.groups in a context variable?
If you serialize these to JSON, you can easily retrieve parse it from your page's JS.
How I wound up solving this, was to use a Context Processor to format the data, and pass it to a template variable:
context_processors.py
def site_settings(request):
if request.user.is_authenticated():
user_groups = "+".join(['{"id":%s, "name":"%s"}' %
(grp['id'], grp['name']) for grp in rquest.user.groups.values()])
else:
user_groups = ''
return {'USER_GROUPS': user_groups, }
template.html
<html>
<script type="text/javascript">
mangle_data("{{ USER_GROUPS|safe }"");
</script>
</html>
handle_data.js
function mangle_data(groups) {
var groups_json = '[' + groups.split('+').join(',') + ']';
var groups_OBJ = JSON.parse(groups_json); // this is now a Javascript object.
}

Categories

Resources