NestJS: How to setup ClassSerializerInterceptor as global interceptor - interceptor

I'm using in every Controller code like #UseInterceptors(ClassSerializerInterceptor) so I decided make it global and was trying to setup it with no luck.
I was trying without and with new and ended up with something like this totally not working.
app.useGlobalInterceptors(new ClassSerializerInterceptor(new Reflector()));
I checked NestJS source code and I assume that it cannot be used as global but it should.

Have you tried using this line of code:
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));

I do prefer injecting global interceptors inside app.modules.ts instead.
Global interceptors registered from outside of any module with useGlobalInterceptors() cannot inject dependencies since this is done outside the context of any module.
import { ClassSerializerInterceptor, Module } from '#nestjs/common';
import { APP_INTERCEPTOR } from '#nestjs/core';
#Module({
providers: [
{
provide: APP_INTERCEPTOR,
useClass: ClassSerializerInterceptor,
},
],
})
export class AppModule {}
Reference:
How to use Service in Global-interceptor in NEST Js
https://docs.nestjs.com/interceptors#binding-interceptors

Related

How to inject AngularJS dependencies while calling from Angular module

I am trying to host a simple hybrid application (AngularJS + Angular 7). I was able to set the basic and bootstrap both the modules based on the guidelines. I was able to establish the communication from AngularJS to Angular.
I followed the guidelines for injecting AngularJS service in the Angular module ( https://angular.io/guide/upgrade ). However, I see there are few issues that I am stuck with which could be a basic set up which I am trying to understand.
Here is the real issue, When I try to call the AngularJS service from Angular, it fails during the run time stating the dependency injected in AngularJS service is undefined. For ex: $http is not defined.
My question is, do I need to inject this dependency through a provider in the Angular module, I have a provider which injects the service itself to the Angular module. Any help with the guidelines or standards would be helpful.
Here is the format of my AngularJS service. At present, I am modifying this to class and trying to invoke from Angular
function GetUsers( $http, OtherDependency) {
return {
getUsers: getUsers
}
function getUsers(userID, key, phrase) {
//$http is used inside this method
}
In angular, I am injecting this service through a provider and trying to use this service by instantiating through its constructor
Since your stackbliz demo is not runnable, from my project, I just create a Angular SharedModule and inject angularjs services to provider like below:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
export function getToastrService($injector: any) {
return $injector.get('toastr');
}
export function getLoadingService($injector: any) {
return $injector.get('loadingService');
}
#NgModule({
imports: [
CommonModule
],
exports: [
NgxComponentsModule
],
providers: [
{ provide: 'toastr', deps: ['$injector'], useFactory: getToastrService },
{ provide: 'loadingService', deps: ['$injector'], useFactory: getLoadingService }
]
})
export class NgxSharedModule { }
And then in my Angular business module, import SharedModule, and then only need to use DI in constructor:
constructor(#Inject('toastr') public toastr: any,
private notifyService: NotifyService) { }
Hope it will work for you.

How to use 3rd party AngularJS (1.6) module (angular-translate) in Angular (2 or 4)

The case
I am in the process of upgrading an AngularJS (i.e. Angular 1.6) application to Angular (i.e. Angular 4.1.3). I chose to do the incremental upgrade so currently both AngularJS and Angular are bootstrapped and running. So far so good, but: One of the AngularJS services that should be rewritten to Angular relies on a well known service $translate which is part of the 3rd party AngularJS (read Angular 1) module pascalprecht.translate. In other words, $translate service is injected to MyService which should become an Angular (read Angular 4) service.
MyService (stripped down) looks like this:
import { Injectable } from '#angular/core';
#Injectable()
export class MyService {
// Here comes the injection (how to do it?).
constructor(private $translate: $translate) {
}
foo() {
// Use the service
this.$translate('HELLO_WORLD');
}
}
It is located within MyModule:
import { NgModule } from '#angular/core';
import { MyService } from './my.service';
#NgModule({
providers: [
MyService
]
})
export class MyModule {
}
The problem
Now, how can I inject $translate into MyService when MyService resides within an Angular module while $translate is part of a 3rd party AngularJS module?
I know how to inject an AngularJS service into an Angular service if the AngularJS service is located within the same module (or at least the module is part of my own solution). It is explained in the official docs. Is there any way to handle a 3rd party service? Do I need to register that service within MyModule's providers?
import { NgModule } from '#angular/core';
import { MyService } from './my.service';
// How this line should look line then?
import { $translate } from 'node_modules/angular-translate/...';
#NgModule({
providers: [
MyService,
$translate
]
})
export class MyModule {
}
Or am I trying to achieve impossible?
Well, after a few hours of struggling I've finally found the solution. Here it is:
Upgrade the 3rd party service
First of all, follow the Angular's official guidelines and upgrade the provider of the 3rd party service - $translate. Like this:
ajs-upgraded-providers.ts
import { InjectionToken } from '#angular/core';
import { downgradeInjectable } from '#angular/upgrade/static';
import 'angular-translate';
// Variable 'i' holds the standard AngularJS injector
export function $translateFactory(i: any) {
return i.get('$translate');
};
// There is no class representing the good old $translate service so we have
// a non-class dependency. Therefore we use an InjectionToken (Angular 4) or
// OpaqueToken (Angular 2).
export let $translate = new InjectionToken('$translate');
// Finally create the upgraded provider
export const $translateProvider = {
provide: $translate,
useFactory: $translateFactory,
deps: ['$injector']
};
One thing to notice, the $translate service might be dependent on other old AngularJS services like (in my case) $translateStaticFilesLoader or $translateMessageFormatInterpolation. If this is also your case, be sure to extend the code above and make upgraded providers for those services as well (keep them in the same file).
Make sure the import statement works
The angular-translate is installed as a node module so the statement
import 'angular-translate';
works just fine if your tsconfig.json is set up to use moduleResolution: "node".
Then, of course, you need to ensure that the import statement will work even after the code is transpiled from TypeScript to ES5 (or whichever target you use) and picked up by a module loader (SystemJS in my case).
Notice that we imported the angular-translate script without getting anything from it, just to cause side effects. Basically, the import ensures that the script containing the desired service $translate is simply executed and registers $translate service for the AngularJS $injector.
Register the upgraded provider in Angular module
Now ensure that the new upgraded provider of $translate service is registered among other providers of MyModule.
my.module.ts
import { NgModule } from '#angular/core';
import { MyService } from './my.service';
import { $translateProvider } from './ajs-upgraded-providers';
#NgModule({
providers: [
MyService,
$translateProvider
]
})
export class MyModule {
}
Use it
Finally, use the $translate service in MyService.
my.service.ts
import { Injectable, Inject } from '#angular/core';
import { $translate } from './ajs-upgraded-providers';
#Injectable()
export class MyService {
// Notice the usage of InjectionToken
constructor(#Inject($translate) private $translate: any) {
}
foo() {
this.$translate('hello.world').then((translation: string) => {
console.log(translation);
});
}
}

Migration to Angular2: How to use injected AngularJS dependencies

How Am I supposed to use an AngularJS dependency during migration to Angular2 outside the constructor? I am using upgrade module and service is not yet upgraded.
So the answer was partially Making AngularJS Dependencies Injectable to Angular but it was not demonstrated how to make it available outside the constructor.
Here is an example for the $log angularJS service.
Create ajs-upgraded-providers.ts where we declare the provider:
/**
* $log upgraded provider
*/
export abstract class Log {
[key: string]: any;
}
export function logFactory(i: any) {
return i.get('$log');
}
export const logProvider = {
provide: Log,
useFactory: logFactory,
deps: ['$injector']
};
Import to app.module.ts the declared provider:
import { logProvider } from './ajs-upgraded-providers';
#NgModule({
imports: [
//imports
],
providers: [
//Providers & Services
//Upgraded angularJS providers
logProvider
]
})
example.service.ts How to use the angularJS service while migration takes place:
import { Log } from '../ajs-upgraded-providers'; //edit path accordingly
#Injectable()
export class ExampleService {
constructor(private $log: Log) {}
exampleFunction() {
this.$log.info("Info to be logged");
}
}
Making AngularJS Dependencies Injectable to Angular
When running a hybrid app, we may bump into situations where we need to have some AngularJS dependencies to be injected to Angular code. This may be because we have some business logic still in AngularJS services, or because we need some of AngularJS's built-in services like $location or $timeout.
In these situations, it is possible to upgrade an AngularJS provider to Angular. This makes it possible to then inject it somewhere in Angular code. For example, we might have a service called HeroesService in AngularJS:
import { Hero } from '../hero';
export class HeroesService {
get() {
return [
new Hero(1, 'Windstorm'),
new Hero(2, 'Spiderman')
];
}
}
We can upgrade the service using a Angular Factory provider that requests the service from the AngularJS $injector.
We recommend declaring the Factory Provider in a separate ajs-upgraded-providers.ts file so that they are all together, making it easier to reference them, create new ones and delete them once the upgrade is over.
It's also recommended to export the heroesServiceFactory function so that Ahead-of-Time compilation can pick it up.
— Angular Developer Guide - Upgrading (Making AngularJS Dependencies Injectable)

No provider for $scope! error when using a angular 1 directive in an angular 2 app

I have an angular 2 App built with angular-cli and I need to use an angular 1 directive in one of my components (to re-use it from a different application). I followed the steps from:
https://angular.io/docs/ts/latest/guide/upgrade.html#!#using-angular-1-component-directives-from-angular-2-code
But now I got to this error and cannot get past it. I am using angular2.0.2 (I managed to build a hybrid app in the past with the beta version but it was an angular1 app and I used angular 2 components with downgrade function of the adapter).
In my app.module.ts I have:
import { UpgradeAdapter } from '#angular/upgrade';
const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule));
const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail');
#NgModule({
imports: [
BrowserModule,
...
],
declarations: [
...
HeroDetail
]
})
export class AppModule { }
and my hero-detail.component.ts looks like this:
export const heroDetail = {
templateUrl: 'hero-detail.html',
controller: function() {
}
};
and my hero-detail.html looks like this:
<h2>Windstorm details!</h2>
I try to use the directive in another angular 2 component simply by adding in the template:
When I run ng serve, the application compiles fine but when I try to load the page I get the mentioned error.
Any suggestions on how I can move forward with this?
It seems you have incorrect bootstrap logic.
It's actually not quite obvious, make sure that:
you don't bootstrap any ng2 component with #NgModule({bootstrap:[ ... ]}). Instead, you should have empty ngDoBootstrap() { } method in your main module.
root template is ng1 template. I.e. in your index.html you should have only ng1 components or downgraded ng2 components. You can have ng2 component as a root, but you need to downgrade it first.
Official upgrade guide contains an example of DOM structure:
... which ensures that ng2 injectors have all required providers from ng1.

How to inject upgraded Angular 1 service/factory to Angular 2 component in ES5?

I have an Angular1 service with name, say, 'myService'
I then upgraded it using the Angular2 UpgradeAdapter like this:
var upgradeAdapter = new ng.upgrade.UpgradeAdapter();
upgradeAdapter.upgradeNg1Provider('myService');
Now I need to inject it to the angular2 component. Official upgrade guide only has typescript version for now. In typescript you use #Inject anotation with the service name for it like so:
export class MyComponent {
constructor(#Inject('myService') service:MyService) {
...
}
}
What is the syntax for injecting a service by name using ES5?
To complete the pixelbits' answer, you need also define my service within the providers list either:
At the application level
document.addEventListener('DOMContentLoaded', function() {
ng.platform.browser.bootstrap(Cmp, [MyService]);
});
At the component level
var Cmp = ng.core.
Component({
selector: 'cmp',
providers: [ MyService ]
}).
(...)
Class({
constructor: [MyService, function(service) {
}]
});
It depends on what you want to do: share your service instance for all elements in the Angular2 application or per component.
This answers could give more details on dependency injection in Angular2 with ES5: Dependency Injection in Angular 2 with ES5.
Edit
In fact, there is a subtlety. IN the case of upgrade you need not to bootstrap using the ng.platform.browser.bootstrap function but the one from the upgrade object.
upgrade.bootstrap(document.body, ['heroApp']);
Where heroApp is the Angular1 module containing services and factories I want to use in the Angular2 application.
In fact, when you call the upgradeNg1Provider method on the upgrade, corresponding providers are registered within its associated injector. This means that you don't need to specify them at described above.
So you simply need to do that where you want to inject:
(...)
Class({
constructor: [ ng.core.Inject('customService'),
ng.core.Inject('customFactory'),
function(cService, cFactory) {
}]
});
Miško Hevery provides a great plunkr for this: http://plnkr.co/edit/yMjghOFhFWuY8G1fVIEg?p=preview.
Hope it helps you,
Thierry
Use the array notation for constructor DI of services:
.Class({
constructor: [MyService, function (service) {
...
}],

Resources