Object variable property undefined even if it's not - javascript

I'm trying to read the property of a json object using variables. If I use variables i get error, while if I use properties it works.
JSON:
{
"homebrews": {
"books": {
"title": "text."
},
"cards": {
"template": {
"id": 0,
"name": "myName"
}
}
}
}
Function called
createHomebrew('card');
function:
function createHomebrew(type) {
var homebrew;
$.getJSON('/data-files/templateHomebrew.json', function(json) {
var id = type + 's'; // cards
homebrew = json.homebrews[id].template // json.homebrews[id] is undefined
});
Instead
console.log(json.homebrews.cards.template); // Object { id: 0, name: "myName"}

Solved, since setting id = "cards" worked, for some reason the function called with createHomebrew('card') didn't recognize card as a String, even though console.log(typeof id) returned String. So I added id = id.toString();
function createHomebrew(type) {
var homebrew;
$.getJSON('/data-files/templateHomebrew.json', function(json) {
var id = type + 's';
id = id.toString();
homebrew = json.homebrews[id].template
});

Related

WKWebView evaluateJavaScript returns wrong JavaScript Object

I'm making a hybrid app and using WKWebView.
I need to pass a JavaScript Object to the emitter command to open the edit dialog.
Here is my code:
let statDict: [String: Any] = [
"income" : account.stat.income,
"expense" : account.stat.expense,
"summary" : account.stat.summary,
"incomeShorten" : account.stat.incomeShorten,
"expenseShorten" : account.stat.expenseShorten,
"summaryShorten": account.stat.summaryShorten
]
let accountDict: [String: Any] = [
"id": account.id,
"name": account.name,
"description": "",
"icon": account.icon,
"currency": account.currency,
"customer_contact_id": account.customer_contact_id ?? 0,
"is_archived": account.is_archived,
"sort": account.sort,
"create_datetime": account.create_datetime,
"update_datetime": account.update_datetime ?? "",
"stat": statDict
]
let accountData = try! JSONSerialization.data(withJSONObject: accountDict, options: JSONSerialization.WritingOptions(rawValue: 0))
guard let accountString = String(data: accountData, encoding: .utf8) else {
return
}
webView.evaluateJavaScript("function parse(string){ return JSON.parse(string)}") { result, error in
if error == nil { // this is returns correct staff
}
}
webView.evaluateJavaScript("parse('\(accountString)')") { object, error in
if error == nil {
let object = object as AnyObject
print("parse object \(object)")
webView.evaluateJavaScript("window.emitter.emit('openDialog', 'Account', \(object))") { (result, error) in
if error == nil { // here the error "Unexpected token '='..."
webView.evaluateJavaScript("window.emitter.on('closeDialog', function(){ window.webkit.messageHandlers.emitterMessage.postMessage('closeDialog'); })") { (result, error) in
if error == nil {
}
}
webView.evaluateJavaScript("window.emitter.on('createAccount', function(){ window.webkit.messageHandlers.emitterMessage.postMessage('createAccount'); })") { (result, error) in
if error == nil {
}
}
} else {
print(error as Any)
}
}
}
}
The \ (object) returned by the function looks like this:
{
"create_datetime" = "2021-08-24 19:19:28";
currency = RUB;
"customer_contact_id" = 1;
description = "";
icon = "";
id = 7;
"is_archived" = 0;
name = "Business 111";
sort = 0;
stat = {
expense = 0;
expenseShorten = 0;
income = 300000;
incomeShorten = 300K;
summary = 300000;
summaryShorten = 300K;
};
"update_datetime" = "";
}
but it should look like this:
{
create_datetime: "2021-08-24 19:19:28",
currency: "RUB",
customer_contact_id: 1,
description: "",
icon: "",
id: 7,
is_archived: false,
name: "Business 111",
sort: 0,
stat: {
expense: 0,
expenseShorten: "0",
income: 300000,
incomeShorten: "300K",
summary: 300000,
summaryShorten: "300K"
},
update_datetime: ""
}
With such an object, the compiler generates the error Unexpected token '='. Expected an identifier as property name.
The parse (string) function will return the correct object if you run it in the js compiler, but in swift the output is not correct.
How to bring an object to the correct form?
You are trying to pass the string interpolated representation of a Swift object (NSMutableDictionary in your case) to Javascript.
Instead you can directly pass the JSON representation to JS context since JSON is a native Javascript object it should do what you are trying to achieve :
/// Sample emitter function that consumes object an prints its local parameter, also assigns it to sample object value in window.
self.webView?.evaluateJavaScript(
"window.emitter = (sampleObject) => { window.sampleObject = sampleObject;setTimeout(function(){console.log('Hello sampleObject : ',sampleObject.name); }, 7000);}"
) { result, error in
if error == nil { // this is returns correct staff
}
}
self.webView?.evaluateJavaScript("window.emitter(\(accountString));") { result, error in
if error == nil {
print("parse object \(result)")
}
}
Result in window :

Create Dynamic json in javascript

I want to create a dynamic json string.
Json looks like:
{
"getHostedPaymentPageRequest": {
"merchantAuthentication": {
"name": "x345dsfg",
"transactionKey": "456tyYYUU7876"
},
"transactionRequest": {
"transactionType": "authCaptureTransaction",
"amount": "20.00",
"profile": {
"customerProfileId": "123456789"
}
}
}
}
The values in json like name, transactionKey, transactionType, amount, customerProfileId will vary for different users.
I am following this method to create json:
var getHostedPaymentPageRequest = new Object();
var merchantAuthentication = {};
merchantAuthentication.name = "x345dsfg";
merchantAuthentication.transactionKey = "456tyYYUU7876";
var transactionRequest = {};
transactionRequest.transactionType = "";
transactionRequest.amount = "20.00";
var profile = {};
profile.customerProfileId = "123456789";
transactionRequest.profile = profile;
getHostedPaymentPageRequest.merchantAuthentication = merchantAuthentication;
getHostedPaymentPageRequest.transactionRequest = transactionRequest;
getHostedPaymentPageRequest = JSON.stringify(getHostedPaymentPageRequest);
But its not giving back the right values.
How do I make a valid json in the desired format?
The provided code (if we add a console.log on getHostedPaymentPageRequest) displays the following result (which is how it should behave):
{
"merchantAuthentication": {
"name": "x345dsfg",
"transactionKey": "456tyYYUU7876"
},
"transactionRequest": {
"transactionType": "",
"amount": "20.00",
"profile": {
"customerProfileId": "123456789"
}
}
}
The only meaningful difference that I see between this and the expected result is that in your expected result the JSON starts with
{
"getHostedPaymentPageRequest": {
...
}
}
For that you have to wrap your getHostedPaymentPageRequest object in another object. So instead of doing this:
getHostedPaymentPageRequest = JSON.stringify(getHostedPaymentPageRequest);
add braces like this:
getHostedPaymentPageRequest = JSON.stringify({ getHostedPaymentPageRequest });
You can use this as a reference..
I've split the object based on what it's doing and I've obtained two separate objects: merchantAuthentication and transactionRequest. For each object I created a separate function who return an individual object, because in the future you might want to add more fields therefore it will be easier to you to know were to place them :)
function createMerchantAuthObject() {
let merchantAuth = {};
merchantAuth.name = "x345dsfg";
merchantAuth.transactionKey = "456tyYYUU7876"
return merchantAuth;
}
function createTransactionRequestObject() {
let transactionRequest = {};
transactionRequest.transactionType = "authCaptureTransaction"
transactionRequest.amount = "20.00"
transactionRequest.profile = {};
transactionRequest.profile.customerProfileId = "123456789"
return transactionRequest;
}
function getHostedPaymentPageRequest() {
let request = {}
request.getHostedPaymentPageRequest = {}
request.getHostedPaymentPageRequest.merchantAuthentication = createMerchantAuthObject();
request.getHostedPaymentPageRequest.transactionRequest = createTransactionRequestObject();
return request; // used in order to print the whole object
}
const myObject = getHostedPaymentPageRequest();
console.log(myObject);
This solved my problem:
var money=document.getElementById("amount").value;
var customerprofileid = "1926616706";
var merchantAuthentication = {};
merchantAuthentication.name = "ser555";
merchantAuthentication.transactionKey = "fgrtyujjj";
var getHostedPaymentPageRequest = {
"getHostedPaymentPageRequest": {
"merchantAuthentication": {
"name": merchantAuthentication.name,
"transactionKey": merchantAuthentication.transactionKey
},
"transactionRequest": {
"transactionType": "authCaptureTransaction",
"amount": money,
"profile": {
"customerProfileId": customerprofileid
}
},
"hostedPaymentSettings": {
"setting": [ {
"settingName": "hostedPaymentIFrameCommunicatorUrl",
"settingValue": "{\"url\": \"http://localhost:52965/IframeCommunicator.html\"}"
}]
}
}
};
getHostedPaymentPageRequest = JSON.stringify(getHostedPaymentPageRequest);

Combining multiple objects to create JSON object in Node

I am trying to construct my own JSON object from multiple online image/photography sources. The below code should explain what I am trying to accomplish:
var searchUnsplash = require('./apis/unsplash');
var searchFlickr = require('./apis/flickr');
function combineObjs(callback) {
var obj = {}
var key = 'item';
obj[key] = [];
searchFlickr.searchFlickr(searchTerm, searchCount, searchPage,
function (callback) { // each API call is in a separate file with these functions exported
obj[key].push(flickrObj); // this does not work
// console.log(flickrObj) // this works
});
searchUnsplash.searchUnsplash(searchTerm, searchCount, searchPage,
function (callback) {
obj[key].push(unsplashObj);
// console.log(unsplashObj)
});
console.log(obj)
}
combineObjs();
The goal is to end up with a JSON object like below:
["item": {
"id": 1,
"title": 2,
"content": 3,
"source": "flickr"
},
"item": {
"id": 1,
"title": 2,
"content": 3,
"source": "unsplash"
}]
etc, which I can use to power my front end.
I am a beginner to javascript and I am just working off what I have learned in tutorials and articles, so I might be using the wrong approach entirely for what I am aiming to achieve. Happy to take any pointers
search function:
function searchUnsplash(term, count, page, callback) {
request(`https://api.unsplash.com/search/photos/?per_page=${count}&page=${page}&query="${term}"&client_id=KEY&`,
function searchResult(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body)
for ( var i = 0; i < info.results.length; i++) {
obj = {
id: `us-${info.results[i].id}`,
}
callback(obj);
}
}
})
}
module.exports.searchUnsplash = searchUnsplash;
First, your intended result is not correct. You can't name "item" the individual array entries. A corrected and working example would be this one.
[ {
"id": 1,
"title": 2,
"content": 3,
"source": "flickr"
},
{
"id": 1,
"title": 2,
"content": 3,
"source": "unsplash"
}]
Second, you mistake JSON for your data structure. JSON is just the text notation. So, let's see first how to build a suitable data array.
let results = [];
results.push( { id:1, title:2, content:3, source:"flickr" });
results.push( { id:2, title:4, content:6, source:"unsplash" });
And then with JSON.stringify(results) will code your results into JSON.
Finally, you mix up the aynchronous calls in your code with synchronous invocations. You need to save the results on the callback of the individual functions, that is when you really obtain the responses asynchronously. Also, you need to count the pending results and invoke the final callback when all done.
So, putting all the pieces together, in a contrived fake example, we just invoke twice the search functions and so we callback when two results are combined.
function combineObjs(callback) {
let results = [];
function partialResult(obj) {
results.push(obj);
if (results.length=2) callback(results);
};
searchFlickr(searchTerm, searchCount, searchPage, partialResult);
searchUnsplash(searchTerm, searchCount, searchPage,partialResult);
}
combineObjs( function(results) { console.log(JSON.stringify(results)) });
This is excessive but it would work. It can be used over and over and over again. :D
Run the snippet to see a result
class JSONBuilder
{
constructor(contents=null)
{
if(!contents)
{
//Private objecy hash that isn't publicly accessible
var objectHash = {};
//Get stashed item
this.GetItem = function(key)
{
if(!key) throw new Error("Null or Underfined Key Passed.");
let value = objectHash[key];
if(!value) throw new Error(`Key : ${key} Not Found in JSON objectHash`);
return value;
}
//Set an item in the objecy hash
this.SetItem = function(key, value)
{
if(!key) throw new Error("Null or Underfined Key Passed.");
if(!value) throw new Error("Null or Underfined Key Not Found.");
objectHash[key] = value;
}
//Remove item from the hash
this.DeleteItem = function(key)
{
if(!key) throw new Error("Null or Underfined Key Passed.");
if(!objectHash[key]) throw new Error(`Key : ${key} Not Found in JSON objectHash`);
objectHash.DeleteItem(key);
}
//Turn items into a JSON object
this.Build = function()
{
return JSON.stringify(objectHash);
}
}
else
{
//If a string is passed as a paremeter, reconstruct from that
try
{
objectHash = JSON.parse(contents);
}
catch(Err)
{
console.log("Parsing of JSON Content Failed.");
throw Err;
}
}
}
}
class Item
{
constructor(id, source, content, title)
{
this.Id = id;
this.Source = source;
this.Content = content;
this.Title = title;
}
}
let builder = new JSONBuilder();
let itemContainer = [];
itemContainer.push(new Item(1, 'flicker', 'stuff', 'item1'));
itemContainer.push(new Item(2, 'flicker', 'morestuff', 'item2'));
builder.SetItem('items', itemContainer);
console.log(builder.Build());

Javascript array.find() only finds within first instance

I have the following object array:
var data = {};
data.type = {
"types": [{
"testA": {
"testVar": "abc",
"testContent": "contentA"
}
}, {
"testB": {
"testVar": "def",
"testContent": "contentB"
}
}]
};
What I'm trying to do is find the value of testContent based on finding the object it belongs by searching it's parent and sibling:
/* within the data, find content where parent is testA and sibling testVar is "abc" */
var findSet = data.type.types.find(function(entry) {
return entry['testA'].testVar === "abc";
});
console.log(findSet['testA'].testContent); /* returns string "contentA" as expected */
This works fine for first object but fails to find next object, giving error:
Cannot read property 'testVar' of undefined
var findSet = data.type.types.find(function(entry) {
return entry['testB'].testVar === "def"; /* Cannot read property 'testVar' of undefined */
});
console.log(findSet['testB'].testContent);
How else could I find what's needed?
Here's a fiddle to test the output
var data = {};
data.type = {
"types": [{
"testA": {
"testVar": "abc",
"testContent": "contentA"
}
}, {
"testB": {
"testVar": "def",
"testContent": "contentB"
}
}]
};
var findSet = data.type.types.find(function(entry) {
return entry['testA'] && entry['testA'].testVar === "abc";
});
console.log(findSet['testA'].testContent);
var findSet = data.type.types.find(function(entry) {
return entry['testB'] && entry['testB'].testVar === "def"; /* Cannot read property 'testVar' of undefined */
});
console.log(findSet['testB'].testContent);
just check if your entry exist before testing his attribute.

Ajax in spring return java.lang.stackoverflow error

Controller returns Java.lang.stackoverflow error when calling from ajax.
My Ajax function is like this.
$.ajax({
url: '${pageContext.servletContext.contextPath}/exam/test',
type: 'POST',
data: 'examName='+examName,
success: function(response) {
alert(response);
}
});
Controller
#RequestMapping(value = "/exam/test", method = RequestMethod.POST)
public #ResponseBody List<SchoolExam> examsTest(#ModelAttribute(value = "examName") String examName, BindingResult result, WebRequest webRequest, ModelMap map, Principal principal) {
User loggedUser = userService.getUserByUserName(principal.getName());
***********************
Some code here
***********************
List<SchoolExam> schoolExams = new ArrayList<SchoolExam>();
for (School school : schools) {
if (student) {
Set<Student> students = school.getStudents();
for(Student std : students) {
if (std != null && !std.isEmpty()) {
schoolExams.add(new SchoolExam(std, true));
}
}
}
if (teacher) {
Set<Teacher> teachers = school.getEvents();
for (Teacher tchr : teachers) {
if (loggedUser.equals(tchr.getOwner())) {
schoolExams.add(new SchoolExam(tchr, true));
}
}
}
if (exam) {
Set<Exam> exams = school.getCampaigns();
for (Exam exam1 : exams) {
if (loggedUser.equals(exam1.getOwner())) {
schoolExams.add(new SchoolExam(exam1, true));
}
}
}
}
return schoolExams;
}
SchoolExam
public SchoolExam(Object obj, boolean editable) {
this.editable = editable;
if (obj instanceof Student) {
Student student = (Student) obj;
this.id = student.getId();
this.name = student.getName();
this.type = Constants.Student;
this.obj = student; // <-- This is causing issue here
}
if (obj instanceof Teacher) {
Teacher teacher = (Teacher) obj;
this.id = teacher.getId();
this.name = teacher.getName();
this.type = Constants.Teacher;
this.obj = teacher; // <-- This is causing issue here
}
if (obj instanceof Exam) {
Exam exam = (Exam) obj;
this.id = exam.getId();
this.name = exam.getName();
this.type = Constants.Exam;
this.obj = exam; // <-- This is causing issue here
}
}
Issue:
This is working fine when a form is submit then I can use all data by running foreach loop in jsp but when I tried to return list in my function then ajax work successfully and it also return me response
response in ajax
[
{
"id":"2123244",
"name":"UK School",
"type":"exam",
"editable":true,
"obj":
{
"id":"2123244",
"authorizationRequired":false,
"owner":
{
"id":"5676764554",
"company":
{
"id":"55435435345",
"name":"SchoolTest Software",
"enabled":true,
"size":3,
"sector":null,
"phone":"1231231232",
"schoolFees":5000,
"location":"US",
"users":
[
{
"id":"5676764554",
"company": // <-- Start Repeating here
{
"id":"55435435345",
"name":"SchoolTest Software",
"enabled":true,
"size":3,
"sector":null,
"phone":"1231231232",
"schoolFees":5000,
"location":"US",
"users":
[
{
"id":"5676764554",
"company": // <-- Repeating again
{
"id":"55435435345",
"name":"SchoolTest Software",
"enabled":true,
"size":3,
"sector":null,
"phone":"1231231232",
"schoolFees":5000,
"location":"US",
"users":
[
{
"id":"5676764554",
"company":// <-- It keeps repeating it self
but when I tried to print list value in controller it's only printing one value.
e.g:
for (SchoolExam schoolExam : schoolExams) {
System.out.println("Name: " + schoolExam.getName());
System.out.println("ID: " + schoolExam.getId());
Exam exam = (Exam) schoolExam.getObj();
System.out.println("Exam Name: " + exam.getName());
}
Output:
Name: UK School
ID: 2123244
Exam Name: UK School
Note:
If I comment obj line then everything works fine for me.
e.g:
this.obj = student;
this.obj = teacher;
this.obj = exam;
But I need to use this to get data as It contain data for different table.
Please find this file for error log that I'm getting in console.
So, What I'm doing wrong which cause this issue or I need to use any other way to prevent this issue.
Any suggestion or link will be helpful.
According to your error log file, you have a cyclic recursion in your Java classes. So Jackson try to serialize some objects infinitely.
The main problem is here : com.school.model.Company_$$_javassist_8["users"]->org.hibernate.collection.PersistentSet[0]->com.school.model.User["company"]->com.school.model.Company_$$_javassist_8["users"]
You have a property users containing a set of User containing a property ompany containr a Company containing the same users. So infinity loop.

Categories