Im writing a function to export data pulled from C# to a csv file in JavaScript. The data is trying to be passed into an active webpage with live data. The goal is to export said data from C# string to the clients window hence the transfer to JavaScript (if my understanding is right). Then the JavaScript function in the page will download to the users window.
My issue is why am I have the invalid export data, please provide an array of objects output when I think I provide it one?
C# Code:
protected string test()
{
MyRequest request = new MyRequest();
request.Id = "TEST";
// Cant post this class but this is what I do
var tmp = new ExistingClassOfMine();
// pulls the data from the existing class through GetResponse();
// Then convert to json string
string data = JsonConvert.SerializeObject(tmp.GetResponse(request));
// Data found from breakpoint: {"Slot1":[{"Name":"TJ", "ID":"123"},{"Name":"Joe","ID:456"}], "TotalCount":2}
return data;
}
JavaScript:
function exportToExcel() {
console.log("Exporting to Excel");
isExporting = true;
const fileName = 'NameList';
const exportType = 'csv';
var data = <%=this.test()%>;
var readData = data["Slot1"];
var myArray = [];
// Followed a stack article to create this
for (var i in readData) {
myArray.push(readData[i]);
}
// Logging stuff for debugging
console.log("Data from C#");
console.log(data);
console.log(typeof (data));
console.log("Data we want to export");
console.log(readData);
console.log("Parsed Data?");
console.log(myArray);
// fails here with the error Invalid export data, please provide an array of objects
// which I thought I did with my for loop up a few lines
window.exportFromJSON({myArray, fileName, exportType});
isExporting = false;
}
function onRequestStart(sender, args) {
if (isExporting) {
args.set_enableAjax(false);
}
}
Log output:
Look, your triying to change the name of the key which is sent to exportFromJSON. The right way to name the key is data no myArray.
Change:
myArray
to
data
or assign myArray to data key
window.exportFromJSON({data:myArray, fileName, exportType});
Related
I am working on a Google Data Studio community connector, and I am trying to display only one field to start with. All of the code is in the code.gs file, except getAuthType() and isAdminUser() is in Auth.gs.
The issue is that once getData() is called, getFields() returns an empty object. Here is the log:
It looks like getSchema() is working correctly, here is the log from that function:
Here is the getFields() function:
function getFields() {
var fields = cc.getFields();
var types = cc.FieldType;
fields
.newDimension()
.setId('device')
.setName('Device')
.setType(types.TEXT);
return fields;
}
Here is getData():
function getData(request){
console.log('getData request', request);
request.configParams = validateConfig(request.configParams);
console.log('getFields()', getFields(), typeof getFields());
var requestedFields = getFields().forIds(
request.fields.map(function(field){
return field.name;
})
);
try{
console.log('start request');
var apiResponse = fetchDataFromApi(request);
var data = formatData(apiResponse, requestedFields);
}catch (e){
cc.newUserError()
.setDebugText('Error fetching data from API. Exception details: ' + e)
.setText(
'The connector has encountered an unrecoverable error. Please Try again later.'
)
.throwException();
}
return {
schema: requestedFields.build(),
rows: data,
}
}
getSchema():
function getSchema(request){
var schema = {schema: getFields().build()};
console.log(schema);
return schema;
}
The community connector is initialized outside of all functions in the same file:
var cc = DataStudioApp.createCommunityConnector();
I looked through the documentation, but I cannot find anything that would cause getFields() to return an empty object, based off what I have. Any thoughts?
I thought that getFields() returning an empty object was causing my app to display the fields incorrectly, but the issue was that the data I was passing to the app was in the incorrect format.
getFields() isn't useful until it is called with build() (i.e. getFields().build() )
I think it is expected behavior to receive an empty object for getFields() alone.
I've a image input in my webpage and input's output (File object) is saved inside the Question class. questionArr is a array of Question objects
let questionsArr = []; // Array of Question
class Question {
constructor(id) {
this.id = id;
this.image = false;
}
}
when the input value of image input changes, following function calls.
const handleImages = evt => {
let id = evt.target.id; // quizCoverImg or a integer (0,1,...)
const file = evt.target.files[0];
if (file && file.type.startsWith("image/")) {
if (id == "quizCoverImg") {
coverImage = file; // declared in top of the code
// console.log(coverImage) => File {name: "cat.png", lastModified ...}
// Returns a file object, which is correct
} else {
questionsArr[id].image = file;
// console.log(questionsArr[id].image) => File {name: "cat.png", lastModified ...}
// Returns a file object, which is correct
}
}
};
To this point everything works fine. Problem arise when I use above variables somewhere eles
const somewhereElse = () => {
console.log(coverImage); // File {name: "cat.png", lastModified ...} ✔
console.log(typeof coverImage); // object ✔
console.log(questionsArr[0].image); // C:\fakepath\cat.jpg ❓ should return a file object as mentioned above
console.log(typeof questionsArr[0].image); // string ❓
}
I know FileReader() exist, but I want to figure out why I'm getting two different outputs here.
Issue occurred in svelte#3.22.2
Edit 1: Places where questionArr used
This add Question to array
const addQuestion = () => {
const q = new Question(n);
questionsArr = [...questionsArr, q]; // because I'm using svelte :)
n++;
};
Then used in above handleImage()
The key difference is in the toString() method that affects what you are looking at. There is not much context to help debug the details of exactly how you are running this and how you are inspecting the values.
When you have selected a file in a form file input, the browser converts the path to a "fakepath" so that while the script can access the selected file, it cannot learn about the user's directory structure. The filename/path is a reasonable default toString result when trying to inspect/print the file object.
i'm currently working with rendering some graphs on a web mvc project. The graphs already render on my machine when i'm debugging the code, but the moment I publish it on the IIS of my QA server, I get the following error on console
TypeError: JSON.parse(...).forEach is not a function
Here's the a snippet of the code I'm currently working
ajaxPostConstancy.done(function (html) {
Utils.Alerts.HideGif();
var data = {};
var category = [];
var colors = [];
JSON.parse(html).forEach(function (e) {
category .push(e.date);
colors.push(e.color);
data[e.date] = e.data1;
})
....
any ideas of what's going on?
Edit: the html var inside the JSON.parse is te string returned by this code
public async Task<string> GetCompositionGraph(string contract, string methodName)
{
string preFormat = null;
try
{
string method = _configuration["Position:method:" + methodName];
PositionBL _bl = new PositionBL(Request, Response, _baseUri, method);
object model = await _bl.PostCompositionGraph(contract);
preFormat = JsonConvert.SerializeObject(model);
}
catch(Exception ex)
{
ViewBag.error = ex.Message;
}
return preFormat;
}
edit 2: the content of html variable which is generated by the code on the first edit:
html content:
[{"color":"#162ECB","date":"20","data1":1122954.8708},{"color":"#E03473","date":"00","data1":1323061.6168},{"color":"#CE029D","date":"26","data1":29982.2271}]
and this picture is the result I get from the JSON.parse when I debug my website
Edit 3: Visual input
The explorer console when the sites is deployed on my localhost for debugging
The explorer console while checking the site published on QA server
Edit 4: So i narrowed it down to the fact that the error comes when I debug the websit in Release mode, so that's kind of a step foward
If preformat returns null or an object forEach() will throw an error.
ajaxPostConstancy.done(function (html) {
Utils.Alerts.HideGif();
var data = {};
var category = [];
var colors = [];
var parsedDatas = JSON.parse(html)
if (Array.isArray(parsedDatas)) {
parsedDatas.forEach(function (e) {
// logic here
});
} else {
console.warn('This is not an array : ', html)
}
...
The forEach() method calls a function once for each element in an array while the JSON.parse() makes the html an object.
I have this function below:
const displayUserPhotoAndName = (data) => {
if(!data) return;
// add your code here
clearNotice();
};
the data parameter is an API from https://randomuser.me/api/
The assignment has the instructions below:
Locate the displayUserPhotoAndName function and do the follwing within it:
After the first if(!data) return; statement that terminates the
function if the expected data parameter is not provided, create a
statement that de-structures the data parameter and obtains the
results property from it;
Create a second statement in the next line that de-structures the
results variable you just created, and obtain the first item from it
(it is an Array! See https://randomuser.me/api/). Your de-structured
array item should be declared as profile. This represents the profile
data for the user gotten from the API call that you want to display
in your app.
Step 3
Still within the displayUserPhotoAndName function :
Set the HEADING element in your app to display the title, last name,
and first name (in that order, separated by a single space) of the
user profile returned by the API.
Set the IMG in your app to display the large photo of the user
profile returned by the API.
what I have done:
const displayUserPhotoAndName = (data) => {
if(!data) return;
// add your code here
const {results} = data.results;
const [profile] = results;
const {title, First, Last} = results;
const [,,,,,,,,,picture] = results;
const largeImage = picture.large;
userImage.src = largeImage;
headerUserInfo.innerText = title + ' ' + First + ' ' + Last;
clearNotice();
displayExtraUserInfo(profile);
};
The error I get:
You have not de-structured the 'results' property from the 'data'
parameter passed to 'displayUserPhotoAndName' function
I'm in dire need of assistance. Thanks in anticipation
I'm not going to provide you the full answer but giving you the hints:
const { results } = data
const { profile } = results
console.log(profile)
Can be written as:
const { results: { profile } } = data
console.log(profile)
Here are my some posts from which you may go further:
destructure an objects properties
how is this type annotation working
why source target when destructuring
I'm using Protobuf.js to write a hook for sails.js to be able to send message encoded by protocol buffers by socket.io.
Say I have a proto scheme Message.proto:
message Message{
required string message = 1;
optional string user = 2;
optional int32 id = 3;
}
And I'm getting an object from database as data:
data = {
message: 'Hello',
user: 'johnDoe',
id: 90,
createdAt: '2015-10-16T10:15:39.837Z',
updatedAt: '2015-10-16T10:15:39.837Z'
};
And I have a sails hook with code:
var ProtoBuf = require("protobufjs"),
Reflect = ProtoBuf.Reflect,
builder = ProtoBuf.newBuilder(),
protoModels;
...
// This method overrides socket.io broadcast call for sails.js models pubSub:
augmentModels: function () {
for (var identity in app.models) {
var protobufSchemeName = app.models[identity].protobufSchemeName;
// protobufSchemeName is the file name of the sheme
if (protobufSchemeName) {
ProtoBuf.loadProtoFile(path.join(app.config.appPath, app.config.protobuf.folder, protobufSchemeName + ".proto"), builder);
app.models[identity].broadcast = function (roomName, eventName, data, socketToOmit) {
var dataToSend = protoModels[protobufSchemeName].encode(???HERE???); //HERE I SHOULD PUT THE MODIFIED DATA WITH THE ONLY NECESSARY FIELDS
app.sockets.broadcast(roomName, eventName, dataToSend.toBuffer(), socketToOmit);
};
}
protoModels = builder.build();
}
}
I can't pass data directly this way: protoModels[protobufSchemeName].encode(data) because it will cause an error: this+"#"+keyOrObj+" is not a field, because data contains extra fields;
So here goes the question: what is the easiest and correct way to save to dataToSend only fields that are in the scheme (Message.proto)?
P.S. I know that should have something with Reflection and they say you can do it like this way:
var TPlayer = builder.lookup("Game.Player"); // instance of ProtoBuf.Reflect.Message
var fields = TPlayer.getChildren(ProtoBuf.Reflect.Message.Field); // instances of ProtoBuf.Reflect.Message.Field
fields.forEach(function(field) {
//Filter it here
});
But I can't figure it out how to to reach lookup method from protoModels. And maybe there is the way to use Builder's isMessageField method to filter fields in data?
We still have a builder there so the solution is quite the same as in example:
...
augmentModels: function () {
for (var identity in app.models) {
var protobufSchemeName = app.models[identity].protobufSchemeName;
if (protobufSchemeName) {
ProtoBuf.loadProtoFile(path.join(app.config.appPath, app.config.protobuf.folder, protobufSchemeName + ".proto"), builder);
app.models[identity].broadcast = function (roomName, eventName, data, socketToOmit) {
var fields = builder.lookup(protobufSchemeName).getChildren(ProtoBuf.Reflect.Message.Field).map(function (f) {
return f.name;
}); //Here are the fieldnames of the scheme as an array
var dataToSend = protoModels[protobufSchemeName].encode(_.pick(data, fields)).toBuffer();
app.sockets.broadcast(roomName, eventName, dataToSend, socketToOmit);
};
}
protoModels = builder.build();
}
}
Another way is to override emit/broadcast methods like I did in the hook below:
P.S. If anyone will find this useful:
I've made a Protobuf Serialization Hook for Sails.js. Contributions are welcome!