hello i want to display the data that i got from a mongodb using a backend api (nodejs)
this is the code for event model
const mongoose = require('mongoose');
const config = require('../config/database');
// Events Schema
const EventSchema = mongoose.Schema({
eventname: {
type: String,
required: true
},
eventstartdate: {
type: String,
required: true
},
eventenddate: {
type: String,
required: true
},
eventcategorie: {
type: String
},
eventdescription: {
type: String
},
eventimage: {
type: String
}
});
const Event = module.exports = mongoose.model('Event', EventSchema);
this is the code from the router
const express = require('express');
const router = express.Router();
const passport = require('passport');
const jwt = require('jsonwebtoken');
const config = require ('../config/database');
const User = require('../models/user');
const Event = require('../models/event');
//get event by id
router.get('/event/:eventid', (req,res) => {
Event.findById(req.params.eventid, (err, event) =>{
if (err){
return res.status(500).send({message:err.message});
}
if(!event){
return res.status(400).send({message:'Event not found'});
}
res.json({
event: {
id: event._id,
eventname: event.eventname,
eventstartdate: event.eventstartdate,
eventenddate: event.eventenddate,
eventcategorie: event.eventcategorie,
eventdescription: event.eventdescription,
eventimage: event.eventimage
}
});
});
});
and this is the code from the service in the angular
// GET an event by ID
displayEvent$(id: string) {
return this.http.get(`http://localhost:3000/users/event/${id}`)
.map(response => response.json());
}
then i created a simple method that is triggered by a button
and i passed an id of an event that i konw is in the database just to test it out
onclickeventpage(){
this.authService.displayEvent$('5ae0c8e96b40a71cd3b772cc').subscribe(event => {
console.log(event)
});
}
this gives me back at the console the event i need with every aribute
but whene i change this
console.log(event)
to this so i can get evey atribute separetly and then i an put them in the html
console.log(event.eventname)
i get undefined
i just want to know how to get every event atribute so i can display them in my html page
First you dont have to call .json() witn angular5
displayEvent$(id: string) {
return this.http.get(`http://localhost:3000/users/event/${id}`)
.map(response => response.json());
}
also you need to access
console.log(event.event.eventname);
HttpModule is deprecated and the new HttpClientModule by default formats the response to JSON so we no longer need to parse it using response.json():
I just want to know how to get every event attribute so that I can
display them on my HTML page
You can tell HttpClient the type of the response to make consuming the output easier and more obvious.
Typechecking of response can be done by using type parameter
export interface Ievent {
id:string
eventname: string
eventstartdate: string
eventenddate: string
eventcategorie: string
eventdescription: string
eventimage: string
}
Http returns an observable and We can tell the HttpClient.get to return response as Ievent type When we use http.get<Ievent>(...) then it returns the instance of Observable<Ievent> type.
In your service
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import {Ievent} from './eventModel'
#Injectable()
export class authService()
{
constructor(private http:HttpClient){}
displayEvent$(id: string)Observable<Ievent> {
return this.http.get<Ievent>(`http://localhost:3000/users/event/${id}`);
}
}
In your component subscribe to Observable<Ievent> to get instance of Ievent
onclickeventpage(){
this.authService.displayEvent$('5ae0c8e96b40a71cd3b772cc').subscribe(event => {
console.log(event);
console.log(event.eventname)});
}
Related
I am trying to use react-query to fetch data in getServerSideProps in Next JS but I keep getting this weird error:
Error: Error serializing `.dehydratedState.queries[0].state.data.config.adapter` returned from `getServerSideProps` in "/auth/google/callback".
Reason: `function` cannot be serialized as JSON. Please only return JSON serializable data types.
Here is my code:
// Packages
import { useRouter } from 'next/router'
import { dehydrate, QueryClient, useQuery } from 'react-query';
// APIs
import { completeGoogleAuth } from '../../../hooks/auth';
export async function getServerSideProps(context) {
const queryClient = new QueryClient()
await queryClient.prefetchQuery('completeGoogleAuth', () => completeGoogleAuth(context.query.code));
return {
props: {
dehydratedState: dehydrate(queryClient),
},
}
}
export default function Callback() {
const router = useRouter();
const { data } = useQuery('completeGoogleAuth', () => completeGoogleAuth(router.query.code))
return (
<>
Loading
</>
)
}
I have tried to use JSON.stringify(dehydrate(queryClient)) and also used JSON.parse(JSON.stringify(dehydrate(queryClient))) but none of them worked.
What can I do?
I stumbled across the same error just today, JSON.stringify(dehydrate(queryClient)) or serializing dehydrate(queryClient) by any means won't really work as the object your completeGoogleAuth function is returning has function values in the key-value pairs, here's a picture of the config object.
And as you know, functions can't be JSON serialized as straightforwardly. Now, what I assume you used(or what I did too) for the completeGoogleAuth fetcher function is use Axios as your API client library. I have found that Axios returns objects that can't be JSON serialized. As a solution, I have just used the native JavaScript fetch() API to get API data and the haven't faced any issues since then.
Here's my fetcher function:
export const getScholarshipInfoSSR = async (token) => {
const response = await fetch(
process.env.NEXT_PUBLIC_API_BASE_URL + portalRoutes.getScholarshipInfo,
{
headers: { Authorization: `JWT ${token}` },
}
);
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json().then((data) => ({ data }));
};
Here's the prefetched useQuery invocation:
await queryClient.prefetchQuery("portal", () =>
getScholarshipInfoSSR(token)
);
I am able to call the API ,I have set the params with id having key and values which needs to be pass dynamically as received from the server (ex:s1,s3,s4..these are sensor names received from the server) and I have to pass these sensor names dynamically .
.service.ts
export class DashboardService {
public sensors: any[];
constructor(private http: HttpClient, private router: Router) {
}
sensorstart(tokenstr) {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Token ' + tokenstr
}),
params: new HttpParams().set('id', JSON.stringify(this.sensors.map(itm => itm.name)))
};
this.http.get(environment.apiUrl + '/api/sensors/start?' + this.id, httpOptions).subscribe(
(senst: any[]) => {
// localStorage.setItem("senst",JSON.stringify(senst));
console.log('senst:', JSON.parse(localStorage.getItem('senst')));
this.router.navigate(['/dashboard']);
},
err => {
console.log('Error', err);
}
);
}
}
.component.ts
this.jammerstart();
--some code--
sensorstart(){
this.senst=JSON.parse(localStorage.getItem("senst"));
console.log("senst",this.senst)
}
But in console It is showing
{
"status": true,
"action": "sensor started"
}
But I want to show the sensor name in action what I have called dynamically in calling the API.
I want the below result which changes dynamically in console
{
"status": true,
"action": "sensor j3 started"
}
How can I Pass the id values (sensor names s1,s2,s3--)dynamically in calling the API.
The question seems to be how pass an dynamic array (like s1,s2,s3) to the server.
This is actually depending how the server API has been designed.
If you build the HttpParams like you did:
const sensors: any[] = [{name: 's1'},{name: 's2'},{name: 's3'}];
const httpOptions = {
params: new HttpParams().set('id', JSON.stringify(sensors.map(itm => itm.name)))
};
this.httpClient.get('api/sensors/start', httpOptions).subscribe();
The request url will be something like this:
/api/sensors/start?id=%5B%22s1%22,%22s2%22,%22s3%22%5D
Which is the encoded string for ["s1","s2","s3"]
If you want to send it like this
/api/sensors/start?id=s1&id=s2&id=s3
You may have to do this:
const sensors: any[] = [{name: 's1'},{name: 's2'},{name: 's3'}];
let httpParams = new HttpParams();
for (const sensor of sensors) {
httpParams = httpParams.append('id', sensor.name);
}
const httpOptions = {
params: httpParams
};
this.httpClient.get('api/sensors/start', httpOptions ).subscribe();
You have to adapt the way you are sending your array depending what the server side is accepting.
The server could also accept another shape:
/api/sensors/start?id[]=s1&id[]=s2&id[]=s3
or
/api/sensors/start?id%5B%5D=s1&id%5B%5D=s2&id%5B%5D=s3
or
/api/sensors/start?id=s1,s2,s3
https://medium.com/raml-api/arrays-in-query-params-33189628fa68
I realize that the new updates don't require conversion of a response to JSON.
The tutorial I am following puts this into the api.service.ts
export class ApiService {
constructor(private http: HttpClient){}
messages = []
getMessage(){
this.http.get('http://localhost:3000/newroute').subscribe(res =>{
this.messages = res.json()
})
}
}
However, with the new update, "res.json()" does not work. I get the following error: Property 'json' does not exist on type 'Object'.
How can I solve this?
Here is the data I'm trying to loop through:
var posts = [
{message:'Hello World'},
{greeting:'Whats going on'}
]
Simply do:
getMessage(){
this.http.get('http://localhost:3000/newroute').subscribe(res =>{
this.messages = res;
})
}
Angular allows you to do type checking on the response. You don't have to manually parse JSON.
Here is a code snippet from your example (I recommend using types):
messages: Message[] = []
getMessage() {
this.http.get<Message[]>('http://localhost:3000/newroute').subscribe((res: Message[]) => {
this.messages = res;
});
}
(Update)
Based on your provided data, an interface for Message could look like this:
export interface Message {
[s: string]: string;
}
However, if "Messages" can only have specific keys like "message" and "greeting", then you can add any of those as optional properties as well.
export interface Message {
message?: string;
greeting?: string;
}
HttpClient gives you json object only, so no need to do .json() again.So do the following code it works for you
getMessage(){
this.http.get('http://localhost:3000/newroute').subscribe(res =>{
let messages: any = res;
this.messages = messages;
})
}
I am handling Http result in a reducer function of an Observable. While a type of the parameter jwt is set as { id: string, auth_token: string, expires_in }, the jwt argument turns out to be a string. I thought TypeScript does parsing automatically. Do I have to do JSON.parse(JSON.stringify(jwt)) by myself?
.mergeMap((jwt: { id: string, auth_token: string, expires_in }) => {})
Type checking external code
There is no relationship between the TypeScript source code and the JavaScript outputs that gets executed at run-time. TypeScript is only effective at catching compile-time errors if the compiled types match the run-time types.
Normally, this isn't a problem. But in scenarios where you call out to external code (i.e. AJAX call to fetch data from the server), there is no guarantee that the response will be the type you expect. So you must be cautious in these scenarios.
Your specific example
I suspect that your code has a variable jwt with type any and you just assigned the type to { id: string, auth_token: string, expires_in } when in fact, jwt was of type string as far as javascript is concerned.
In this case, you already found your solution, JSON.parse(str). This converts the json string into a javascript object.
Now that you have an object, you can use duck typing to infer the run-time type and let typescript know about the type at compile-time via type guards.
Solution
function isDate(obj: any): obj is Date {
return typeof obj === 'object' && 'toISOString' in obj;
}
function isString(obj: any): obj is string {
return typeof obj === 'string';
}
interface JWT {
id: string;
auth_token: string;
expires_in: Date;
}
function isJwt(obj: any): obj is JWT {
const o = obj as JWT;
return o !== null
&& typeof o === 'object'
&& isString(o.id)
&& isString(o.auth_token)
&& isDate(o.expires_in);
}
function print(jwt: any) {
if (typeof jwt === 'string') {
try {
jwt = JSON.parse(jwt);
} catch (e) {
console.error(`String is not JSON: ${jwt}`);
}
}
if (isJwt(jwt)) {
console.log(`Found jwt: ${jwt.id} ${jwt.auth_token} ${jwt.expires_in}`);
} else {
console.error(`Object is not of type jwt: ${jwt}`);
}
}
print(42);
print('failing');
print(null);
print(undefined);
print({});
print({ id: 'id01', auth_token: 'token01', expires_in: new Date(2018, 11, 25) });
Playground
Try running that code on the TS Playground to see how it inspects the object at run-time.
If the jwt(JSON) object is retrieved with Http from HttpModule #angular/http you have to parse it to JSON
e.g.:
import { Http } from '#angular/http';
....
constructor(
private http: Http
...
) {}
this.http.get(url)
.map((res: any) => {
return res.json();
}).subscribe( (jwt: any) => {
//you got jwt in JSON format
});
If you use HttpClient from HttpClientModule #angular/common/http (Angular > 4.3.x) you do not need to parse the received data because it is already done.
import { HttpClient } from '#angular/common/http';
....
constructor(
private http: HttpClient
...
) {}
this.http.get<any>(url)
.subscribe((jwt: any) => {
//you got jwt in JSON format
})
More info in this answer
Consider this simple snippet of an AngularJS 2 application:
TestObject
export class TestObject {
id: number;
name: string;
}
TestService
[...]
export class TestService {
constructor(private http: Http) {}
test(): Observable<TestObject> {
return this.http
.get("http://www.example.com")
.map(this.save)
.catch(this.fail);
}
private save(response: Response) {
let testObject: TestObject = <TestObject> response.json();
return testObject || {};
}
private fail(error: any) {
return Observable.throw("error!");
}
}
AppComponent
[...]
export class AppComponent implements OnInit {
testObject: TestObject;
constructor(private testService: testService) {}
ngOnInit() {
this.testService.test().subscribe(
data => {
this.testObject = new TestObject();
console.log(this.testObject); // prints (empty) TestObject
this.testObject = data;
console.log(this.testObject); // prints object, not TestObject?
},
error => { }
);
}
}
Here my questions:
1) Why does my application print out (using Chrome Inspector) object and not TestObject as type?
2) The property testObject of class AppComponent should be of type TestObject. Why does my application not fail?
3) How can I achieve that I really get TestObject? What would be the best way to do it? Of course I could just manually fill up my TestObject, but I hoped there is some way of automatically mapping the json to my object.
Here is an answer that I wrote to a question which explained the handling of observables in angular2.
Angular 2 http post is returning 200 but no response is returned
Here you can see how I am handling the Response object as returned by the service. It is very important that you return your response object from the map function in service.
Similarly you can convert your response object to typescript type by casting your response object. The example can be:
this._loginService.login(this.username, this.password)
.subscribe(
(response) => {
//Here you can map the response to a type.
this.apiResult = <IUser>response.json();
//You cannot log your object here. Here you can only map.
},
(err) => {
//Here you can catch the error
},
() => {
//this is fired after the api requeest is completed.
//here you can log your object.
console.log(this.apiResult);
//result will only be shown here.
}
);
Here, it can be clearly seen that I am casting the response object to IUser type.
Another thing is while handling apiresponse in your component it is to be noted that the subscribe function has three arguments and if you will like to log your object, you must do it in the last function of subscribe.
Hope this helps!
your call must be like
ngOnInit() {
this.testService.test().subscribe(
(data) => {
this.testObject = new TestObject();
console.log(this.testObject); // prints (empty) TestObject
//only mapping
this.testObject = data;
},
error => { },
() => {
console.log(this.testObject);
}
);
}