I'm fairly new to AngularJS (2.0.0-beta.16). I've managed to setup a service that pulls data from an API, via a GET request. Now, how do I set it up to run the GET request every n seconds? I've seen other posts saying you could just using this._http.get(...).interval(5000).map(...);, however when I've tried that, I get a Typescript compilation error:
Property 'interval' does not exist on type 'Observable'.
Am I making a silly mistake or is there a better pattern for doing this?
import { Injectable } from 'angular2/core';
import { Http, Response } from "angular2/http";
import { Observable } from "rxjs/Observable";
import * as _ from "js/lodash.js";
import { Foo } from "./foo";
#Injectable()
export class FooService {
fooList: Observable<Foo[]>;
constructor(private _http: Http) {
this.fooList = this._http.get('http://localhost:9090/api/').map(
response => {
var json = response.json();
if(response.ok === true) {
let newFooList: Foo[] = [];
_.forEach(json, f => {
newFooList.push(new Foo(f));
});
return newFooList;
}
throw Error("Bad status: " + response);
});
}
}
This is probably not the only (or the best) way, but it worked for me. The only issue is that the first GET request is delayed by the amount of time specified by create().
import { Injectable } from "angular2/core";
import { Http, Response } from "angular2/http";
import { Observable } from "rxjs/Observable";
import { IntervalObservable } from "rxjs/observable/IntervalObservable";
import * as _ from "js/lodash.js";
import { API_URI } from "./constants";
import { Foo } from "./foo";
#Injectable()
export class FooService {
public fooList: Observable<Foo[]>;
constructor(private _http: Http) {
this.fooList = IntervalObservable.create(2000).flatMap(
() => {
return this._http.get(API_URI);
}).map(
response => {
var json = response.json();
if(response.ok === true) {
let newFooList: Foo[] = [];
_.forEach(json, f => {
newFooList.push(new Foo(f));
});
return newFooList;
}
throw Error("Bad status: " + response);
});
}
}
Related
So, when i get the info from the MongoDB database in a NestJS service, i want to return it to the controller and send it to the client (Angular)
I tried returning it with a Promise but i cant get it working.
Heres my code with the thing a tried:
Service:
import { Injectable } from "#nestjs/common";
import { InjectModel } from "#nestjs/mongoose";
import mongoose, { Model } from "mongoose";
import {
FriendRequest,
FriendRequestDocument,
} from "../schema/friend-requests.schema";
import { Users, UsersDocument } from "../schema/user.schema";
import { FriendsDto } from "./dto/friends.dto";
#Injectable()
export class AddFriendService {
constructor(
#InjectModel(Users.name) private readonly usersModel: Model<UsersDocument>,
#InjectModel("friendRequests")
private readonly friendrequestModel: Model<FriendRequestDocument>
) {}
async getRequests(userid: string) {
let incomingrqs = new Promise((resolve, reject) => {
let response = {
incoming: [],
};
this.friendrequestModel
.aggregate([
{
$lookup: {
from: "users",
localField: "author",
foreignField: "_id",
as: "userdata",
// pipeline: [
// {
// $match: {
// friend_id: new mongoose.Types.ObjectId(userid)
// }
// }
// ],
},
},
])
.exec((err, data) => {
if (err) {
console.log(err);
}
if (!data) {
console.log("No data returned");
}
data.forEach((rqsData) => {
response.incoming.push({
userid: rqsData.userdata[0]._id,
username: rqsData.userdata[0].username,
created_at: rqsData.userdata[0].created_at,
pfp: "/assets/cdn/pfp/" + rqsData.userdata[0].pfp,
});
});
});
resolve(response);
})
incomingrqs.then(x => {
return x;
})
}
}
Controller:
import { Get, Controller, Body, Post, Param } from "#nestjs/common";
import { AddFriendService } from "./friends.service";
import { FriendsDto } from "./dto/friends.dto";
#Controller("friends")
export class AddFriendController {
constructor(private friendsService: AddFriendService) {}
#Post("rqs")
async getRqs(#Body() friendsDto: FriendsDto){
let rqs = await this.friendsService.getRequests(friendsDto.userid);
console.log(rqs)
return rqs;
}
}
FriendRequestDocument:
import { Prop, Schema, SchemaFactory } from "#nestjs/mongoose";
import mongoose, { Document, ObjectId } from "mongoose";
export type FriendRequestDocument = FriendRequest & Document;
#Schema({collection: "friendRequests"})
export class FriendRequest {
#Prop()
author: mongoose.Types.ObjectId;
#Prop()
friend_id: mongoose.Types.ObjectId;
#Prop()
request_at: Date;
}
export const FriendRequestSchema = SchemaFactory.createForClass(FriendRequest);
Can you help me? Thanks!
aggregate.exec can already return a promise if no callback is given, just FYI.
You need to return the incomingrqs to the controller. This is standard of how promises work.. Returning inside the then forwards the return on to the next promise, which is why the incomingrqs needs to be returned as well. Otherwise, the controller will never know what the service returns.
I am trying to use this template to learn how to use graphql/apollo/prisma etc.
When I try to start the server, I get a confirmation in the console, but an error in the browser that says: GET query missing.
import "reflect-metadata"
import "dotenv/config"
import { ApolloServerPluginCacheControl, ApolloServerPluginLandingPageDisabled } from "apollo-server-core"
import { ApolloServer } from "apollo-server-express"
import jwt from "express-jwt"
import { buildSchema } from "type-graphql"
import { Container } from "typedi"
import { JWT_AUTH } from "./lib/config"
import { ExpressContext } from "./lib/express"
import { formatResponse } from "./lib/formatResponse"
import { ErrorInterceptor } from "./lib/globalMiddleware"
import { loadPrismaHooks } from "./lib/hooks"
import { loadCurrentUser } from "./lib/loadCurrentUser"
import { loadResolvers } from "./lib/loadResolvers"
import { prisma } from "./lib/prisma"
import { Server } from "./lib/server"
class App extends Server {
constructor() {
super()
this.init().catch((error) => {
this.logger.error(error)
process.exit(1)
})
}
async init() {
await this.setUpDb()
await this.setUpAuth()
await this.setupApollo()
this.start()
}
async setUpDb() {
await prisma.$connect()
loadPrismaHooks()
this.logger.info("DB ready")
}
async setUpAuth() {
this.app
.use(jwt(JWT_AUTH))
.use((err: any, _: any, __: any, next: any) => {
if (err.name === "UnauthorizedError") next()
})
.use(loadCurrentUser)
this.logger.info("Auth ready")
}
async setupApollo() {
const schema = await buildSchema({
container: Container,
resolvers: loadResolvers(),
globalMiddlewares: [ErrorInterceptor],
})
const apolloServer = new ApolloServer({
context: ({ req, res }: ExpressContext) => ({ req, res, prisma }),
formatResponse,
plugins: [ApolloServerPluginCacheControl(), ApolloServerPluginLandingPageDisabled()],
schema,
// playground: true,
// introspection: true
})
await apolloServer.start()
apolloServer.applyMiddleware({ app: this.app })
// I deleted cors: true from the above line
this.logger.info("Apollo setup hello")
}
}
new App()
I have seen other posts describing that cors is no longer needed (not sure what the basis for that is) and also suggesting that I add the playground and introspection arguments to the new ApolloServer. I tried this (as shown in the commented lines), but the playground is not recognised as a valid argument.
Server is defined in the lib folder as:
import "reflect-metadata"
import "dotenv/config"
import * as Sentry from "#sentry/node"
import * as Tracing from "#sentry/tracing"
import chalk from "chalk"
import express from "express"
import morgan from "morgan"
import { IS_PRODUCTION, PORT, SENTRY_DSN } from "./config"
export class Server {
private readonly _app: express.Application
readonly logger: {
info: (message: string) => void
error: (message: string) => void
}
constructor() {
this._app = express()
.use(Sentry.Handlers.requestHandler())
.use(Sentry.Handlers.tracingHandler())
.enable("trust proxy")
.use(
morgan("dev", {
skip: (req) => req.method === "OPTIONS",
stream: { write: (message) => console.log(message + "\n\n") },
}),
)
if (IS_PRODUCTION) {
Sentry.init({
dsn: SENTRY_DSN,
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
new Tracing.Integrations.Express({ app: this._app }),
],
enabled: IS_PRODUCTION,
tracesSampleRate: 1.0,
})
}
this.logger = {
info: this.info,
error: this.error,
}
}
protected error(message: string) {
console.log(`[${chalk.red("ERROR")}] `, message)
}
protected info(message: string) {
console.log(`[${chalk.blue("INFO")}] `, message)
}
protected get app(): express.Application {
return this._app
}
start(): void {
this._app
.use(Sentry.Handlers.errorHandler())
.listen(PORT, () => this.logger.info(`Server started at http://localhost:${PORT}/graphql 🚀` + "\n"))
}
}
The console logs in the terminal print the server started confirmation, but the browser just generates the cannot GET message. I don't know what this message means, to be able to begin to try and figure out how to get to the playground.
Can anyone recommend current instructions for how to configure the server?
the reason for this problem seems to be related to the move to the graphql sandbox environment. If you add localhost555 to the sandbox address bar, the page loads without an error.
hello every one I had a problem, I create my Ticketservice. this file and I try to add it to the home.ts file but it gives me an error
tickerServices.ts
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root',
})
export class TicketService{
result:any;
constructor(public http: HttpClient) { }
getTicket(){
var CronJob = require('cron').CronJob;
var id=this.formulaire.id;
new CronJob('* * * * * *', function(){
const http = require('http');
console.log('You will see this message every second');
/* this.url+'/'*/
http.get('http://localhost:8888/'+id+'/notif', (resp) => {
let data = '';
// A chunk of data has been recieved.
resp.on('data', (chunk) => {
data += chunk;
this.resulta=data;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
console.log(data);
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
}, null, true, 'America/Los_Angeles');
}
}
home.ts
import {Component} from "#angular/core";
import {NavController, PopoverController,NavParams} from "ionic-angular";
import { HttpClient } from '#angular/common/http';
import { TicketService } from '../services/ticketservice'
import 'rxjs/add/operator/map';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
public search = {
date: new Date().toISOString()
}
constructor(public nav: NavController,public http: HttpClient,public popoverCtrl: PopoverController ,public tikSer:TicketService) {
}}
when I test it, he gives me undefined ".. /services/ticketservice"
Add it like this
import { TicketService } from '../../services/ticketservice'
I want to call a Rest-Service (Spring MVC) to receive a list of releases. On client side (AngularJs) I use a service creating a HttpClient call. I also have a registered HttpInterceptor to use simple Basic Authentification. The interceptor is provided in app.modules.ts and is called during the rest call.
Unfortunately I get statuscode 401 and I cannot find the 'Authentification' entry in the header. What is missing?
Interceptor:
import { Injectable } from '#angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable()
export class BasicAuthInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
request = request.clone({
setHeaders: {
Authorization: `Basic username:password`
},
});
return next.handle(request);
}
}
Service class:
import { Injectable } from '#angular/core';
import { Observable, of } from 'rxjs/';
import { HttpClient } from '#angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';
import { Release } from './Release';
#Injectable()
export class ReleasesService {
constructor(
private http: HttpClient) {}
private releasesUrl = 'http://localhost:8080/releases/showAll';
getReleases(): Observable<Release[]> {
return this.http
.get<Release[]>(this.releasesUrl)
.pipe( tap(releases => this.log('fetched releases')),
catchError(this.handleError('getReleases', [])));
}
private handleError<T> (operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.error(error); // log to console instead
return of(result as T);
};
}
private log(message: string) {
console.info(message);
}
}
app.modules.ts
providers: [
APP_PROVIDERS,
{ provide: HTTP_INTERCEPTORS, useClass: BasicAuthInterceptor, multi: true },
],
I found the solution.
Setting the header was correct. But I had to add following parameter to the HttpClient-call: { withCredentials: true }
getReleases(): Observable<Release[]> {
return this.http
.get<Release[]>(this.releasesUrl, { withCredentials: true })
.pipe( tap(releases => this.log('fetched releases')),
catchError(this.handleError('getReleases', [])));
}
Then the credentials are passed to the server.
I have the following code for my service
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import {Response} from "angular2/http";
import {PRIVATE_SERVERS} from "../mock/private_servers_list";
import 'rxjs/Rx';
/*import {PRIVATE_SERVERS} from "../mock/private_servers_list";*/
#Injectable()
export class PrivateServerService {
http= null;
PRIVATE_SERVERS = null;
constructor(http:Http){
this.http = http;
}
logError(err){
console.log("some error");
}
getPrivateServers(){
this.http.get('http://private-server.eviry.com/get_private_servers')
.map(res => res.json())
.subscribe(
data => this.PRIVATE_SERVERS = data, //printing data here gives me the correct value
err => this.logError(err),
() => console.log('Private Server fetching complete')
);
console.log(this.PRIVATE_SERVERS);
return this.PRIVATE_SERVERS;
}
}
I have injected this service in to a component called private-server.component. Basically, in this service I am trying to get a list of private servers using the url http://private-server.eviry.com/get_private_servers
I access this url in getPrivateServers() function. When I print the response within the subscribe method, I can see the data fetched correctly.
However, when I try to console.log(this.PRIVATE_SERVERS), it prints null. Is this the correct way to use the angular service or is there a way to make it wait for the response?
The assignment happens in an asynchronous callback. If you want to use its value outside that callback, you need to wait for it to complete.
You can also use Event Emitter to react asynchronous to the response.
Here is an good introduction to Observables in Angular2.
PrivateServerService.ts
import { Injectable } from 'angular2/core';
import { Http } from 'angular2/http';
import { Response } from "angular2/http";
import { PRIVATE_SERVERS } from "../mock/private_servers_list";
import 'rxjs/Rx';
/*import {PRIVATE_SERVERS} from "../mock/private_servers_list";*/
#Injectable()
export class PrivateServerService {
PRIVATE_SERVERS = null;
constructor(private http: Http) {
this.setPrivateServerMocksData();
}
logError(err) {
console.log("some error");
}
getPrivateServers() {
return this.http.get('http://private-server.eviry.com/get_private_servers')
.map(res => res.json());
}
setPrivateServerMocksData() {
this.getPrivateServers()
.subscribe((data) => {
this.PRIVATE_SERVERS = data
console.log(this.PRIVATE_SERVERS);
},
(err) => {
this.logError(err)
});
}
}
YourComponent.ts
getPrivateServerInfo() {
this.privateServerService.getPrivateServers()
.subscribe((data) => {
//you have your data here to work with
console.log(data);
},
(err) => {
this.logError(err)
});
}