Inject store into errorhandler class Angular - javascript

I am trying to implement sentry error handling into my application, now I have it set up and working as expected.. but now I want to be able to pass user information on the Sentry object for better error logging.
So I have the following setup
export class SentryErrorHandler implements ErrorHandler {
userInfo: UserInfo;
constructor(
private _store: Store<AppState>
) {
this.getUserInfo();
}
getUserInfo() {
this._store.select('userInfo')
.subscribe(result => {
this.userInfo = result;
});
}
handleError(err: any): void {
Sentry.configureScope((scope) => {
scope.setUser({
email: this.userInfo?.emailAddress,
id: this.userInfo?.id?,
});
});
const eventId = Sentry.captureException(err.originalError || err);
Sentry.showReportDialog({ eventId });
}
}
and I am providing the error handler like so in my root module
// ...
{ provide: ErrorHandler, useClass: SentryErrorHandler }
// ...
but what happens is, when I start my application I get the following error
Obviously im doing something wrong here, any help would be appreciated!

This error is happening because without the #Injectable decorator Angular cannot wire up dependencies for the class (even using it in providers).
So all you have to do is add the #Injectable() decorator in your error class.
See a demo here:
https://stackblitz.com/edit/angular-ctutia

Related

How to get this onfido cordova plugin to initialise properly?

Im trying to get this onfido cordova plugin to work but even though I get no errors it doesnt seem to do anything.
https://github.com/rewireltd1/cordova-plugin-onfido
This is a simple Ionic tutorial app which ive added a button to, which calls a method in my ts file to initialize the plugin.
import { Component } from '#angular/core';
#Component({
selector: 'page-hello-ionic',
templateUrl: 'hello-ionic.html'
})
export class HelloIonicPage {
applicantId: string = APPLICANT_ID
token: string = TOKEN
options: any;
constructor(
) {
this.options = {
token: this.token, // IMPORTANT: see notes
applicant_id: this.applicantId,
flow_steps: [ 'welcome', 'document', 'face', 'final'],
}
}
handleOnfido() {
try {
console.log(1)
window['cordova'].plugins.onfido.init((res) => {
console.log(res)
this.onComplete(res)
}, this.options)
console.log(2)
} catch (error) {
console.log('ERROR', error)
}
}
onComplete(completeResponse) {
console.log('in on complete', completeResponse)
}
}
The app successfully builds on my android and when I click the button I get the logs 1 and 2 so no errors but then nothing. From looking at the Github does it look like im doing anything wrong? Any assistance would be massively helpful.
Thanks

Nest.js - skip middleware based on header value

I have an application which uses nestjs and MiddlewareConsumer.
I would like to know if there's a way to skip a middleware based on a header value?
I checked documentation and saw that I can only use path or method (as I do now) but maybe there's something I'm missing?
Sample of my code:
export class AuthorizationModule implements NestModule {
configure(consumer: MiddlewareConsumer): void {
consumer.apply(DiscriminatorValidator).with(common.USERS).forRoutes(
{path: RELATIVE_RESOURCE_PATH, method: RequestMethod.POST},{path: RELATIVE_RESOURCE_PATH, method: RequestMethod.PUT});
consumer.apply(validate).forRoutes(AuthorizationController);
consumer.apply(HeadersValidator).with().forRoutes(AuthorizationController);
consumer.apply(ContextAndHeadersMiddleware).forRoutes(AuthorizationController);
}
}
This is not possible with the MiddlewareConsumer.
However, the middleware itself can check if its applicable or should be skipped:
#Injectable()
export class ContextAndHeadersMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: Function) {
if (req.get('my-header') === 'SKIP') {
// skip this middleware if header value is set
return next();
}
// middleware logic
}
}

Angular router.redirect doesn't populate variables

I am using Stripe checkout with my Angular 5 project and seem to be stuck on a router redirect / template lifecycle issue.
On user signup, I open the stripe checkout modal. When that modal get's a payment source token, I do some more API work and then do a router.redirect.
stripe.open({
email: 'foo#foo.com',
name: 'Subscription',
description: 'Basic Plan',
amount: 499,
token: (source) => {
this.http.post('/user/subscribe', { source: source.id }).subscribe(_ => {
this.router.navigate(['stylist/profile']);
});
}
});
The app redirects properly, but the variables do not display whatsoever. Below is an example of my page. Ideally, the redirect would trigger the ngOnInit and the test variable would be true. In my scenario, the test is displayed in the html template as blank.
Profile Route
{ path: 'stylist/profile', component: ProfilePageComponent, canActivate: [AuthGuard] },
Auth Guard
#Injectable()
export class AuthGuardService implements CanActivate {
constructor(
public auth: AuthService,
public router: Router,
public route: ActivatedRoute
) {}
canActivate(): boolean {
if (!this.auth.isAuthenticated()) {
this.router.navigate(['']);
return false;
}
return true;
}
}
Profile Page Component
export class ProfilePageComponent implements OnInit {
test: boolean = false;
ngOnInit() {
this.test = true;
}
}
Profile Page HTML
<div>Test variable: {{test}}</div>
This code has been simplified, but I wanted to make sure I wasn't missing any strange lifecycle events due to redirecting in a callback of a callback?
I've tried subscribing to various Router and ActivatedRoute events without any luck. I've also seen solutions involving ngZone, but those didn't seem to fit the bill either.
01/07/19 UPDATE
I was able to recreate this via stackblitz per the suggestion in the comments.
https://stackblitz.com/edit/angular-un9tfk
Upon initial load of the homepage, you can click the "Open Stripe" button and fill out some dummy data. The callback then redirects to /test with a warning message in the console.
Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?
I believe this points me to doing ngZone.run()... somewhere in my signup.component.ts, but not sure where just yet.
As stated in the edit above, it turns out using Router.navigate in a function callback is technically outside of an Angular zone.
Wrapping my Router.navigate in NgZone.run(() => {}) did the trick.
Implemented solution:
import { Component, Input, NgZone } from '#angular/core';
constructor(private zone: NgZone) { }
signup() {
stripe.open({
email: 'foo#foo.com',
name: 'Subscription',
description: 'Basic Plan',
amount: 499,
token: (source) => {
this.http.post('/user/subscribe', { source: source.id }).subscribe(_ => {
this.zone.run(() => {
this.router.navigate(['stylist/profile']);
});
});
}
});
}

Angular - Display server error in component

I'm currently working on a register page and therefore, I need to post my data to the server. The client-side validation and server-validation works. I know I can handle the client-side errors like *ngIf="(emailAddress.errors?.required || emailAddress.errors?.email) && emailAddress.touched". But how to handle the server-side errors?
In my service, if an error occurs, I simply give it into the component by return throwError(error);
But how can I know to display the specific error in my component if for example there is already someone with this email address? And how do distinguish between email/password validation errors server side?
Depends on the complexity and modules you have.
If you use any kind of state management library such as ngrx or ngxs, I suggest you do as follow:
Define State with a property 'error' which keeps track of the latest server-error.
Api call executed via actions and error is caught and stored to state also via actions. (Do whatever error mapping before saving the error to your State)
Use selectors for component to receive error stream from State.
If you don't have any state management library, you can create a BehaviorSubject within singleton service, and use it to publish server-error as soon as you got into any catchError context.
This way you can write your own http interceptor and have your response inside your component. Also in your component you know your http response is success or error.
You can implement other Http calls(GET, PUT, etc) and also handle your general errors in handleError() function.
app.module.ts
export class AppModule {
constructor() {}
imports: [
HttpClientModule,
],
providers: [
{
provide: Http,
useFactory: httpFactory,
deps: [HttpHandler]
},
],
}
export function httpFactory(httpHandler: HttpHandler) {
return new Http(httpHandler);
}
http.service.ts
export class Http extends HttpClient {
constructor(handler: HttpHandler) {
super(handler);
}
postCall(url: string, body, options?): Observable<any> {
return super.post(url, body, options)
.pipe(
tap(response => { console.log(response) }),
catchError(this.handleError(error)));
}
private handleError<T>(result?: T) {
return (error: any): Observable<T> => {
console.log(error);
return of(result as T);
};
}
}
your.component.ts
export class YourComponent {
constructor(private http: Http) {}
this.http.postCall('URL', {}).subscribe(response => {
if (response instanceof HttpErrorResponse) {
// Your Response is error
} else {
// Your Response is your desired result
}
}

Angular: Cannot read property 'insertNode' of undefined at TransitionAnimationEngine

I have created my own directive, that hides content if user is not logged: *onlyUser. When I try to use it in component that utilises ng/animation I sometimes get an error:
Cannot read property 'insertNode' of undefined at TransitionAnimationEngine
Directive looks like this:
export class OnlyUserDirective {
constructor(private _templateRef: TemplateRef<any>,
private _viewContainer: ViewContainerRef,
private _userContextService: UserContextService) {
this._userContextService.isLogged$().subscribe(x => {
if (x === true) {
this._viewContainer.createEmbeddedView(this._templateRef);
} else {
this._viewContainer.clear();
}
});
}
}
And when I try to use it within a component with #Component({ animations: [...] }) I sometimes get the error from this question's beginning. Is this expected behavior, or an angular bug?
It is a known bug -> https://github.com/angular/angular/issues/19712.
I am checking if it is working with Angular 5

Categories