Tableau json API WebConnector - javascript

I've written the following tableau webconnector to pull data from an internal API, using earthquakeUSGS.html as a guideline (https://github.com/tableau/webdataconnector). The API returns json (see code below). I've been using the "Web data connector simulator 2.0" and all has been going well. I get the correct Table, however, Im unable to "Fetch Table Data". As this is my first js script, Im very sure that is were the error is. To iterate through the data I used the answer from Korijn in this post Iterate through nested json object array
The Problem: Is probably with the js iterator over the json object. If anyone can take a look at the json (below), and have a look at my iterator, I would greatly appreciate it. This is what makes it impossible for me to fetch data.
test.js
(function() {
// Create the connector object
var myConnector = tableau.makeConnector();
// Define the schema
myConnector.getSchema = function(schemaCallback) {
var cols = [{
id: "prog",
alias: "PrognosisTime",
dataType: tableau.dataTypeEnum.string
}, {
id: "start",
alias: "Start",
dataType: tableau.dataTypeEnum.date
}, {
id: "val",
alias: "Value",
dataType: tableau.dataTypeEnum.float
}];
var tableSchema = {
id: "table",
alias: "187",
columns: cols
};
schemaCallback([tableSchema]);
};
// Download the data
myConnector.getData = function(table, doneCallback) {
$.getJSON("http://myapi.com/119%2C7777/Flattened?start=today&end=today&timeZone=CET&asOf=now&aggregation=None", function(resp) {
var feat = resp.features,
tableData = [];
tableData.push(
{"table":feat.properties.table}
);
// Iterate over the JSON object
//var SeriesId = feat.SeriesId
for(var i = 0; i <feat.DataPoints.length; i++){
var PrognosisTime = feat.DataPoints.PrognosisTime;
var Start = feat.DataPoints.Start;
var Value = feat.DataPoints.Value;
}
table.appendRows(tableData);
doneCallback();
});
};
tableau.registerConnector(myConnector);
// Create event listeners for when the user submits the form
$(document).ready(function() {
$("#submitButton").click(function() {
tableau.connectionName = "Neas"; // This will be the data source name in Tableau
tableau.submit(); // This sends the connector object to Tableau
});
});
})();
json from API
[
{
"SeriesId": 119,
"DataPoints": [
{
"PrognosisTime": null,
"Start": "2016-08-24T00:00:00",
"Value": 26.19
},
{
"PrognosisTime": null,
"Start": "2016-08-24T01:00:00",
"Value": 23.9
},
{
"PrognosisTime": null,
"Start": "2016-08-24T02:00:00",
"Value": 22.82
}
]
},
{
"SeriesId": 7777,
"DataPoints": [
{
"PrognosisTime": null,
"Start": "2016-08-24T00:00:00",
"Value": 36.39
},
{
"PrognosisTime": null,
"Start": "2016-08-24T00:15:00",
"Value": 28.81
},
{
"PrognosisTime": null,
"Start": "2016-08-24T00:30:00",
"Value": 24.28
}
]
}
]

The problem is this line:
var feat = resp.features
resp is an array from your JSON, there is nothing called features. So, simply iterate over resp (or feat = resp) and pull out your DataPoints array.

Related

Converting JSON data with pdfMake

I have a code snippet from bpampuch that converts JSON data into a pdf. It worked for me before, but when I linked my own local JSON file it stopped working. I'm not 100% sure of what fixes I need to do to get my own JSON data to be converted---I think it has something to do with the line data.jsonData.forEach (see below), but I'm not sure what else. Any thoughts on this?
JS snippet:
import $ from 'jquery';
import jsonData from "./test.json";
import pdfMake from 'pdfmake/build/pdfmake.min.js';
function _buildTableBody(data, cols) {
let body = [];
body.push(cols);
data.jsonData.forEach(function(row) { // reg obj doesn't have forEach
let dataRow = [];
cols.forEach(function(column) {
dataRow.push(row[column].toString());
})
body.push(dataRow);
});
return body;
}
function _table(data, cols) {
return {
table: {
headerRows: 1,
body: _buildTableBody(data, cols)
}
};
}
function _printFunc() {
var docDefinition = {
content: [
{ text: 'Dynamic Parts', style: 'header' },
_table(jsonData.d.results[0].Title, ['Title'])
]
};
pdfMake.createPdf(docDefinition).download(name + '.pdf');
console.log(docDefinition.content)
}
$("#pdf-trigger").on("click", _printFunc)
JSON snippet:
{
"d": {
"results": [
{
"FileSystemObjectType": 0,
"Id": 1,
"Title": "TitleHere",
"GoalRange": "3",
"Office": "Somewhere",
"Role": "FPSL",
"IsFilled": false,
"Employee": null,
"IsActive": true,
"Notes": null,
"ID": 1,
"Attachments": false
...etc
Your json file is clearly not in the same format as the demo. Try removing the .jsonData from the line you're having an issue with:
data.forEach(function(row) { // reg obj doesn't have forEach
And further down, you have this line
_table(jsonData.d.results[0].Title, ['Title'])
Leave it as an array
_table(jsonData.d.results, ['Title'])

Node.js loop through nested Javascript object

I want to have posts + attachments from Facebook so I can create a list of posts. The problem is that I want to put attributes: id, message and any attachment in a array for every post feed. I'm not sure whether I need to iterate objects inside a array or can I select the ID and get the related information.
Also I'm using async.waterfall() to get synchronous calls because I will make other calls that depend on the previous call.
I tried this to get the id, message and src url of attachment:
var async = require("async");
var graph = require('fbgraph');
async.waterfall([
getFeed,
getPostPicture,
], function (err, result) {
});
function getFeed(callback) {
graph.get("/.../feed" + "?fields=message,attachments&access_token=APPID|APPSECRET", function(err, res) {
callback(null, res);
});
}
function getPostPicture(arg1, callback) {
var feedData = arg1.data;
for(var i in feedData)
{
var id = feedData[i].id;
var message = feedData[i].message;
var feedAttachment = feedData[i].attachments
for (var j in feedAttachment)
{
var attachment = feedAttachment.data;
var attachmentURL = attachment[i].src;
for (var j in attachmentURL)
{
var attachmentURL = feedAttachment.src;
}
}
}
console.log(attachment);
}
Above will output:
[ { description: 'post message 1',
media: { image: [Object] },
target:
{ id: '...',
url: 'https://www.facebook.com/.../photos/a............/.../?type=3' },
title: 'Timeline Photos',
type: 'photo',
url: 'https://www.facebook.com/.../photos/a............/.../?type=3' } ]
Below is the response where I first called graph.get in the source code
and I need { data -> [message, id, attachments -> data[src] ]}
{
"data": [
{
"message": "post message 1",
"id": "..._...",
"attachments": {
"data": [
{
"description": "picture 1",
"media": {
"image": {
"height": 256,
"src": "https://scontent.xx.fbcdn.net/v/t1.0-9/..._..._..._n.png?oh=...&oe=...",
"width": 256
}
},
"target": {
"id": "...",
"url": "https://www.facebook.com/.../photos/a............/.../?type=3"
},
"title": "Timeline Photos",
"type": "photo",
"url": "https://www.facebook.com/.../photos/a............./..../?type=3"
}
]
}
},
{
"message": "Test status update 123",
"id": "..._..."
}
],
"paging": {
"previous": "https://graph.facebook.com/v2.8/.../feed?fields=message,attachments&format=json&since=...&access_token=...&limit=25&__paging_token=enc_...&__previous=1",
"next": "https://graph.facebook.com/v2.8/.../feed?fields=message,attachments&format=json&access_token=...&limit=25&until=...&__paging_token=enc_..."
}
}
When you are using the for loop in getPostPicture function, the i variable is actually the element in the array feedData, so you have to i.id or i.attachments and i.message. Also I think since you are using same j in 2 loops with one nested inside the other, it also won't work properly, so you might have to change that also, and explain you question with the kind of output you are expecting.

How to hide object property to display using angular ng-model?

I want to hide _id to display on UI using ng-model , I see alot of examples of filtering data using ng-repeat but i did not find angular solution to achieve this task using ng-model.How can hide _id property to display ?
main.html
<div ng-jsoneditor="onLoad" ng-model="obj.data" options="obj.options" ></div>
Ctrl.js
$scope.obj.data = {
"_id": "58a3322bac70c63254ba2a9c",
"name": "MailClass",
"id": "MailTask_1",
"createdBy": "tyuru",
"__v": 0,
"properties": [{
"label": "Java Package Name",
"type": "String",
"editable": true,
"binding": {
"type": "property",
"name": "camunda:class"
},
"$$hashKey": "object:29"
}],
"appliesTo": [
"bpmn:ServiceTask"
]
}
var json = {};
function loadCurrentUserAndTemplate() {
AuthService.getCurrentUser()
.then(function(resp) {
$scope.currentUser = resp.data.id;
// console.log($scope.currentUser);
userTemplate($scope.currentUser);
});
}
loadCurrentUserAndTemplate();
$scope.obj = {
data: json,
options: {
mode: 'tree'
}
};
var privateFields = removePrivateFields($scope.obj.data, ['_id', '__v']);
// add private fields back to $scope.obj.data before POST
var modifiedData = Object.assign({}, $scope.obj.data, privateFields);
function removePrivateFields(obj, props) {
var output = {};
props.forEach(function(prop) {
if (obj.hasOwnProperty(prop)) {
output[prop] = obj[prop];
delete obj[prop];
}
});
return output;
}
function userTemplate(user) {
// console.log('inside template',$scope.currentUser);
templateService.getUserTemplates(user)
.then(function(response) {
// console.log('userTemplate',response.data);
// console.log(response.data.length);
$scope.displayedTemplates = response.data;
if (response.data.length !== 0 && response.data !== null) {
$scope.obj.data = response.data[0];
}
}
you can create a function like removePrivateFields to strip the private fields from original object and attach them back to the modified object before submitting to server
// for testing
var $scope = { obj: {} };
var jsonData = {
"_id": "58a3322bac70c63254ba2a9c",
"name": "MailClass",
"id": "MailTask_1",
"createdBy": "tyuru",
"__v": 0,
"properties": [{
"label": "Java Package Name",
"type": "String",
"editable": true,
"binding": {
"type": "property",
"name": "camunda:class"
},
"$$hashKey": "object:29"
}],
"appliesTo": [
"bpmn:ServiceTask"
]
};
var privateFields = removePrivateFields(jsonData, ['_id', '__v']);
// private fields got removed form actual jsonData
$scope.obj.data = jsonData;
console.log($scope.obj.data);
// once edit
// add private fields back to $scope.obj.data before POST
var modifiedData = Object.assign({}, $scope.obj.data, privateFields);
console.log(modifiedData);
function removePrivateFields(obj, props) {
var output = {};
props.forEach(function(prop) {
if (obj.hasOwnProperty(prop)) {
output[prop] = obj[prop];
delete obj[prop];
}
});
return output;
}
It would be both more performant and along Angular best practices to instead delegate this functionality into your controller or the service fetching the object.
Ideally, you want to perform any object manipulation or formatting within an Angular service, but you could also do it within your controller (probably fine if you're just instantiating your JSON editor with mock data).

Getting an array of users that edited a page

I am working on a user script for a Wikia community ( http://c.wikia.com ) and I need to get array of users (and possibly revision IDs) of a page. I have come up with the following code but cannot seem to make it work. Any help would be appreciated.
Code:
var revisions = [];
$.getJSON('/api.php', {
action: 'query',
prop: 'revisions',
titles: mw.config.get("wgPageName"),
rvprop: 'user',
rvlimit: '50',
format: 'json'
}, function (result) {
for (var i = 0; i < 50; i++) {
var revision = result.query.pages.page[i].revisions.user;
revisions.push(revision);
}
alert(revisions);
});
The query result looks something like this:
{
"query": {
"pages": {
"421588": {
"pageid": 421588,
"ns": 0,
"title": "Community Central",
"revisions": [
{
"user": "Mhadick"
},
{
"user": "Nblonkenfeld"
},
…
]
}
}
},
…
}
You'll notice that pages is an object with property named after the page id of the current page "421588" (judging from your code, you might be looking at the XML version of the response, you have to look at the JSON). To work with that, you can use something like:
var users = [];
$.getJSON('/api.php', {
action: 'query',
prop: 'revisions',
titles: mw.config.get("wgPageName"),
rvprop: 'user',
rvlimit: '50',
format: 'json'
}, function (result) {
var revisions = result.query.pages[mw.config.get("wgArticleId")].revisions;
$.each(revisions, function(key, revision) {
users.push(revision.user);
});
alert(users);
});

Appending to JSON object using JavaScript

I'm building the JSON object using JavaScript. How would I inset the following data to the bottom of the stack:
"hello": { "label":"Hello", "url":"#hello" }
in to the following variable:
var ListData = {
"main": {
"label":"Main",
"url":"#main"
},
"project": {
"label":"Project",
"url":"#project"
},
"settings": {
"label":"Settings",
"url":"#settings",
"subnav":[
{
"label":"Privacy",
"url":"#privacy"
},
{
"label":"Security",
"url":"#security"
},
{
"label":"Advanced",
"url":"#advanced"
}
]
}
};
So the variable looks like:
var ListData = {
"main": {
"label":"Main",
"url":"#main"
},
"project": {
"label":"Project",
"url":"#project"
},
"settings": {
"label":"Settings",
"url":"#settings",
"subnav":[
{
"label":"Privacy",
"url":"#privacy"
},
{
"label":"Security",
"url":"#security"
},
{
"label":"Advanced",
"url":"#advanced"
}
]
},
"hello": {
"label":"Hello",
"url":"#hello"
}
};
I used the following code but it doesn't seem to work:
var NewData = '"hello": { "label":"Hello", "url":"#hello" }';
ListData.push(NewData);
You can insert it directly with an object literal:
ListData.hello = { label: "Hello", url: "#hello" };
If you are using jQuery, you can use the .extend() jQuery API like:
$.extend(ListData, {"hello": { "label":"Hello", "url":"#hello" }});
I have one more solution using underscore.js module,
var _ = require("underscore");
var src = {
"main": {
"label": "Main",
"url": "#main"
},
"project": {
"label": "Project",
"url": "#project"
},
"settings": {
"label": "Settings",
"url": "#settings",
"subnav": [
{
"label": "Privacy",
"url": "#privacy"
},
{
"label": "Security",
"url": "#security"
},
{
"label": "Advanced",
"url": "#advanced"
}
]
}
};
var dest = {"hello": { "label":"Hello", "url":"#hello" }};
var data = _.extend(src, dest);
console.log(JSON.stringify(data));
Required op :
{"main":{"label":"Main","url":"#main"},"project":{"label":"Project","url":"#project"},"settings":{"label":"Settings","url":"#settings","subnav":[{"label":"Privacy","url":"#privacy"},{"label":"Security","url":"#security"},{"label":"Advanced","url":"#advanced"}]},"hello":{"label":"Hello","url":"#hello"}}
Keeping with you object literal statements just add another object to your ListData object.
ListData.hello = { "label":"Hello", "url":"#hello" };
push is only for Javascript Arrays.
A JavaScript Object Literal is a comma-separated list of name/value pairs wrapped by a pair of curly braces.
To append the property name of encampment name with a value of Valley Forge to the bottom of the stack, simply add the property name after the JSON object with a dot syntax. Then specify the value. (See 'Append data' below)
You can also delete the appended name/value pair from the object literal. (See 'Delete data below')
// Start with some JSON
var myJson = { "name":"George Washington", "rank":"General", "serial":"102" };
// Append data
myJson.encampment = "Valley Forge";
// Delete data
delete myJson.encampment

Categories

Resources