Note: I am new to JavaScript and html so there are a lot of things i do not quite understand yet.
I am trying to make a web-application that uses a bus-schedule API to show the bus times around my apartment. I have managed to retrieve the data, but I struggle to display that data in the html. (edit: it is possibly a SDK, i dont really know the difference)
// this is the function write_bus() in my javascript file departures.js:
function write_bus() {
document.getElementById("bustime-kong").innerHTML = data;
}
// 'data' is a variable in javascript that contains the information I fetched from the client, and is what I am trying to show.It is on the following format:
const data = {
aimedArrivalTime: '2022-01-06T12:36:00+0100',
aimedDepartureTime: '2022-01-06T12:36:00+0100',
cancellation: false,
date: '2022-01-06',
destinationDisplay: {
frontText: 'xxx'
},
expectedDepartureTime: '2022-01-06T12:38:12+0100',
expectedArrivalTime: '2022-01-06T12:37:32+0100',
forAlighting: true,
forBoarding: true,
notices: [],
predictionInaccurate: false,
quay: {
id: 'xxx',
name: 'xxx',
publicCode: 'P2',
situations: [],
stopPlace: [Object]
}
}
<script src="departures.js"></script>
<input type="button" onclick="write_bus()" value="Busstider"> <br>
<div id="bustime-kong"></div>
(In order to save some space i removed 2/3 of the data)
I appreciate every bit of help i could get!
You can't insert raw objects like that as DOM text. You have to use specific properties, but if you are so inclined to insert object like that, use JSON.stringify() method.
document.getElementById("bustime-kong").innerHTML = JSON.stringify(data);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
BTW, It is good practice to put <script> tag at the end to make sure HTML is loaded before running any JavaScript.
You can create a function that will parse through the json and print it in table form like below.
// this is the function write_bus() in my javascript file departures.js:
function write_bus() {
document.getElementById("bustime-kong").innerHTML = createTable(data);
}
// 'data' is a variable in javascript that contains the information I fetched from the client, and is what I am trying to show.It is on the following format:
const data = {
aimedArrivalTime: '2022-01-06T12:36:00+0100',
aimedDepartureTime: '2022-01-06T12:36:00+0100',
cancellation: false,
date: '2022-01-06',
destinationDisplay: {
frontText: 'xxx'
},
expectedDepartureTime: '2022-01-06T12:38:12+0100',
expectedArrivalTime: '2022-01-06T12:37:32+0100',
forAlighting: true,
forBoarding: true,
notices: [],
predictionInaccurate: false,
quay: {
id: 'xxx',
name: 'xxx',
publicCode: 'P2',
situations: [],
stopPlace: [Object]
}
}
function createTable(data){
var table = "<table>";
for(var key in data){
table+="<tr>";
table+="<td>"+key+"</td>";
table+="<td>"+data[key]+"</td>";
table+="</tr>";
}
table+="</table>";
return table;
}
<input type="button" onclick="write_bus()" value="Busstider"> <br>
<div id="bustime-kong"></div>
Since it is array of data you need to use Json.stringify method,
document.getElementById("bustime-kong").innerHTML = JSON.stringify(data);
Related
I'm not sure if what I'm trying to do is the correct/valid approach to what I'm trying to accomplish; essentially, I'm retrieving data from a db via an ajax call, I want this data to populate a js library where the layout is something like
data[
item{
name: 'name',
start_date: date,
end_date: date
},
item{
name: 'name',
start_date: date,
end_date: date
},
]
is there any way I can populate the code inside 'data' on the fly?
I was thinking with a loop to populate a variable which would hold the data and placing it like so
//this is hard coded, but the idea is that a loop would populate this with the necessary information
let items = "
item{
name: 'name',
start_date: date,
end_date: date
},
item{
name: 'name',
start_date: date,
end_date: date
}";
data[
items
]
Would this be a valid approach?
thanks in advance!
UPDATE:
For clarification, this what I have
$('#calendar').fullCalendar({
defaultDate: today,
eventLimit: true,
events: [
{
title: 'Some event',
start: '2022-08-31',
end: '2022-08-31'
},
{
title: 'Some event',
start: '2022-08-31',
end: '2022-08-31'
}
]
});
What im trying to achieve is something like this
let allEvents = "
{
title: 'Some event',
start: '2022-08-31',
end: '2022-08-31'
},
{
title: 'Some event',
start: '2022-08-31',
end: '2022-08-31'
}";
$('#calendar').fullCalendar({
defaultDate: today,
eventLimit: true,
events: [
allEvents;
]
});
Would this be possible?
So, closing this question, thanks to #DaveNewton for the insight, it really clarified what I was supposed to do; I apologize for the confusion, my thought process essentially revolved around 'echoing' or 'printing' code in php.
my approach was:
$.ajax({
type: "GET",
url: filethathandlesrequest.php,
data: {
data_to_be_sent: 'data',
},
success: function(response) {
response = JSON.parse(response);
eventsGotten = response.return_result;
//this is where I create the object
let eventsToDisplay = [];
for (let index = 0; index < eventsGotten.length; index++) {
const element = eventsGotten[index];
let singleEvent = {title: element.description, start: element.start_date, end: element.end_date};
eventsToDisplay.push(singleEvent);
}
if (response.return_code === 0) {
if ($('#calendar').exists()) {
loadScript(plugin_path + 'fullcalendar/fullcalendar.min.js', function() {
$('#calendar').fullCalendar({
defaultDate: today,
//editable: true,
eventLimit: true,
events: eventsToDisplay // <-- this is where I use it; and it works!
});
});
}
} else { //you can ignore this, this is just to not display anything if my ajax request fails
if ($('#calendar').exists()) {
loadScript(plugin_path + 'fullcalendar/fullcalendar.min.js', function () {
$('#calendar').fullCalendar({
defaultDate: today,
//editable: true,
eventLimit: true,
events: []
});
});
}
}
});
It seems you are asking if you can import data from a database and populate a JSON array in Javascript with it. The answer would be yes. In fact, I do this routinely to create Javascript front ends that can be quickly rendered and only talk to the database when necessary so you're not waiting on it. You can use Jquery ajax calls to retrieve and write data. I like to have local variables with JSON formatted data which I use to run the app. The app can quickly read and write changes to these JSON arrays. Keep in mind if the page is reloaded or fails all the data to that point will be lost and the user will have to start over so you need to store data to the database at strategic intervals. You can also use HTML localStorage to store data in the browser itself. I've found this an efficient way to build single-page Javascript apps without resorting to React or some of the other frameworks. It's not as efficient though, but easier to code and maintain.
The approach I would take is to define a particular DOM element as a parent / container for the DOM elements which will represent each item. Iterate over the items array in your ajax response, and create DOM elements with jquery for each item. Something along the lines of $('<div>${currentItem.name}>/div>').appendTo(containerDiv);
I have a situation where a user can upload a csv file. This CSV file contains a lot of data, but I am only interested in 2 columns (ID and Date). At the moment, I am parsing the CSV using Papaparse
Papa.parse(ev.data, {
delimiter: "",
newline: "",
quoteChar: '"',
header: true,
error: function(err, file, inputElem, reason) { },
complete: function (results) {
this.parsed_csv = results.data;
}
});
When this is run this.parsed_csv represents objects of data keyed by the field name. So if I JSON.stringify the output is something like this
[
{
"ID": 123456,
"Date": "2012-01-01",
"Irrelevant_Column_1": 123,
"Irrelevant_Column_2": 234,
"Irrelevant_Column_3": 345,
"Irrelevant_Column_4": 456
},
...
]
So my main question is how can I get rid of the columns I dont need, and just produce a new csv containing the columns ID and Date?
Thanks
One thing I realised, is there a way to add dynamic variables. For instance I am letting users select the columns I want to map. Now I need to do something like this
let ID = this.selectedIdCol;
this.parsed_csv = results.data.map(element => ({ID: element.ID, Date: element.Date}));
It is saying that ID is unused however. Thanks
let data = [
{
"ID": 123456,
"Date": "2012-01-01",
"Irrelevant_Column_1": 123,
"Irrelevant_Column_2": 234,
"Irrelevant_Column_3": 345,
"Irrelevant_Column_4": 456
},
...
]
just produce results by using the following code:
data = data.map(element => ({ID: element.ID, Date: element.Date}))
Now you have desired column, please generate a new CSV on these columns
As Serrurier pointed out above, You should use the step/chunk function to alter the data rather than after parse map as in memory data is already available.
PapaParse.parse(file, { skipEmptyLines: true, header: true, step: (results, parser) => {
results.data = _.pick(results.data , [ 'column1' 'column2']);
return results;
}});
Note that if you are loading a huge file, you will have the whole file in memory right after the parsing. Moreover it may freeze the browser due to the heavy workload. You can avoid that by reading and discarding columns :
row by row
chunk by chunk.
You should read Papaparse's FAQ before implementing that. To sum up, you will store required columns by extracting them from the step or chunk callbacks.
I've been stuck on this for a while. Take the following code as an example:
models.Summoner.findOne({
include: [{ model: models.RankedStats, as: 'SummonerRankedStats', required: true }],
where: { summonerId: summonerId, server: server }
}).then(function(summoner) {
models.RankedStats.create({
totalWins: 0,
totalLosses: 0
}).then(function(rankedStats) {
summoner.setSummonerRankedStats(rankedStats).then(function() {
console.log(summoner.SummonerRankedStats)
//This outputs undefined
summoner.getSummonerRankedStats().then(function(srs) {
console.log(srs)
//This outputs the RankedStats that were just created
})
models.Summoner.findOne({
include: [{ model: models.RankedStats, as: 'SummonerRankedStats', required: true }],
where: { summonerId: summonerId, server: server }
}).then(function(summoner) {
console.log(summoner.SummonerRankedStats)
//This outputs the SummonerRankedStats object
})
})
})
})
So, to put it simply... If I have a Summoner (var summoner) and perform a .setAssociation() or .createAssociation() on it, and then log summoner, the data created isn't there. If I fetch it again from the database (with .getAssociation() or by searching for that Summoner again) I can access it, but I was hoping to avoid that extra DB call.
Is there a way to add this information to the original object when using .create() or .set()? It can be achieved by doing something like:
summoner.dataValues.SummonerRankedStats = rankedStats
But that seems somewhat hacky :)
Is there a correct way to do it, or does it even make any sense?
Thanks in advance!
I have a factory, which goes into a controller, and I am trying to get data from that display on an HTML page. I am having trouble specifying an Object's pathway however.
My Factory:
app.factory('APIMethodService', function() {
var Head = "api.example.com";
return {
apis:
[{
accounts: [
{
v1: [
{
uri: Head+"/v1/accounts/",
item1: "AccountNumber",
item2: "MoneyInAccount"
}],
v2: [
{
uri: Head+"/v2/accounts/",
item1: "AccountNumber",
item2: "MoneyInAccount"
}]
}
],
customers: [
{
v1: [
{
uri: Head+"/v1/customers/",
item1: "CustomerName",
item2: "CustomerID",
item3: "CustomerEmail"
}]
}
]
}]
};
});
My Controller:
app.controller('APIController', function($scope, APIMethodService) {
$scope.title = "API";
$scope.apiList = APIMethodService;
$scope.accountList = $scope.apiList.accounts.v1;
$scope.accountList2 = $scope.apiList[0][0];
});
My HTML
<div ng-controller="APIController">
<div id="api" class="row">
<div class="col-xs-12">
<div class="row" style="font-size:20px">
{{title}} Page!
<table class="table table-striped">
<tr ng-repeat="api in apiList | orderBy:'uri' | filter:search">
<td>{{api.uri}}</td>
<td>{{api.item1}}</td>
<td>{{api.item2}}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
The errors I get are in regards to the Controller trying to parse out the individual objects I wish to grab, like accounts or customers, and then any version v#, they may have.
So it will say something such as
TypeError: Cannot read property 'v1' of undefined
I just need some help specifying the proper pathways into my factory service.
You have a few problems. First, you are referring to the object returned from the factory incorrectly. APIMethodService is the factory that you're injecting, so you need to first reference the object that that factory is returning like this:
APIMethodService.apis
This will give you your entire JSON object.
From there, the rest of your object is made up of arrays of objects, so referring to 'v1' won't do you any good. You need to specify an index instead. If you want v1, you'll need:
APIMethodService.apis[0].accounts[0].v1
This will give you the v1 array, which again is an array of objects.
Customers would be:
APIMethodService.apis[0].customers[0].v1
The first problem you have is that the factory returns an object with a single property called apis. So basically this $scope.apiList.accounts.v1 should be $scope.apiList.apis.accounts.v1. Bu that's not all as this won't either work since dotting(.) into apis is an array you'd have to use the index. In this case it would be $scope.apiList.apis[0] and then you could .accounts[0].v1 which is also an array containing a single object.
Now if you can I would suggest to you that you'd change how you represent this data structure.
This is how you could do it.
app.factory('APIMethodService', function() {
var Head = "api.example.com";
return {
accounts: {
v1: {
uri: Head+"/v1/accounts/",
items: ["AccountNumber","MoneyInAccount"]
},
v2: {
... // skipped for brevity
}
},
customer: {
... // code skipped for brevity
}
};
});
And then it's just a matter of dotting into your APIMethodService-object like APIMethodService.accounts.v1.items[0] if you want the AccountNumber method name.
Constructing your url could then be done like this.
var baseUrl = APIMethodService.accounts.v1.uri; // 'api.example.com'
var url = baseUrl + APIMethodService.accounts.v1.items[0]; // 'AccountNumber'
// url = "api.example.com/v1/accounts/AccountNumber"
Again, this is one way you could do it but this can be further enhanced upon. The examples I provided are simply for demo purposes and this is not in any way the only way to do it.
Expanding upon recieved comments/questions your service (and data representation) could now look like this.
app.factory('APIMethodService', function() {
var Head = "api.example.com";
return {
accounts: {
v1: {
uri: Head+"/v1/accounts/",
items: [
{
name:'AccountNumber',
description:'Show the account number'
},
{
name:'AccountOwner',
description:'Show information about the owner of the account'
},
{
name:'MoneyInAccount',
description:'Show money in the Account'
}
]
},
v2: {
... // skipped for brevity
}
},
customer: {
... // code skipped for brevity
}
};
});
// Get descriptions
var accountNumberDescription = APIMethodService.accounts.v1.items[0].description; // 'Show the account number'
var accountOwnerDescription = APIMethodService.accounts.v1.items[1].description; // 'Show information about the owner of the account'
var moneyInAccountDescription = APIMethodService.accounts.v1.items[2].description; // 'Show money in the Account'
By using objects with properties like this it's alot easier to understand what you are trying to do. With arrays with indexes you'd have to know or take a look at the source to see what's going on. Here, someone viewing your code they can instantly understand that it is the description you are getting.
I'm trying to use jqTree to render a collapsible tree to display data from a MySQL database via an ASP.NET project using AJAX.
The Problem:
I can successfully get the string containing the jqTree formatted data (which is not JSON even though they say it supports it) back from my AJAX call. However, once I get it there it get rendered as a vertical string of characters. If I do a typeof call on the data, it says it's a string, even though it 'looks' like an object when visually inspected via console.log.
I have tried a number of different ways to get the string into an object, with varying results.
I'm using this in the code behind to return the manufactured string:
return sb.ToString();
The resultant string looks like this (notice no wrapping quotation marks):
[{label: 'PCBID: 350',children:[{label: 'TimeStamp: 04-Sep-14 10:30:23'},{label: 'User: DAVEG'},{label: 'PCBID: 350'},{label: 'Assembly Drawing: 41411'},{label: 'PCB Drawing: 10348'},{label: 'Vendor: SBE'},{label: 'PO Number: 98019'}]},{label: 'Serial Number: Not Assigned'},{label: 'Assembly Drawing: 41411'},{label: 'Last Test Result: None Found'}]
Which gets rendered like this in my div:
[
{
l
a
b
e
l
:
'
P
C
B
I
D
...and so on...
I know these are being rendered by jqTree because I can drag & drop them, they highlight when clicked on, etc., but instead of a tree view, I get a "dangling vine" view, not exactly useful.
If I simply take that same exact same string and declare it as a var inside the JS (not using the return value of message.d):
var data = [{label: 'PCBID: 350',children:[{label: 'TimeStamp: 04-Sep-14 10:30:23'},{label: 'User: DAVEG'},{label: 'PCBID: 350'},{label: 'Assembly Drawing: 41411'},{label: 'PCB Drawing: 10348'},{label: 'Vendor: SBE'},{label: 'PO Number: 98019'}]},{label: 'Serial Number: Not Assigned'},{label: 'Assembly Drawing: 41411'},{label: 'Last Test Result: None Found'}]
inside my JS code & use that, it displays perfectly and typeof thinks it's an object.
Working Example so you can see what I'm looking for:
JSFiddle
The Code on the JS side:
Here's the Success portion of my AJAX call with a bunch of commented out versions that don't work either:
success: function (message)
{
console.log("SUCCESS: Inside processEvent AJAX success call");
console.log(message.d);
console.log(typeof message);
console.log(typeof message.d);
var data = message.d;
//this method works, but not very useful as it's hard coded:
//var data = [{ label: 'PCBID: 350', children: [{ label: 'TimeStamp: 04-Sep-14 10:30:23' }, { label: 'User: DAVEG' }, { label: 'PCBID: 350' }, { label: 'Assembly Drawing: 41411' }, { label: 'PCB Drawing: 10348' }, { label: 'Vendor: SBE' }, { label: 'PO Number: 98019' }] }, { label: 'Serial Number: Not Assigned' }, { label: 'Assembly Drawing: 41411' }, { label: 'Last Test Result: None Found' }];
var data = $.getJSON(message.d);
//var data = { JSON.parse(message.d) };
//var data = ({}).valueOf.call($.parseJSON(message.d));
//var data = object.create(message.d);
console.log(typeof data);
console.log(data);
$(function ()
{
$('#tree1').tree({
data: data,
autoOpen: false,
saveState: true,
dragAndDrop: true
});
});
The Question:
So after all that, my question is, how do I take the string from the AJAX message.d and turn it into an object so that jqTree can use it to render the tree I'm looking for?
Working Code:
I've added back in some of the success user informing stuff (jGrowl) so don't let that throw you. The bit of code that fixed it is here: data = eval($.parseJSON(message.d));
success: function (message)
{
console.log("SUCCESS: Inside processEvent AJAX success call");
console.log(message.d);
//if it's a non query event, do this
if (DTO.eventData.eventType != "PCBID_query")
{
$.jGrowl("\nSuccessfully inserted a " + DTO.eventData.eventType + " event into the MySQL database.",
{ header: 'SUCCESS', theme: "pcb-success", life: 10000 });
}
//if processData was used for a PCBID query, process this code
if (DTO.eventData.eventType === "PCBID_query")
{
var data = {};
data = eval($.parseJSON(message.d));
$(function ()
{
//force reload of tree data
$('#tree1').tree('loadData', data);
$('#tree1').tree({
data: data,
autoOpen: false,
saveState: true,
dragAndDrop: true
});
});
}
I know the eval is evil & presents a security hole, however, this is all internal code that'll only be used on local servers & production floor computers so I think the risk is acceptable (as does my manager).
eval(data) would work in this case, but using eval() is usually a security issue, especially when getting data from public areas, such as user submitted SQL data.
The best solution would be to look for a real way to export JSON from your ASP.NET. Without knowing your code, a little googling shows there are solutions out there.