WKWebView evaluateJavaScript returns wrong JavaScript Object - javascript

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 :

Related

Object variable property undefined even if it's not

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
});

How to check if boolean is passed as string?

So in below code if i pass ancillaryProductInd as boolean code works, but when I pass it as a string, it does not work. In my understanding the below code should only work when I pass "false" string value and throw error on boolean. Any idea what is the issue here ?
main.ts
request
var rxInfos = [{
"ancillaryProductInd": "false",
"indexID": "eyJrZXkiOiIEOHdpNUpNWmR3PT0ifQ=="
}]
function subQuestionsHandler(rxInfos, data) {
const subQuestionArray = [];
rxInfos.forEach((rxInfo) => {
const subQuestion = {
question: []
};
if (rxInfo.ancillaryProductInd !== undefined && rxInfo.ancillaryProductInd === "false") {
subQuestion.question = data;
subQuestionArray.push(subQuestion);
}
});
return subQuestionArray;
}
subQuestionsHandler(rxInfos, [{
some data
}]);
Your example code works as expected with a string value "false" and doesnt run the if block when a boolean is used. See my example:
var rxInfos = [
{
ancillaryProductInd: "false",
indexID: "eyJrZXkiOiIEOHdpNUpNWmR3PT0ifQ=="
},
{
ancillaryProductInd: false,
indexID: "eyJrZXkiOiIEOHdpNUpNWmR3PT0ifQ=="
}
];
function subQuestionsHandler(rxInfos, data) {
const subQuestionArray = [];
rxInfos.forEach(rxInfo => {
const subQuestion = {
question: []
};
if (
rxInfo.ancillaryProductInd !== undefined &&
rxInfo.ancillaryProductInd === "false"
) {
console.log("no error");
subQuestion.question = data;
subQuestionArray.push(subQuestion);
} else {
console.log("throw error");
}
});
return subQuestionArray;
}
subQuestionsHandler(rxInfos, [
{
test: ""
}
]);

Javascript associate dynamic array

I have a JSON response as below;
"finalData" :
[
{
"message":"Display success msg",
"status":["SUCCESS"]
},
{
"message":"Display fail msg",
"status":["FAIL"]
}
]
Now this is dynamic. Meaning, I can either get just "SUCCESS" or just "FAILURE" or both
So finalData can be an array of 0 or 1 or 2 objects
My question is what is the best way to access the "message" property of the array dynamically. i.e. I want to know if finalData.message belongs to
"status":["SUCCESS"] or "status":["FAILURE"]
So kind of associate the array
var d = { "finalData": [{ "message": "Display success msg", "status": ["SUCCESS"] }, { "message": "Display fail msg", "status": ["FAIL"] }] }
var status = 'SUCCESS';
var message = d.finalData.filter(e => e.status == status).map(e => e.message)[0];
document.write(message);
ES5 code:
var d = { "finalData": [{ "message": "Display success msg", "status": ["SUCCESS"] }, { "message": "Display fail msg", "status": ["FAIL"] }] }
var status = 'SUCCESS';
var message = d.finalData.filter(function(e) {
return e.status == status;
}).map(function(e) {
return e.message;
})[0];
document.write(message);
Check whether each code is there, then just use an if statement to continue conditionally, depending on the status.
var status = finalData[0].status;
var succeeded = status.indexOf('SUCCESS') >= 0;
var failed = status.indexOf('FAIL') >= 0;
if(succeeded && failed) {
// code when both are true
}
else if(succeeded) {
// code for only success
}
else if(failed) {
// code for only failure
}
else {
// code if neither are present
}

parsing error JSON.parse(unexpected token u)

var storage = chrome.storage.local;
var cachedStorage = {};
this is js file.It shows unexpected token u.even though I've done parsing correctly.and it also shows unexpected token for for its html source page.can any one suggest me how to sort this out.
var defaultStorage = [{
savedPatterns: JSON.stringify([
[{
"en": "English"
}, {
"it": "Italian"
}, "25", true],
[{
"en": "English"
}, {
"la": "Latin"
}, "15", false]
]),
}];
error occurs here unexpected token u
function createPattern() {
console.log('createPattern begin');
var patterns = JSON.parse(S('savedPatterns'));
var srce = [],
trg = [],
prb = [];
console.log(S('savedPatterns'));
console.debug(S('savedPatterns'));
var translator = document.getElementById('translatorService');
var service = translator.children[translator.selectedIndex].value;
srce[0] = document.getElementById('sourceLanguage');
srce[1] = srce[0].children[srce[0].selectedIndex].value;
srce[2] = srce[0].children[srce[0].selectedIndex].text;
trg[0] = document.getElementById('targetLanguage');
trg[1] = trg[0].children[trg[0].selectedIndex].value;
trg[2] = trg[0].children[trg[0].selectedIndex].text;
prb[0] = document.getElementById('translationProbability');
prb[1] = prb[0].children[prb[0].selectedIndex].value;
patterns.push([
[srce[1], srce[2]],
[trg[1], trg[2]],
prb[1],
false,
service
]);
saveBulk({
'savedPatterns': JSON.stringify(patterns)
}, 'Saved Pattern');
console.log('createPattern end');
}
function S(key) {
return cachedStorage[key];
}
function loadStorageAndUpdate(callback) {
storage.get(null, function(data) {
console.log('data: ' + data + ' : ' + JSON.stringify(data));
var d = {};
if (!data || JSON.stringify(data) == '{}') { // in this case, storage was not initialized yet
console.log('setting storage to defaultStorage (stringified): ');
console.log(JSON.stringify(defaultStorage));
storage.set(defaultStorage);
d = defaultStorage;
} else {
d = data;
}
cachedStorage = d;
if (!!callback) {
callback(d);
}
});
}
Error Unexpected token comes when JSON.parse fails and depending on character (u in this case), you can assume its cause.
u is if value is undefined
o is if value is object
try {
JSON.parse(undefined)
} catch (ex) {
document.write(ex.message + "<br/>")
}
try {
JSON.parse({})
} catch (ex) {
document.write(ex.message)
}
You can try something like this:
function s(key) {
var obj = {
foo: "foo",
bar: "bar"
}
var v = null;
try {
v = JSON.parse(obj[key]);
} catch () {
v = obj[key];
}
return v;
}
function main() {
var v = s("foo");
}
Please refer following post for more information. Uncaught SyntaxError: Unexpected token with JSON.parse
You're trying to parse undefined. When you call JSON.parse(), you're passing in S('savedPatterns'), which in turn tries to access cachedStorage['savedPatterns'], but that starts as undefined, which you can't parse. You could just initialize your cachedStorage as:
var cachedStorage = {
savedPatterns: JSON.stringify([])
};

create a PhoneCall record in Crm using Javascript

When I try to create a PhoneCall record in Crm using Javascript, I got following error message, I cannot figure out the reason, any help?
{
"readyState": 4,
"responseText": "{\r\n\"error\": {\r\n\"code\": \"\", \"message\": {\r\n\"lang\": \"en-US\", \"value\": \"Error processing request stream. The property name 'from' specified for type 'Microsoft.Crm.Sdk.Data.Services.PhoneCall' is not valid.\"\r\n}\r\n}\r\n}",
"status": 400,
"statusText": "Bad Request"
}
"error"
"Bad Request"
<code>
var fromArray = [];
var FromActivityParty = {
PartyId:
{
Id: Xrm.Page.context.getUserId(),
LogicalName: "systemuser"
},
ActivityId: {
Id: TeamId,
LogicalName: "team"
},
ParticipationTypeMask: { Value: 1 }
};
fromArray[0] = FromActivityParty;
var toArray = [];
var ToActivityParty = {
PartyId:
{
Id: Xrm.Page.data.entity.getId(),
LogicalName: "account"
},
ActivityId: {
Id: TeamId,
LogicalName: "team"
},
ParticipationTypeMask: { Value: 2 }
};
toArray[0] = ToActivityParty;
var PhoneCall = {
from: fromArray,
to: toArray,
Subject: "Create a phonecall record",
OwnerId: fromArray,
PhoneNumber: phoneNumber
}
CrmRestKit.Create("PhoneCall", PhoneCall)
.fail(function (xhr, status, errorThrown)
{
console.log(JSON.stringify(xhr, null, 4));
console.log(JSON.stringify(status, null, 4));
console.log(JSON.stringify(errorThrown, null, 4));
})
.done(function (data, status, xhr) {
console.log(JSON.stringify(data, null, 4));
}
</code>
If you're using the REST endpoint, you need to add the To and From using the relationship with the activity party entity.
Here is the code I use:
var phoneCall = {};
phoneCall.phonecall_activity_parties = [
new ActivityParty(2, "systemuser", "GUID"),
new ActivityParty(1, "contact", "GUID")
]; //2 = 'To' 1 = 'From'
//TODO: Call CREATE using phoneCall object.
function ActivityParty(typeMask, logicalName, partyId) {
if (partyId && partyId[0] === '{') {
partyId = partyId.substring(1, partyId.length - 1);
}
this.PartyId = {
LogicalName : logicalName,
Id : partyId
};
this.ParticipationTypeMask = {
Value : typeMask
};
}
Well the error message sounds pretty clear to me.
"from" seems not to be a valid property name for the phone call type.
A quick guess: Have you tried to use "From" with an upper case? I see that your other properties are written this way.

Categories