Angular9 string to array - json

I have a pandas Series that I have converted into JSON for Angular to display in a table. The issue is that the key values are a python list under a string type. How can I convert the key into an array for Angular?
JSON:
{
"result": {
    "('', '100.83.105.90')": 1,
    "('AS1124 Universiteit van Amsterdam', '145.18.162.122')": 2,
    "('AS11796 Airstream Communications, LLC', '64.33.197.15')": 1,
    "('AS16276 OVH SAS', '51.75.201.126')": 1,
    "('AS209 CenturyLink Communications, LLC', '174.27.155.12')": 1,
    "('AS22394 Cellco Partnership DBA Verizon Wireless', '174.241.2.88')": 1,
    "('AS24608 Wind Tre S.p.A.', '37.227.23.201')": 1,
    "('AS3329 Vodafone-panafon Hellenic Telecommunications Company SA', '5.55.162.202')": 1,
    "('AS3352 Telefonica De Espana', '80.24.64.41')": 1,
    "('AS6128 Cablevision Systems Corp.', '69.116.62.88')": 1,
    "('AS6805 Telefonica Germany', '2.240.20.127')": 1,
}
In Angular:
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col" >{{selectedGroup}}</th>
<th scope="col">{{selectedColumn}}</th>
<th scope="col">Hits</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of mvaHits | keyvalue">
<td>{{item.key[0]}}</td>
<td>{{item.key[1]}}</td>
<td>{{item.value}}</td>
</tr>
</tbody>
</table>
What it looks like:
How can I fix this?
Appreciate the help :)

The best solution would be to export the data from Python in a proper JSON format. You could then parse the array as a real Javascript array using JSON.parse().
If you can't adjust mvaHits, this should parse the Python array as a Javascript array and let you access the elements in the array. Note that this wouldn't work in all cases, especially if the strings in your array had commas. I would recommend not doing these conversions in the HTML for the sake of clarity and cleanliness, but rather when you load mvaHits for the first time. But this should work:
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col" >{{selectedGroup}}</th>
<th scope="col">{{selectedColumn}}</th>
<th scope="col">Hits</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of mvaHits | keyvalue">
<td>{{item.key.slice(1,-1).split(', ').map((s) => s.slice(1,-1))[0]}}</td>
<td>{{item.key.slice(1,-1).split(', ').map((s) => s.slice(1,-1))[1]}}</td>
<td>{{item.value}}</td>
</tr>
</tbody>
</table>
Breaking it down:
item.key
.slice(1,-1) // Removes the first and last characters in the string, removing the ()
.split(', ') // Splits the string into an array using ', ' as the delimiter
.map((s) => s.slice(1,-1)) // Removes the quotes from the strings in the array
[0] // access the first element of the new array

Thanks to #zeterain for helping realize split/slice/etc can be applied directly to item.key.
Solution:
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col" >{{selectedGroup}}</th>
<th scope="col">{{selectedColumn}}</th>
<th scope="col">Hits</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of mvaHits | keyvalue">
<td>{{item.key | slice:1:-1 | split:", ":0}}</td>
<td>{{item.key | slice:1:-1 | split:", ":1}}</td>
<td>{{item.value}}</td>
</tr>
</tbody>
</table>
String splitting requires generating a custom pipe, instructions can be found here: https://stackoverflow.com/a/45205047/6575456
Slice pipe (default angular): https://angular.io/api/common/SlicePipe

I will propose you to use regular expressions in order to parse the keys. In this case is pretty simple. Regular expressions are a really powerful tool.
const data = {
"result": {
"('', '100.83.105.90')": 1,
"('AS1124 Universiteit van Amsterdam', '145.18.162.122')": 2,
"('AS11796 Airstream Communications, LLC', '64.33.197.15')": 1,
"('AS16276 OVH SAS', '51.75.201.126')": 1,
"('AS209 CenturyLink Communications, LLC', '174.27.155.12')": 1,
"('AS22394 Cellco Partnership DBA Verizon Wireless', '174.241.2.88')": 1,
"('AS24608 Wind Tre S.p.A.', '37.227.23.201')": 1,
"('AS3329 Vodafone-panafon Hellenic Telecommunications Company SA', '5.55.162.202')": 1,
"('AS3352 Telefonica De Espana', '80.24.64.41')": 1,
"('AS6128 Cablevision Systems Corp.', '69.116.62.88')": 1,
"('AS6805 Telefonica Germany', '2.240.20.127')": 1,
}
};
const regex = /\('(?<asn>.*)', '(?<ip>.*)'\)/;
const mvaHits = [];
for (const key of Object.keys(data.result)) {
const found = key.match(regex);
if (found) {
mvaHits.push({
asn: found.groups.asn,
ip: found.groups.ip,
hits: data.result[key]
});
}
}
console.log(mvaHits);
result
[ { asn: '', ip: '100.83.105.90', hits: 1 },
{ asn: 'AS1124 Universiteit van Amsterdam',
ip: '145.18.162.122',
hits: 2 },
{ asn: 'AS11796 Airstream Communications, LLC',
ip: '64.33.197.15',
hits: 1 },
{ asn: 'AS16276 OVH SAS', ip: '51.75.201.126', hits: 1 },
{ asn: 'AS209 CenturyLink Communications, LLC',
ip: '174.27.155.12',
hits: 1 },
{ asn: 'AS22394 Cellco Partnership DBA Verizon Wireless',
ip: '174.241.2.88',
hits: 1 },
{ asn: 'AS24608 Wind Tre S.p.A.', ip: '37.227.23.201', hits: 1 },
{ asn:
'AS3329 Vodafone-panafon Hellenic Telecommunications Company SA',
ip: '5.55.162.202',
hits: 1 },
{ asn: 'AS3352 Telefonica De Espana',
ip: '80.24.64.41',
hits: 1 },
{ asn: 'AS6128 Cablevision Systems Corp.',
ip: '69.116.62.88',
hits: 1 },
{ asn: 'AS6805 Telefonica Germany', ip: '2.240.20.127', hits: 1 } ]
html
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col" >{{selectedGroup}}</th>
<th scope="col">{{selectedColumn}}</th>
<th scope="col">Hits</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of mvaHits">
<td>{{item.asn}}</td>
<td>{{item.ip}}</td>
<td>{{item.hits}}</td>
</tr>
</tbody>
</table>
Although you can add code logic in angular template, as an advice try not abuse of these.

Related

Angular: Dynamically find headers when converting JSON array to HTML table

In Angular, I want to convert a JSON array to an HTML table.
I have seen an old answer for AngularJS:
<table>
<thead>
<tr>
<th ng-repeat="(key, value) in records[0]">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="(key, value) in records">
<td ng-repeat="(key, value) in value">
{{value}}
</td>
</tr>
</tbody>
</table>
JSON looks like this:
[{
"Name": "Alfreds Futterkiste",
"City": "Berlin",
"Country": "Germany"
}, {
"Name": "Berglunds snabbköp",
"City": "Luleå",
"Country": "Sweden"
}, {
"Name": "Centro comercial Moctezuma",
"City": "México D.F.",
"Country": "Mexico"
}]
I've tried to translate it to the Angular syntax. Here is what I got so far:
<table>
<thead>
<tr>
<th *ngFor="let item of records[0] | keyvalue">{{item.key}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of records">
<td *ngFor="let item1 of item | keyvalue">
{{item1.value}}
</td>
</tr>
</tbody>
</table>
Right now it's failing to compile because records[0] is undefined... how can I translate this expression to the newer syntax (or create something equivalent)?
UPDATE 1:
I have a partial solution. However with this partial solution the rendered table is not completely identical to the older AngularJS rendition (because it creates multiple unnecessary header rows, which only one of them is populated, as opposed to only one header row in the older rendition).
<table style="border-collapse: collapse;">
<thead *ngFor="let item of records; let last=last">
<tr *ngIf="last">
<th *ngFor="let item1 of item | keyvalue">
{{item1.key}}
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of records">
<td *ngFor="let item1 of item | keyvalue">
{{item1.value}}
</td>
</tr>
</tbody>
</table>
Do you have a better way to do it, possibly similar to the older AngularJS version?
UPDATE 2:
In Angular, I access the JSON data through a request from Angular that is then redirected to a back end service. That service may read a file, or get the data from a database. When the back end service has the data ready, it returns the data to the Angular request. The code on the Angular end looks like this:
HTML:
<div>
<h3>Test Post Request</h3>
<button (click)="postData()">Click Me</button>
<div>Response: {{records}}</div>
</div>
TypeScript:
private dataPostTestUrl = '/api/postTest';
records: string | undefined;
public postData(): void {
this.appService.sendData().subscribe((data: any) => {
this.records = data.content;
});
}
public sendData(): Observable<any> {
return this.http.post(this.dataPostTestUrl, {});
}
I think maybe you need to define records in the component.
records = [{
"Name": "Alfreds Futterkiste",
"City": "Berlin",
"Country": "Germany"
}, {
"Name": "Berglunds snabbköp",
"City": "Luleå",
"Country": "Sweden"
}, {
"Name": "Centro comercial Moctezuma",
"City": "México D.F.",
"Country": "Mexico"
}];
I am fairly certain this is what you need: https://stackblitz.com/edit/angular-ivy-n7irpw?file=src/app/hello.component.ts
Take a look at how I import the file in the app.component.ts
As well as how I loop in the HTML.
Let me know if it helps!

How to remove scientific notation in nodejs/html and display in decimal only?

I am using a node JS app to send an email using amazon SES using the ses.sendTemplatedEmail API
I have also mentioned the template's pure html file for reference if need be
how do i achieve expected output ? i don't know what is going wrong and why it is using scientific when decimal is specified in JSON
test.js
const aws=require('aws-sdk')
const ses = new aws.SES({ apiVersion: "2020-12-01",region:"us-east-1"});
var a = {
"Items": [
{
"timeSinceInactive": 0.00011574074074074075,
"id": "myid1",
"ssid": "myssid",
"deviceName": "devicename1"
},
{
"timeSinceInactive": 0.00009259259259259259,
"id": "myid2",
"ssid": "myssid2",
"deviceName": "devicename2"
}
]
}
b = JSON.stringify(a)
console.log(b)
async function sesSendEmail(b,ses) {
var params = {
Source: "abc#gmail.com",
Template: "mytemplatename",
Destination: {
ToAddresses: ["xyz#gmail.com"] // Email address/addresses that you want to send your email
},
TemplateData: b,
}
try {
await ses.sendTemplatedEmail(params).promise()
}
catch (err) {
console.log(err)
throw new Error(err)
}
};
function setAwsCredentials() {
awsCredentials = {
region: "us-east-1",
accessKeyId: "",
secretAccessKey: ""
};
aws.config.update(awsCredentials);
console.log("Set credentials successfully")
}
setAwsCredentials()
sesSendEmail(b,ses)
template.html
<table border='2' width='1000'>
<tr>
<th>timeSinceInactive</th>
<th>id</th>
<th>ssid</th>
<th>deviceName</th>
</tr>
<thead>
<tr>
{{#each Items.[0]}}
{{/each}}
</tr>
</thead>
<tbody>
{{#each Items}}
<tr>
{{#each this}}
<td>
{{this}}
</td>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
Current output:
timeSinceInactive id ssid deviceName
1.1574074074074075E-4 myid1 myssid devicename1
9.259259259259259E-5 myid2 myssid2 devicename2
desired output
timeSinceInactive id ssid deviceName
0.00011574074074074075 myid1 myssid devicename1
0.00009259259259259259 myid2 myssid2 devicename2
EDIT
I need to sort the data as well so converting it to a string is not a feasible alternative unfortunately.
Note
I am using createTemlate API from Amazon SES which supports handlebars.. so the html code is using handlebars by default... that is causing the issue its making it in scientific notation for some reason how do i make it decimal only ?
You might consider converting the numbers to strings before passing them to the template. That way you have control over the formatting.
To my mind you should switch to a template that is less generic and make a call to a custom helper that would display the number as you want. The template will look like this one :
<table border='2' width='1000'>
<tr>
<th>timeSinceInactive</th>
<th>id</th>
<th>ssid</th>
<th>deviceName</th>
</tr>
<thead>
<tr>
{{#each Items.[0]}}
{{/each}}
</tr>
</thead>
<tbody>
{{#each Items}}
<tr>
<td>
{{customFormatNumber timeSinceInactive}}
</td>
<td>
{{id}}
</td>
<td>
{{ssid}}
</td>
<td>
{{deviceName}}
</td>
</tr>
{{/each}}
</tbody>
</table>
And here is the custom helper that you could write (this is just an example, probably not the one you want exactly) :
Handlebars.registerHelper('customFormatNumber ', function(item, options) {
retrun item.toPrecision(10)
});

How to display the value returned by avg function (mysql) in angular

After executing a query, I received the following data which is in Json format which is in myDocData:
data: [
RowDataPacket {
updatedAt: 2020-01-03T18:30:00.000Z,
email: 'charles#hotmail.com',
name: 'charles',
money_spent: 1,
'avg(e.money_spent)': 1
},
RowDataPacket {
updatedAt: 2020-01-11T18:30:00.000Z,
email: 'ank#gmail.com',
name: 'ank',
money_spent: 10,
'avg(e.money_spent)': 6
}
]
angular code:
<table class="content-table" >
<thead>
<tr>
<th>EMAIL</th>
<th>NAME</th>
<th>money spent</th>
<th>UPDATED</th>
<th>AVERAGE</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of myDocData">
<td>{{item.email}}</td>
<td>{{item.name}}</td>
<td>{{item.money_spent}}</td>
<td>{{item.updatedAt}}</td>
<td>{{item.avg(e.money_spent)}}</td>
</tr>
</tbody>
</table>
Issue is that I am unable to display the value given by avg function
(other attributes are displayed correctly).
Change the line:
<td>{{item.avg(e.money_spent)}}</td>
to:
<td>{{item['avg(e.money_spent)']}}</td>
In JS, you can use square bracket notation to get properties of objects.
If you have the control over the back-end code then you can change the query which is returning "avg(e.money_spent)" to "avg(e.money_spent) as avg_money_spent" in this way will not be facing the issue and you can access the value using
<td>{{item.avg_money_spent}}</td>
Or you could also use the previous answer by #Viqas

Angular 5: Access JSON Object with Template Syntax

I get the following JSON represantion from a web service
{
"STAT": {
"Total": 216,
"Average": 2.9722222222222223
},
"PPRP": {
"Total": 31494,
"Average": 19.884390677589384
}
}
Within my component I have the following code:
rawOverview: any
ngOnInit() {
this.service.getPlcOverview().subscribe(
data => {
this.rawOverview = JSON.parse(JSON.stringify(data))
},
err => console.error(err),
() => console.log('done loading foods')
);
}
How can I access PPRP and STAT with template syntax?
I tried the following:
<table class="table table-dark">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Tels with acks</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">PPRP</th>
<td>{{rawOverview.PPRP?.Average}}</td>
</tr>
</tbody>
</table>
but I get an error in the console.
ERROR TypeError: Cannot read property 'PPRP' of undefined
Is it possible to access a JSON object in this way?
Or do I have to create known objects which can access the values?
At the moment, because rawOverview is set asynchronously, it starts life undefined, which is causing your error.
If you move the question mark, it will perform a null safe check, which will prevent the error
<td>{{rawOverview?.PPRP?.Average}}</td>
More on that here
Yes you can and should access it like this.
in the HTML just do something like this:
<tr>
<th scope="row">PPRP</th>
<td>{{rawOverview.PPRP?.Average}}</td>
</tr>
<tr>
<th scope="row">STAT</th>
<td>{{rawOverview.STAT?.Average}}</td>
</tr>

AngularJs: Convert json string to html table

I am an absolute newbie to angularjs and i have been making my hands dirty from the past 3 days. Now, the requirement is to convert a json string from the rest end point to tabular data. Here is the code i am trying.
$scope.getDataCatalogue = function(){
$http.get('http://api.geosvc.com/rest/US/84606/nearby?apikey=485a35b6b9544134b70af52867292071&d=20&pt=PostalCode&format=json')
.success(function(data, status, headers, config){
//do something with your response
$scope = data;
})
.error(function(error){
console.log("not world");
});
}
$scope.getDataCatalogue = function(){
alert('getDataCatalogue');
}
Now,how can i convert the json to grid from the data. Is this the right way to approach the problem.
If you have a fixed structure coming out of the data then you can simply make use of ng-repeat to iterate through the object(data) and display it on your pre-created table. Fiddle
Example shown below:
Considering this is your object which your assigning to a $scope variable name people. $scope.people = data;
[
{
id: 1,
firstName: "Peter",
lastName: "Jhons"
},
{
id: 2,
firstName: "David",
lastName: "Bowie"
}
]
In your controller:
.success(function(data, status) {
$scope.people = data;
});
In your HTML :
<table>
<tr>
<th>Id</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
<tr ng-repeat="person in people">
<td>{{person.id}}</td>
<td>{{person.firstName}}</td>
<td>{{person.lastName}}</td>
</tr>
</table>
Either do it yourself in the view:
<table>
<thead>
<tr>
<th>header 1</th>
<th>header 2</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in data">
<td>{{row.attribute1}}</td>
<td>{{row.attribute2}}</td>
</tr>
</tbody>
</table>
Or use a library like ui-grid to render a more advanced table.