I have a json file called data.json in my assets folder
[
{
"id": 1,
"project_name": "X project",
"project_date": "December 1, 2019 at 9:03:01 AM GMT+1",
"project_status": "vip",
"rating": "5 star"
}
]
Here Is my Angular service called home.service.ts
projectList = '../../../assets/data.json';
getProject() {
return this.httpService
.get(this.projectList)
.map(res => JSON.parse(res.text(), this.reviver));
}
reviver(key, value): any {
if ('project_date' === key) {
return new Date(value);
}
return value;
}
Here is my component.ts file
projects: string[];
showProject() {
this.homeservice.getProject().subscribe(
data => {
this.projects= data as string[];
console.log(this.projects);
},
(err: HttpErrorResponse) => {
console.log(err.message);
}
);
}
And this is my html file
<div *ngFor="let project of projects">
<h5>{{ project.project_date | date }}</h5>
</div>
The error I'm getting is:
res.text is not a function in home.service.ts
If I try it without the .map(res => JSON.parse(res.text(), this.reviver));
I get this error:
Invalid argument 'December 1, 2019 at 9:03:01 AM GMT+1' for pipe 'DatePipe'
Does anyone have a solution to how I can display this on the web page as a date? Thanks.
Your date should look like the following (without at):
"December 1, 2019 9:03:01 AM GMT+1"
There is no need to parse the response of your http request since it is done natively by angular
getProject() {
return this.httpService
.get(this.projectList)
}
To display the date using a format
{{project.project_date | date:'h:mm a z'}}
Related
I'm trying to create an object out of my json (from a http request) but it's a plain string.
Interfaces:
export interface CeleryTask {
uuid: string,
state: string,
received: string,
result: Chat,
}
export interface Chat {
id: number;
chatTitle: string;
chatId: string;
users: User[];
archived: boolean,
}
GET Request in my service:
loadAllSuccessTasksFromFlower(): Observable<CeleryTask[]> {
return this.http.get<CeleryTask[]>("http://localhost:5566/api/tasks?state=SUCCESS")
.pipe(map(response => Object.entries(response)
.map(entry => ({
uuid: entry[0],
state: entry[1].state,
received: entry[1].received,
result: entry[1].result
}))))
}
HTTP Response:
{
"67fe1783-4451-4fa5-838e-b78279fd5c07":{
"uuid":"67fe1783-4451-4fa5-838e-b78279fd5c07",
"name":"upload.tasks.importWorkTask",
"state":"SUCCESS",
"received":1668285215.4455156,
"sent":null,
"started":1668285219.4739492,
"rejected":null,
"succeeded":1668285419.1474545,
"failed":null,
"retried":null,
"revoked":null,
"args":"('C:\\Users\\xx\\AppData\\Local\\Temp\\xxx', 'xx.pdf')",
"kwargs":"{}",
"eta":null,
"expires":null,
"retries":0,
"result":"{'id': 9, 'chatTitle': 'My Chat'}",
"exception":null,
"timestamp":1668285419.1474545,
"runtime":199.67199999999866,
"traceback":null,
"exchange":null,
"routing_key":null,
"clock":599,
"client":null,
"root":"67fe1783-4451-4fa5-838e-b78279fd5c07",
"root_id":"67fe1783-4451-4fa5-838e-b78279fd5c07",
"parent":null,
"parent_id":null,
"children":[
],
"worker":"celery#xxx"
}
When I console.log the result:
{
"uuid": "67fe1783-4451-4fa5-838e-b78279fd5c07",
"state": "SUCCESS",
"received": 1668285215.4455156,
"result": "{'id': 9, 'chatTitle': 'My Chat'}"
}
The id & chatTitle is not a chat object, it's an plain string. So it's not possible to access object.result.chatTitle
Any idea how to solve this problem?
One way to get the object from the received string would be
result: JSON.parse(entry[1].result);
Build a type guard to let typescript understand that you really have a Chat object
function isChat(o: any): o is Chat {
// check whatever is necessary to be a Chat object
return "id" in o && "chatTitle" in o
}
Use the typeguard like this
const parsed = JSON.parse(jsonString);
if (isChat(parsed)) {
// do something with now correctly typed object
} else {
// error handling; invalid JSON format
}
See https://stackoverflow.com/a/62438143/7869582 for more info on that
json format test with postman
{
"localTimeStamp": "2021-08-14T08:19:17.000Z",
"ipAddress": "10.0.5.26",
"subnetMask": "N/A",
"defaultGateway": "N/A",
"productType": "UNIVERGE BX9000",
"versionID": "7.20A.256.721",
"protocolType": "SIP",
"operationalState": "UNLOCKED",
"highAvailability": "Not Operational",
"serialNumber": "9107130",
"macAddress": "00908f8af6ba",
"systemUpTime": 4049040,
"saveNeeded": false,
"resetNeeded": false
}
i use this code in nex.js to fetch the info
import styles from '../styles/Jobs.module.css'
export const getStaticProps = async () => {
const res = await fetch('http://10.0.5.26/api/v1/status',{
headers: { Authorization: "Basic passsssworrdssss" }
}
);
const data = await res.json();
return {
props: { ninjas: data }
}
}
const Ninjas = ({ ninjas }) => {
console.log(ninjas)
return (
<div>
<h1>All Ninjas</h1>
{ninjas.map(ninja => (
<div key={ninja.id}>
<a className={styles.single}>
<h3>{ ninja.productType }</h3>
</a>
</div>
))}
</div>
);
}
export default Ninjas;
the error is browser
enter image description here
think the problem is The .map function is only available on array.
It looks like data isn't in the format you are expecting it to be (it is {} but im expecting []).
hopefully someone knows the solution to solve the error
output of console.log(ninjas) looks ok now
only got still error in browser
ReferenceError: ninja is not defined
[
{
localTimeStamp: '2021-08-14T10:30:35.000Z',
ipAddress: '10.0.5.26',
subnetMask: 'N/A',
defaultGateway: 'N/A',
productType: 'UNIVERGE BX9000',
versionID: '7.20A.256.721',
protocolType: 'SIP',
operationalState: 'UNLOCKED',
highAvailability: 'Not Operational',
serialNumber: '9107130',
macAddress: '00908f8af6ba',
systemUpTime: 4056919,
saveNeeded: false,
resetNeeded: false
}
]
It's an object so you don't need to loop through it to get the value insides:
Just direct access them like this:
<div>
<h1>All Ninjas</h1>
<div key={ninja.id}>
<a className={styles.single}>
<h3>{ ninja.productType }</h3>
</a>
</div>
</div>
- Be aware that id is not available in your object so ninja.id is invalid which return an undefined
- Consider using getServerSideProps to fetch data on each request. Because getStaticProps fetch data at build time
props: { ninjas: data }
Here, according to your description, data is given as
{ "localTimeStamp": "2021-08-14T08:19:17.000Z" ...}
So ninjas is not an array, it's a normal object now.
ninjas.map requires ninjas to be an array and as it is not, an error occured.
To fix it, you can fix this part.
props: { ninjas: [data]}
I'm just trying to fetch some JSON data from a url. The JSON data is formatted like so (reduced to two entries for simplicity):
[
{
"id": 1
"name": "Brett",
"gender": "male"
},
{
"id": 2
"name": "Sandra",
"gender": "female"
}
]
I can print profiles using console.log(profiles) and see all the entries in the console, but when i try to access the .name field i get the error
Property 'name' does not exist on type 'never'.
Here is the code for the app:
const URL = 'someurl'
function App() {
const [curId, setId] = useState(0);
//const [curProfile, setCurProfile] = useState(undefined);
const [profiles, setProfiles] = useState([])
useEffect(() => {
fetch(URL)
.then((response) => {
if (response.ok) {
return response.json();
} else {
throw new Error("Something went wrong!");
}
})
.then(
(response) => {
setProfiles(response);
setId(1);
//setCurProfile(profiles[curId - 1]);
})
.catch((error) => {
console.log(error)
})
}, []);
return (
<div className="App">
<p>
{profiles[curId].name}
</p>
</div>
);
}
export default App;
Also as a side question, I'm having some problems storing the current profile in the curProfile variable. Could someone point me in the right direction for that? Thanks!
The initial state of profiles is empty array and curId is 0, so profiles[curId] should be undefined thus profiles[curId].name would be error as initial rendering.
You should always check if profiles is empty or not.
return (
<div className="App">
{profiles.length > 0 &&
<p>
{profiles[curId].name}
</p>
}
</div>
)
You've got to type your state, otherwise Typescript won't know what to expect. You also need to type the response.
Something like:
type Profile = {
id: number,
name: string,
gender: string
}
const [profiles, setProfiles] = useState <Profile[]> ([]);
(...)
setProfiles(response as Profile[]);
I have a simple Angular HttpClient, which is correctly returning JSON. I am attempting to cast the results to enforce type safety (not sure if this is correct).
But how do I actually access the returned JSON to copy it into an array?
The httpClient get() request is (and seems to be working fine):
public sendGetRequest(): Observable<Symbols[]> {
return this.httpClient.get<Symbols[]>(this.REST_API_SERVER);
}
The Symbols interface is
export interface Symbols {
code: string
desc: string
}
I have a component which calls the data service and is getting a response. However the code below returns an error when attempting to map the JSON into a string array
ERROR TypeError: syms.map is not a function
listOfOption: Array<{ value: string; label: string }> = []
this.dataService.sendGetRequest().subscribe((syms: Symbols[]) => {
console.log('return value ' + JSON.stringify(syms))
// console output shows the returned JSON and it looks correct
//this does not work, how do I copy the results to a string array??
this.listOfOption = syms.map(results => {
return {
value: results.code,
label: results.code,
}
})
})
The JSON data structure is:
{
"results": [
{
"code": "code1",
"desc": "Long description of code 1"
},
{
"code": "code2",
"desc": "Long description of code 2"
},
{
"code": "code3",
"desc": "Long description of code 3"
},
{
"code": "code4",
"desc": "Long description of code 4"
}
]
}
This is driving me crazy
Model a new interface called responseData to support response type.
export interface responseData{
results: Symbols[]
}
export interface Symbols {
code: string
desc: string
}
Update the same in service
public sendGetRequest(): Observable<responseData> {
return this.httpClient.get<responseData>(this.REST_API_SERVER);
}
You can now retrieve the results using array.map()
listOfOption: Array<{ value: string; label: string }> = []
this.dataService.sendGetRequest().subscribe((syms: responseData) => {
console.log('return value ' + syms)
this.listOfOption = syms.results.map(result => {
return {
value: result.code,
label: result.code,
}
})
})
The response data has an object root, but you're trying to parse it as an array root. I think the simplest solution would be something like this:
public sendGetRequest(): Observable<Symbols[]> {
return this.httpClient.get<{results: Symbols[]}>(this.REST_API_SERVER)
.pipe(pluck('results'));
}
Which specifies that the response data is an object with a field named results which holds an array of Symbols.
Alternatively you could also extract the response type to a separate definition:
interface ApiResponse {
results: Symbols[]
}
public sendGetRequest(): Observable<Symbols[]> {
return this.httpClient.get<ApiResponse>(this.REST_API_SERVER)
.pipe(pluck('results'));
}
I am looping through a json file to display data in panels. But i am having some trouble controlling how to display the data appropriately.
This is my json data that is returned from the services:
Object {Group1: Object,
Group2: Object}
The json file data sample:
{
"Group1": {
"name": "Group1List",
"dataFields": [..],
"dataQuery": {..},
"id": 1,
"title": "Group1",
"content": {..}
},
}
This is my services:
getGroupsData(){
return this._http.get('...')
.map((res:Response) => res.json())
}
Component.ts:
groups: Array<any> = [];
getGroups(){
this.groupService.getGroupsData().subscribe(
data => this.groups = data;
}
HTML:
<div dnd-sortable-container [sortableData]="groups" [dropZones]="['container-dropZone']">
<div class="col-sm3" *ngFor="let group of groups; let i = index" dnd-sortable [sortableIndex]="i" [dragEnabled]="dragOperation">
<div class="panel panel-primary" dnd-sortable-container [dropZones]="['widget-dropZone']">
<div class="panel-heading"></div>
<div class="panel-body"></div>
</div>
</div>
</div>
when i render the code i get an error in the console stating: Error trying to diff '[object Object]' in the heading i would like to add Group1 and then in the body i will display different parts from the json.
What is the source of the problem?
*ngFor requires an array, but it looks like you are passing it an object.
If you cannot change the JSON response, and you know the names of the groups beforehand, you can place the objects in an array:
this.groups = [data.Group1, data.Group2, // etc]
*ngFor requires an array [], and you are passing an object
Your sample has unnecessary nested level, flat is always better
Your json should look like this
[
{
"name": "Group1List",
"dataFields": [..],
"dataQuery": {..},
"id": 1,
"title": "Group1",
"content": {..}
},
{
"name": "Group2List",
"dataFields": [..],
"dataQuery": {..},
"id": 2,
"title": "Group2",
"content": {..}
},
// ....
]
Update:
If you have no control over your json scheme, try to flatten it here
getGroupsData(){
return this._http.get('...')
.map((res:Response) => res.json())
.map((obj) => Object.keys(obj).map((key)=>{ return obj[key]})
}
or implement a pipe that iterate over object properties
import { PipeTransform, Pipe } from '#angular/core';
#Pipe({name: 'keys'})
export class KeysPipe implements PipeTransform {
transform(value, args:string[]) : any {
let keys = [];
for (let key in value) {
keys.push(key);
}
return keys;
}
}
and use it like this
<div *ngFor="let group of groups | keys; let i = index">
</div>
Change your component to:
groups: Array<any> = [];
getGroups(){
this.groupService.getGroupsData().subscribe(
data => this.groups = data.Group1.dataFields;
}
Why?
Because, you want your groups component property to be an array.
So, in your subscribe handler, data will refer to the entire JSON object, and you only care about the Group1 property of your results.