Here's I have attached my code. I have implemented global handler and now I need to extract 'dashboard' from 500 Error on zone.js. How can I get it in the global Handler. Is there any way that I can get my desired output?
import { ErrorHandler, Injectable, Injector, NgZone } from '#angular/core';
import { LocationStrategy, PathLocationStrategy } from '#angular/common';
import { LogService } from './logging-service.service';
import * as StackTrace from 'stacktrace-js';
#Injectable()
export class GlobalErrorHandler implements ErrorHandler {
private errors = new Array<any>();
constructor(public injector: Injector, public zone: NgZone) {
}
public handleError(error: any) {
console.log('Im a global handler', JSON.parse(error));
const logService = this.injector.get(LogService);
const location = this.injector.get(LocationStrategy);
const message = error.message ? error.message : error.toString();
const url = location instanceof PathLocationStrategy
? location.path() : '';
const callbackFun = function (stackframes) {
const stringifiedStack = stackframes.map(function (sf) {
return sf.toString();
}).join('\n');
console.log(stringifiedStack);
};
const errback = function (err) {
console.log(err);
console.log(err.stack);
};
window.onerror = function (msg, file, line, col, error) {
// this.zone.fromError.subscribe(this.onZoneError);
StackTrace.fromError(message).then(callbackFun).catch(errback);
StackTrace.get().then(callbackFun).catch(message);
};
const handleErrorData = {
// Some Json to send to server
};
logService.logError(handleErrorData);
throw error;
}
public onZoneError(error) {
console.log(error);
console.error('Error', error instanceof Error ? error.message : error.toString());
}
}
Implement an HttpInterceptor (requires Angular 4.3.x)
From there listen to errors and extract the request url and split it into its parts.
Related
I am trying to validate json request in my nestjs app using my custom validation pipe class "SchemaValidationPipe" which throws BadRequestException. My global exception filter is not catching the exception thrown from validation pipe.
If I throw exception from controller class then global exception filter is able to catch the exception.
#Injectable()
export class SchemaValidationPipe implements PipeTransform<any> {
constructor(private schema: any) {}
transform(value: any, metadata: ArgumentMetadata) {
const schemaValidator = new JsonValidator(this.schema);
schemaValidator
.validate(value)
.then((data) => {
if (data) {
const { isValid, message } = data;
if(!isValid) throw new BadRequestException( { status : '500', message : 'Validation failed' } );
}
return Promise.resolve(value);
})
.catch((err) => {
throw new BadRequestException('Validation failed');
});
}
}
#Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter<HttpException> {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
Looks like you don't return the provide from the validate method, so it's considered void. This means that the promise will run outside of the bound request lifecycle and can end up throwing an unhandled provide rejection. You should just need to add return schemaValidator.validate...
I am able to solve to problem by making transform method as async in SchemaValidationPipe class
#Injectable()
export class SchemaValidationPipe implements PipeTransform<any> {
constructor(private schema: any) {}
async transform(value: any, metadata: ArgumentMetadata) {
const schemaValidator = new JsonValidator(this.schema);
try {
const { isValid, message } = await schemaValidator.validate(value);
if(!isValid) throw new BadRequestException( 'Validation failed' );
} catch (err) {
throw new BadRequestException('Validation failed');
}
}
}
My code is working properly on local environment but notifications arn't working on production. I'm using angular 8. Firebase 7.6.0 is being used.
When I am sending push notification from firebase console, it is working fine but when some request is hitting from live server admin panel then notifications are not sent. Node.js is used for Backend.
constructor(private messagingService: MessagingService){
if ("serviceWorker" in navigator) {
console.log('--------in service qorker condition')
window.addEventListener("load", function() {
navigator.serviceWorker.register("./firebase-messaging-sw.js").then(
function(registration) {
console.log(
"ServiceWorker registration successful with scope: ",
registration.scope
);
},
function(err) {
// registration failed :(
console.log("ServiceWorker registration failed: ", err);
}
);
});
}
}
ngOnInit() {
// const userId = 'user001';
// this.messagingService.requestPermission(userId);
this.messagingService.receiveMessage();
}
Above is app.component.ts constructor call
import { Injectable } from '#angular/core';
import { AngularFireMessaging } from '#angular/fire/messaging';
import { BehaviorSubject } from 'rxjs'
import { AngularFireDatabase } from '#angular/fire/database';
import { AngularFireAuth } from '#angular/fire/auth';
import { take } from 'rxjs/operators';
#Injectable()
export class MessagingService {
token: any = "";
currentMessage = new BehaviorSubject(null);
constructor(private angularFireDB: AngularFireDatabase,
private angularFireAuth: AngularFireAuth,
private angularFireMessaging: AngularFireMessaging) {
this.angularFireMessaging.messaging.subscribe(
(_messaging) => {
_messaging.onMessage = _messaging.onMessage.bind(_messaging);
_messaging.onTokenRefresh = _messaging.onTokenRefresh.bind(_messaging);
}
)
}
updateToken(userId, token) {
// we can change this function to request our backend service
this.angularFireAuth.authState.pipe(take(1)).subscribe(
() => {
const data = {};
data[userId] = token
this.angularFireDB.object('fcmTokens/').update(data)
})
}
requestPermission(userId) {
this.angularFireMessaging.requestToken.subscribe(
(token) => {
console.log(token);
this.token = token;
this.updateToken(userId, token);
},
(err) => {
console.error('Unable to get permission to notify.', err);
}
);
}
receiveMessage() {
this.angularFireMessaging.messages.subscribe((payload: any) => {
if (payload) {
console.log(payload, '----lasjkdfl');
navigator.serviceWorker.ready.then(function(service_worker) {
service_worker.showNotification(payload.notification.title, {
body: payload.notification.body
});
});
console.log("new message received. ", payload);
this.currentMessage.next(payload);
}
else{
console.log("no payload recieved");
}
});
}
}
Above is messaging service
this.messagingService.requestPermission(userId);
this.messagingService.receiveMessage();
this.message = this.messagingService.currentMessage;
Above code is called in login.component.ts
importScripts('https://www.gstatic.com/firebasejs/7.6.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/7.6.0/firebase-messaging.js');
Above is firebase-messaging-sw.js configuration
I'm displaying a LoadingController when the user tries to login. Meanwhile, an API is being called.
I’m able to dismiss the LoadingController when I get a SUCCESS response from subscribe, but when I get an ERROR response, I’m not able to dismiss. Please help!
I’m a professional Python developer and a total newbie to Ionic, just started a day ago. So, please assist as such.
import { Component, OnInit } from '#angular/core';
import { ToastController, LoadingController } from '#ionic/angular';
import { CallapiService } from '../callapi.service';
#Component({
selector: 'app-login',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {
userEmail = '';
userPassword = '';
loginUrl = 'login/';
loginMethod = 'POST';
postBody = {};
constructor(
public toastController: ToastController,
public loadingController: LoadingController,
private callApiService: CallapiService,
) { }
ngOnInit() {
}
async presentToast(displayMessage) {
const toast = await this.toastController.create({
message: displayMessage,
duration: 2000,
position: 'middle',
});
return await toast.present();
}
async presentLoading(loadingMessage) {
const loading = await this.loadingController.create({
message: loadingMessage,
});
return await loading.present();
}
loginUser() {
if (this.userEmail === '' || this.userPassword === '') {
this.presentToast('Email and password are required.');
}
else {
this.presentLoading('Processing...');
this.postBody = {
email: this.userEmail,
password: this.userPassword,
};
this.callApiService.callApi(this.loginUrl, this.postBody, this.loginMethod).subscribe(
(success) => {
console.log(success);
this.loadingController.dismiss();
},
(error) => {
console.log(error);
this.loadingController.dismiss();
}
);
this.loadingController.dismiss();
}
}
}
Without any service,
Same issue I faced while using Ionic 4 loading controller.
After trial and error I got working solution.
As loading controller functions are using async and await because both are asynchronous functions.
dismiss() function will called before present() function because, dismiss function will not wait until creating and presenting the loader, it will fire before present() as soon function will call.
Below is working code,
loading:HTMLIonLoadingElement;
constructor(public loadingController: LoadingController){}
presentLoading() {
if (this.loading) {
this.loading.dismiss();
}
return new Promise((resolve)=>{
resolve(this.loadingController.create({
message: 'Please wait...'
}));
})
}
async dismissLoading(): Promise<void> {
if (this.loading) {
this.loading.dismiss();
}
}
someFunction(){
this.presentLoading().then((loadRes:any)=>{
this.loading = loadRes
this.loading.present()
someTask(api call).then((res:any)=>{
this.dismissLoading();
})
})
}
this.callApiService.callApi(this.loginUrl, this.postBody, this.loginMethod)
.subscribe(
(data) => {
// Called when success
},
(error) => {
// Called when error
},
() => {
// Called when operation is complete (both success and error)
this.loadingController.dismiss();
});
Source: https://stackoverflow.com/a/54115530/5442966
Use Angular property binding. Create a component to your loading:
import { Component, Input } from '#angular/core';
import { LoadingController } from '#ionic/angular';
#Component({
selector: 'app-loading',
template: ''
})
export class LoadingComponent {
private loadingSpinner: HTMLIonLoadingElement;
#Input()
set show(show: boolean) {
if (show) {
this.loadingController.create().then(loadingElem => {
this.loadingSpinner = loadingElem;
this.loadingSpinner.present();
});
} else {
if (this.loadingSpinner) {
this.loadingSpinner.dismiss();
}
}
}
constructor(private loadingController: LoadingController) {}
}
...then in 'login.page.html' use your componente:
...
<app-loading [show]="showLoading"></app-loading>
... in 'LoginPage' create a property 'showLoading' and set it to true or false where you whant:
//.... some source code
export class LoginPage implements OnInit {
showLoading;
userEmail = '';
userPassword = '';
loginUrl = 'login/';
loginMethod = 'POST';
postBody = {};
//.... some source code
loginUser() {
if (this.userEmail === '' || this.userPassword === '') {
this.presentToast('Email and password are required.');
} else {
this.showLoading = true;
this.postBody = {
email: this.userEmail,
password: this.userPassword
};
this.callApiService
.callApi(this.loginUrl, this.postBody, this.loginMethod)
.subscribe(
success => {
console.log(success);
this.showLoading = false;
},
error => {
console.log(error);
this.showLoading = false;
}
);
this.showLoading = false;
}
}
}
This works for me, I reuse the loading component on others pages!
Recommended reading: https://angular.io/start
I actually ran into this exact issue and for me the answer was just to use await.
The functions for both creating and dismissing loaders return promises. What I realized was happening is that the subscribe/promise rejection was halting all other promises from completing. Now, I just await both presenting and dismissing and I have no issue:
async getData() {
//await presenting
await this.presentLoading('Loading...');
try {
let response = await this.httpService.getData();
await this.loadingController.dismiss();
//...
catch(err) {
this.loadingController.dismiss();
//handle error
//...
}
}
async presentLoading(msg: string) {
const loading = await this.loadingController.create({
spinner: 'crescent',
message: msg
});
await loading.present();
}
I hope this simple solution helps!
When I'm trying to subsrcibe to a post request, it always returns the TypeError: result is null
I'm using a Angular CLI that connects with a Spring boot application, with a simple login page. Where I want to save the header of my response in local storage
This is the stacktrace:
"LoginComponent.prototype.login/<#webpack-internal:///../../../../../src/app/components/login/login.component.ts:32:13\nSafeSubscriber.prototype.__tryOrUnsub#webpack-internal:///../../../../rxjs/_esm5/Subscriber.js:245:13\nSafeSubscriber.prototype.next#webpack-internal:///../../../../rxjs/_esm5/Subscriber.js:192:17\nSubscriber.prototype._next#webpack-internal:///../../../../rxjs/_esm5/Subscriber.js:133:9\nSubscriber.prototype.next#webpack-internal:///../../../../rxjs/_esm5/Subscriber.js:97:13\nMapSubscriber.prototype._next#webpack-internal:///../../../../rxjs/_esm5/operators/map.js:88:9\nSubscriber.prototype.next#webpack-internal:///../../../../rxjs/_esm5/Subscriber.js:97:13\nFilterSubscriber.prototype._next#webpack-internal:///../../../../rxjs/_esm5/operators/filter.js:92:13\nSubscriber.prototype.next#webpack-internal:///../../../../rxjs/_esm5/Subscriber.js:97:13\nMergeMapSubscriber.prototype.notifyNext#webpack-internal:///../../../../rxjs/_esm5/operators/mergeMap.js:156:13\nInnerSubscriber.prototype._next#webpack-internal:///../../../../rxjs/_esm5/InnerSubscriber.js:27:9\nSubscriber.prototype.next#webpack-internal:///../../../../rxjs/_esm5/Subscriber.js:97:13\nonLoad#webpack-internal:///../../../common/esm5/http.js:2310:21\nZoneDelegate.prototype.invokeTask#webpack-internal:///../../../../zone.js/dist/zone.js:421:17\nonInvokeTask#webpack-internal:///../../../core/esm5/core.js:4939:24\nZoneDelegate.prototype.invokeTask#webpack-internal:///../../../../zone.js/dist/zone.js:420:17\nZone.prototype.runTask#webpack-internal:///../../../../zone.js/dist/zone.js:188:28\nZoneTask.invokeTask#webpack-internal:///../../../../zone.js/dist/zone.js:496:24\ninvokeTask#webpack-internal:///../../../../zone.js/dist/zone.js:1517:9\nglobalZoneAwareCallback#webpack-internal:///../../../../zone.js/dist/zone.js:1543:17\n"
This is my login.service.ts:
const httpOptions = { headers: new HttpHeaders({'Content-type': 'application/json'}) };
#Injectable() export class LoginService {
private loginUrl = 'https://music-makers.herokuapp.com/login';
constructor(private http: HttpClient) { }
public login(user: User): Observable<any> {
return this.http.post(this.loginUrl, user, httpOptions); }
And my login.components.ts:
export class LoginComponent implements OnInit {
model: any = {};
constructor(private loginService: LoginService, public router: Router) {
}
ngOnInit() {
}
login() {
const user = <User>({
email: this.model.email,
password: this.model.password,
});
console.log('email: ' + user.email + '\npass: ' + user.password);
this.loginService.login(user)
.subscribe(
result => {
// Handle result
localStorage.setItem('Authorization', result.headers.get('Authorization'));
console.log(result);
},
error => {
// Handle error
console.log('Error');
},
() => {
console.log('complete');
// No errors, route to new page
}
);
}
}
Your service should be use map() to return as an observable collection
public login(user: User): Observable<any> {
return this.http.post(this.loginUrl, user, httpOptions)
.map(responce => <any>responce)
.catch(error => {
return Observable.throw(error);
});
}
I can't find my error.
app.module.ts
...
providers: [ValidateService,AuthService]
...
I do the following in my register.component.ts:
import {AuthService} from '../../services/auth.service';
...
constructor( private _validateService: ValidateService,
private _fms: FlashMessagesService,
private _authService: AuthService,
private _router: Router
) { }
...
ngOnInit() {
this._authService.uniqueUser({username:'zomh'}).subscribe(data => {
console.log("data.success: "+data.success);
if(!data.success) { // Username already exists
console.log('exists');
}
else {
console.log('does not exist');
}
});
}
Works as expected the user is already in the database therefore I get the a user exists in the console.
I do pretty pretty much the very same thing (I broke it down to this point) in my validate.service.ts:
import { AuthService } from './auth.service';
import { Injectable } from '#angular/core';
import { FormControl } from '#angular/forms';
#Injectable()
export class ValidateService {
constructor( public _authService: AuthService) { }
validateRegister(user) {
if(user.name == undefined || user.email == undefined || user.username == undefined || user.password == undefined)
return false;
else
return true;
}
validateEmailPattern(c: FormControl) {
const re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (re.test(c.value))
return null;
else
return {invalidPattern:true};
}
validateUsernamePattern(c: FormControl) {
const re = /^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/
if (re.test(c.value))
return null;
else
return {invalidPattern:true};
}
validateUsernameIsUnique (c: FormControl) {
let ret:any;
if (c.value.length >= 3)
{
console.log(c.value);
this._authService.uniqueUser({username:'zomh'}).subscribe(data => {
if(!data.success) { // Username already exists
console.log('call from service: exists');
}
else {
console.log('call from service: does not exist');
}
});
}
return {usernameIsTaken:true};
}
}
But here I get a Cannot read property _authService of undefined Exception
For me it looks like the service did not inject correctly. But I can't find my error.
Update 1:
So i did copy the auth Service call into the Constructor and its working. Therefore it has to be some this. related error (?) i can't get the value of this._authService from any other method outside of the constructor ?
#Injectable()
export class ValidateService {
constructor( private _authService: AuthService ) {
this._authService.uniqueUser({ username: 'zomh' }).subscribe(data => {
if (!data.success) { // Username already exists
console.log('call from service: exists');
}
else {
console.log('call from service: does not exist');
}
});
}
I dont think you can have a new line between #Injectable and export class ValidateService {
Try it without that line.
After reading an article I rewrote my method into an instance method:
validateUsernameIsUnique = (c: FormControl) => {
let ret: any;
if (c.value.length >= 3) {
this._authService.uniqueUser({ username: c.value }).subscribe(data => {
if (!data.success) { // Username already exists
console.log('call from service: exists');
}
else {
console.log('call from service: does not exist');
}
});
}
...
It fixed the problem. I am still not sure why this had to be done though, feel free to add knowledge