I am trying to pass a 2D array created in a Javascript file here:
Code.gs
function getPermits()
{
Logger.log('Starting permits');
var permits = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getDataRange().getValues();
Logger.log('Got permits: ' + permits [0][0]);
return permits;
}
And I call that function with a handler in this html file:
<script type="text/javascript">
function onSuccess(numUnread) {
alert('You have ' + numUnread[0][0]
+ ' unread messages in your Gmail inbox.');
document.getElementById("id2").innerHTML = numUnread[0][0];
}
function onFail(numUnread){
alert('Script failed!');
}
google.script.run.withSuccessHandler(onSuccess).getPermits();
google.script.run.withFailureHandler(onFail).getPermits();
</script>
The Logger.log('Got permits: ' + permits[0][0]);
call works perfect no matter what. However, while I can pass a 1D array in this manner and it works fine, passing a 2D array is causing this to fail. Why does this happen? Am I using improper syntax for this?
Thanks in advance
Stringify it as a JSON object, then you can pass just a String, which works fine:
return JSON.stringify(permits);
And on HTML:
function onSuccess(numUnread) {
numUnread = JSON.parse(numUnread);
Related
I am having problems with my Unity3D calling Firebase Functions function. My code is actually copied from https://firebase.google.com/docs/functions/callable.
My function code is following: (just copied this file actually)
https://github.com/firebase/quickstart-js/blob/a579893cfa33121952aeed9069c1554ed4e65b7e/functions/functions/index.js#L44-L50
and in Unity I have this:
//Create the arguments to the callable function.
var data = new Dictionary<string, object>();
data["text"] = "message";
data["push"] = true;
//Call the function and extract the operation from the result.
var function = FirebaseFunctions.DefaultInstance.GetHttpsCallable("addMessage");
function.CallAsync(data).ContinueWith((task) => {
if (task.IsFaulted)
{
foreach (var inner in task.Exception.InnerExceptions)
{
if (inner is FunctionsException)
{
Debug.Log(inner.Message);
}
}
}
else
{
Debug.Log("Finished: " + task.Result.Data);
}
});
But I am getting this result:
Response is not valid JSON object.
What am I doing wrong?
Thank you for your help!!!
I was still working on that problem and suddenly it worked. I dont know why to be honest, because the could looks exactely the same and I did not change anything on that.
I did have this code working a few years ago and have recently come back to it, i have a javascript refreshing data on a web page. Im calling the server using json and receiving back what i think is ok.
My python database code, which seems to work fine.
cur = db.execute('select sensor_name, temp from cur_temps ORDER BY sensor_name')
return jsonify(cur.fetchall())
Received Json
[["BoilerRoom",24.94],["Cylinder1",49.94],["Cylinder2",42.38],["Cylinder3",41.88],["Sensor1",85],["SolidFuelFlow",59],["SolidFuelReturn",41.62]]
Im trying to get the number thats associated with Cylinder2 = 42.38
My js code that worked previously is as follows
<script type=text/javascript>
function get_temps() {
$.getJSON("_status",
function (data) {
$('#CylTop').text(data.Cylinder1 + "°")
$('#CylMid').text(data.Cylinder2 + "°")
$('#CylBot').text(data.Cylinder3 + "°")
$('#Solid_flow').text(data.SolidFuelFlow)
$('#Solid_return').text(data.SolidFuelReturn)
$('#BRoom').text(data.BoilerRoom);
console.log(data)
console.log(data.Cylinder1)
}
);
}
setInterval('get_temps()', 5000);
</script>
The console shows the (data) fine in the browser, its when i try and show anything else. ' console.log(data.Cylinder1) ' that shows undefined.
Im a newbie so im assuming some indexing needs to happen as its a array but im a bit lost.
Any guidance will be greatly appreciated.
Many Thanks
C Dabbs
You seem to be accessing the properties in the data as an object. As per the response, it is an array inside an array. So you will have to flatten it before accessing it the way you have it.
function get_temps() {
$.getJSON("_status",
function(data) {
let flattendData = data.reduce(function(acc, item) {
return Object.assign({}, acc, {
[item[0]]: item[1]
});
}, {});
$('#CylTop').text(flattendData.Cylinder1 + "°")
$('#CylMid').text(flattendData.Cylinder2 + "°")
$('#CylBot').text(flattendData.Cylinder3 + "°")
$('#Solid_flow').text(flattendData.SolidFuelFlow)
$('#Solid_return').text(flattendData.SolidFuelReturn)
$('#BRoom').text(flattendData.BoilerRoom);
console.log(flattendData)
console.log(flattendData.Cylinder1)
}
);
}
I'm trying to load 3 characters from 5 difference websites and a concatenate them into one string, even though I'm using a try & catch statement the strings say'uncaught reference error' and any codes with numbers cause a 'unexpected tokens error'. I'm using the P5.js framework at the moment but willing to try plain .js.
Thanks
My code:
var data;
function setup(){
var url = [];
url[0] = 'https://assess.joincyberdiscovery.com/challenge-files/clock-pt1?verify=NRpxYLm9hCkAkhy0OSjEPA%3D%3D.json'
url[1] = 'https://assess.joincyberdiscovery.com/challenge-files/clock-pt2?verify=NRpxYLm9hCkAkhy0OSjEPA%3D%3D.json'
url[2] = 'https://assess.joincyberdiscovery.com/challenge-files/clock-pt3?verify=NRpxYLm9hCkAkhy0OSjEPA%3D%3D.json'
url[3] = 'https://assess.joincyberdiscovery.com/challenge-files/clock-pt4?verify=NRpxYLm9hCkAkhy0OSjEPA%3D%3D.json'
url[4] = 'https://assess.joincyberdiscovery.com/challenge-files/clock-pt5?verify=NRpxYLm9hCkAkhy0OSjEPA%3D%3D.json'
try{
for (let i = 0; i < 5; i++){
data += loadJSON(url[i], gotData, 'jsonp') + ' '
}
} catch (data){
console.log('oh well');
}
}
function draw(){
createCanvas(400,400);
background(225);
text(data, 0, 200);
}
function gotData(data){
text(data, 100, 200);
}
From the P5.js reference:
Loads a JSON file from a file or a URL, and returns an Object. Note that even if the JSON file contains an Array, an Object will be returned with index numbers as keys.
This method is asynchronous, meaning it may not finish before the next line in your sketch is executed.
That last line explains what's going on: the loadJSON() function is asynchronous, which means it doesn't directly return anything. So lines like this don't make sense:
data += loadJSON(url[i], gotData, 'jsonp') + ' '
Please see the examples in the reference to understand how to use the loadJSON() function correctly, but basically you either need to use a callback function or you need to use the preload() function.
I want to log objects using log4javascript. For example consider the following code:
function LogObject() {
var blah = {
one: 42,
two: "486"
};
logger.Info(blah);
Assuming that logger is instance of log4javascript logger that is properly set up:
var logger = log4javascript.getLogger("InternalLogger");
var ajaxAppender = new log4javascript.AjaxAppender(url),
jsonLayout = new log4javascript.JsonLayout(false, false);
ajaxAppender.setLayout(jsonLayout);
ajaxAppender.addHeader("Content-Type", "application/json");
logger.addAppender(ajaxAppender);
I am expecting the result to the following: request payload contains array of messages first of which is my object serialized into JSON. What I see is array of messages first of which has string "Object object" (like toString() method was invoked). How can I achieve that?
JsonLayout formats the logging event (which includes log level, timestamp and logger name in addition to the log message(s)) as JSON rather than the log message, which is pretty much assumed to be a string. The reason for this is to avoid a dependency on a JSON library for older browsers; generating JSON for the simple, known data that JsonLayout deals with is no problem without a JSON library but handling arbitrary objects definitely requires one.
The workaround I'd suggest is simply to format the message before you pass it to the logging call:
logger.info( JSON.stringify(blah) );
We were following #Tim Down's suggestion
logger.info( JSON.stringify(blah) );
But we had performance issues since the JSON.stringify happens before logger.info is called, therefore it will always happen even if the logging level is set to ignore this log.
In order to work around this I wrote a new lazy layout so that the stringification only happens if the log is actually output. In order to be more flexible it also alows passing a function, in which case it outputs the result of running said function.
Usage:
logger.trace("Received ", widget, " which has ", () => countFrimbles(widget), ' frimbles');
Implementation:
function LazyFormatLayout() { }
LazyFormatLayout.prototype = new log4javascript.Layout();
LazyFormatLayout.prototype.format = function (loggingEvent) {
var time = loggingEvent.timeStamp.toTimeString().split(/\s/)[0];
var head = time + ' ' + loggingEvent.logger.name + ' [' + loggingEvent.level.name + '] - ';
var body = loggingEvent.messages.map(function (arg) {
try {
switch (typeof (arg)) {
case 'function':
return arg();
case 'object':
return JSON.stringify(arg);
}
}
catch (e) {
return '<<error while logging: ' + e.stack + '>>';
}
return arg;
}).join('');
if (!loggingEvent.exception)
return head + body;
return head + body + ' ==> Exception: ' + loggingEvent.exception.stack;
}
LazyFormatLayout.prototype.ignoresThrowable = function () { return false; };
LazyFormatLayout.prototype.toString = function () { return "LazyFormatLayout"; };
Question is somewhat dated, but a simple google search turned up this question and there seems to be a build-in way to log objects:
var log = log4javascript.getDefaultLogger();
log.info("log following object",{ data:5, text:"bla" });
output
12:49:43 INFO - log following object {
data: 5,
text: bla
}
Thanks to #asgoth, I am able to use AngularJS $http service to retrieve stock prices from Yahoo as described here: Cannot read response from AngularJS $resource JSONP get from Yahoo Finance
In the "getHistoricalPrice" function, it puts the price inside an array, which is inside an object. From inside that function, I am able to access the price and write it to console.
The function returns the object to where it is called from. From there, I can successfully write the entire object out to console. However, I cannot access the elements of this object. I tried many different ways, but still cannot access the data in the object. You can see the code at http://jsfiddle.net/curt00/LTazR/2/ or below:
angular.module('app', ['ngResource']);
function AppCtrl($scope, $http, $resource) {
var historical_price = getHistoricalPrice("AAPL", 'start date is hard coded', 'end date is hard coded');
console.log("after calling historical price: ", historical_price); // historical_price is an object and all of the correct data is outputted to console here, but I cannot access its elements directly from Javascript.
for(var key in historical_price) {
console.log("key =",key); // this outputs "key = list"
}
console.log("after calling getHistoricalPrice: ", historical_price.list[0][1]); // Cannot access this as browser console gives error: TypeError: Cannot read property '1' of undefined
console.log("after calling getHistoricalPrice: ", historical_price['list'][0][1]); // Cannot access this as browser console gives error: TypeError: Cannot read property '1' of undefined
console.log("after calling getHistoricalPrice: ", historical_price[0][1]); // Cannot access this as browser console gives error: TypeError: Cannot read property '1' of undefined
function getHistoricalPrice(symbol, start, end) {
var query = 'select * from csv where url=\'http://ichart.yahoo.com/table.csv?s=' + symbol + '&a=' + '11' + '&b=' + '19' + '&c=' + '2012' + '&d=' + '11' + '&e=' + '19' + '&f=' + '2012' + '&g=d&ignore=.csv\'';
var url = 'http://query.yahooapis.com/v1/public/yql?q=' + fixedEncodeURIComponent(query) + '&format=json&callback=JSON_CALLBACK';
var histData = {};
$http.jsonp(url, {timeout: 30000}).success(function(json) {
var list = [];
var result = json.query.results.row;
result.shift(); // remove the header (columns) row
angular.forEach(result, function(row) {
list.push([(new Date(row.col0)).getTime()/1000, parseFloat(row.col4)]);
});
list.sort(function(val1, val2) {
return val1[0] - val2[0];
});
histData.list = list;
console.log('Loaded historical data',histData.list[0][1],', for ' + symbol); // This works and gives the price
});
return histData;
}
var fixedEncodeURIComponent = function(str) {
return encodeURIComponent(str).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
};
}
Any help or suggestions to solve this problem is greatly appreciate!
It's a matter of timing.
In lines 12-14 you are trying to access histData.list before it has been populated. This is because this code is run before the success callback to the $http.jsonp function is executed.
Any code that depends on that callback being completed must be in the callback or in a function called in the callback.
See my answer on https://stackoverflow.com/a/13967709/1916258
A great way to debug the Yahoo api is using the YQL Console: http://developer.yahoo.com/yql/console/
Info about the different posibilities (which stock info) can be found on http://www.gummy-stuff.org/Yahoo-data.htm
Edit: there was still a problem with function fixedEncodeURIComponent. It should encode quotes (") too:
var fixedEncodeURIComponent = function(str) {
return encodeURIComponent(str).replace(/[!'()]/g, escape).replace(/\*/g, "%2A").replace(/\"/g, "%22");
};
BobS is right, you aren't timing things correctly. Also you declared fixedEncodeURIComponent after you had called it. This was resulting in an immediate error when I loaded up the jsfiddle.
While you were passing the callback through to your function correctly, you weren't actually calling it. I stripped out all the post processing of the json as you have some other errors involving the query and just implemented the callback so you can see it working.
After the request is finished and you're still in the success function you need to add
if(typeof(callback) === "function"){
callback();
}
This calls that function you passed in and runs it. Here is a working jsFiddle of it:
http://jsfiddle.net/LTazR/22/
I also updated a new variable i created call output so you can see it changing.
Thanks to everybody for providing suggestions.
I solved the problem by using AngularJS' $scope variable, such as $scope.symbol[user].price. I created this variable before calling the getHistoricalPrice function and then in that function, after the result is returned from $http.jsonp, I put the value into the $scope variable, as such:
$scope.symbol[user].price = row.col4;