DI - No provider found for EventBus - dependency-injection

Using Angular Dart, I define an event bus like this:
class MyModule extends Module {
MyModule() {
bind(EventBus, toImplementation: EventBus);
...
}
}
When I want to inject this event bus into a component by simply doing:
class MyComponent {
final EventBus _eventBus;
MyComponent(this._eventBus) {}
}
I am getting the error:
No provider found for EventBus!
I have no idea how to debug this...
The event bus is an external library, which looks like:
library event_bus;
import 'dart:async';
#MirrorsUsed(symbols: '*') // Do not keep any names.
import 'dart:mirrors';
class EventBus {
StreamController _streamController;
EventBus({bool sync: false}) {
_streamController = new StreamController.broadcast(sync: sync);
}
...
}
Any help welcome... thanks!

I'm a bit late, but in this case - when you can't put easily an #Injectable() annotation on the class - the simplest solution is to give the injector a value :
bind(EventBus, toValue: new EventBus());

Related

How to pass reflector to Nest.js global guard?

I am new to nest.js and I have a question.
I have a Roles Guard like this
import { CanActivate, ExecutionContext, Injectable } from '#nestjs/common';
import { Observable } from 'rxjs';
import { Reflector } from '#nestjs/core';
#Injectable()
export class RolesGuard implements CanActivate {
constructor(private readonly reflector: Reflector) {
}
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
const roles = this.reflector.get<string[]>('roles', context.getHandler());
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
return user.role.some(role => !!roles.find(item => item === role));
}
}
Now I want to use this guard as a global guard like this
app.useGlobalGuards(new RolesGuard())
But it says that I need to pass argument(the reflector) to the guard as I mentioned in the constructor, now will it be okay to initialize the reflector like this?
const reflector:Reflector = new Reflector();
app.useGlobalGuards(new RolesGuard(reflector))
Or is there a better way to do this?
On the official Nest JS fundamentals course, in lecture "54 Protect Routes with Guards", the instructor specifies it is not best practice to create instance of reflector yourself.
A better way to resolve dependencies is to create a common module, and register your guard there. That way, reflector instance is resolved by nest runtime and you can also specify imports array for any other dependencies.
import { Module } from '#nestjs/common';
import { APP_GUARD } from '#nestjs/core';
import { AuthTokenGuard } from './guards/auth-token.guard';
import { ConfigModule } from '#nestjs/config';
#Module({
imports: [ConfigModule],
providers: [
{
provide: APP_GUARD,
useClass: AuthTokenGuard,
},
],
})
export class CommonModule {}
app.useGlobalGuards(new RolesGuard(new Reflector()));
It is working also. Could not find any better solution.
Although my answer might not add much value, I just want to re-iterate that is the intended way to get the reflector, this is a quote from NestJS's creator
kamilmysliwiec
When you create instance manually, you can create Reflector by
yourself:
new RoleGuard(new Reflector());
Source: https://github.com/nestjs/nest/issues/396#issuecomment-363111707
2023, NestJs 9, related problem:
In case you inject request-scoped dependency into the globally registered guard, the reflector will be undefined.
You can solve this issue by resolving such dependencies using ContextIdFactory and moduleRef.resolve() instead of injecting them normally:
const req = context.switchToHttp().getRequest();
const contextId = ContextIdFactory.getByRequest(req);
this.moduleRef.registerRequestByContextId(req, contextId);
this.authorizationService = await this.moduleRef.resolve(
RequestScopedService,
contextId
);
References:
https://docs.nestjs.com/fundamentals/module-ref
code example
https://discord.com/channels/520622812742811698/1060904277607985172

Angular2 - Use Dependency Injection outside Components

In my app I use DI to pass information about the UserLogged around the different Components that need such info.
This means that I have a main.ts class like this
import {AppComponent} from './app.component';
import {UserLogged} from './userLogged'
bootstrap(AppComponent, [UserLogged]);
and the components that need to use the instance of UserLogged have a constructor like this
constructor(private _user: UserLogged)
Now I would like to use the same instance of UserLogged also in simple TypeScript classes (which are not #Component). Is this possible? In other words, can I get hold of the same instance of UserLogged injected by DI also if I am outside a #Component?
This constructor also works for services (other classes created by DI)
bootstrap(AppComponent, [OtherClass, UserLoggged]);
#Injectable()
export class UserLogged {
log(text) {
console.log(text);
}
}
#Injectable()
export class OtherClass {
constructor(private _user: UserLogged) {}
}
class SomeComponent {
constructor(private otherClass:OtherClass) {
this.otherClass._user.log('xxx');
}
}
If you create these classes using new SomeClass() then you can inject it like
class SomeComponent {
constructor(private _injector:Injector) {
let userLog = this._injector.get(UserLogged);
new SomeClass(userLog);
}
}
In the file where you bootstrap angular:
import { AppComponent } from './app.component';
import { UserLogged } from './userLogged';
declare global {
var injector: Injector;
}
bootstrap(AppComponent, [UserLogged]).then((appRef) => {
injector = appRef.injector;
});
In your other file:
import { UserLogged } from '../path/to/userLogged';
class TestClass {
private userLogged: UserLogged;
constructor() {
this.userLogged = injector.get(UserLogged);
}
}
To be able to use dependency injection in classes you need to have a decorator, the #Injectable one.
#Injectable()
export class SomeClass {
constructor(private dep:SomeDependency) {
}
}
The name Injectable isn't really self-explanatory. It's to make possible the injection within the class (and not into another class).
The provider for the SomeDependency class need to be visible from the component that initiates the call.
See this question for more details about dependency injection and hierarchical injectors:
What's the best way to inject one service into another in angular 2 (Beta)?
Im taking a wild guess here, but do you mean to say you want to Inject the class with having to use providers : [UserLogged] ?
If that is the case, this will work
providers: [ provide(UserLogged, {useClass: UserLogged} ]
add the above to your bootstrap and you are good to go when you 'do not want to use #Component'
sample.ts
export class Sample{
constructor(private ulog : UserLogged){}
}
In your case the bootstrap would be :
import {provide} from 'angular2/core';
import {HTTP_PROVIDERS} from 'angular2/http';
bootstrap(AppComponent,[HTTP_PROVIDERS,provide(UserLogged, { useClass : UserLogged})]);
Ive added the HTTP_PROVIDERS to demonstrate how to add multiple providers.
Cheers!

angular2 CanActivate with http

I am having a component that has canactivate
import {isLoggedIn} from '../login/isLoginedIn';
#CanActivate((next, previous) => {
isLoggedIn()
})
My "isLoggedIn" is as below
import {Http, Headers} from 'angular2/http';
class Auth {
constructor( #Inject(Http) private _http: Api) { }
check() {
this._http.get('/Users/LoggedInUser')
}
}
export const isLoggedIn = () => {
let injector = Injector.resolveAndCreate([Auth, Http]);
let auth = injector.get(Auth);
return auth.check();
};
I can't inject a service which has http as dependancy. Can this be done like this or is there a better way to do it?
Since the CanActivate is a decorator instead of a method as with OnActivate or CanDeactivate then you are correct in assuming that constructor dependency injection of the component that you are attempting to authorize is not an option.
The method which you are using will work, but there is a missed #Injectable() on your Auth class.
import {Injectable} from 'angular2/core';
import {Http, Headers} from 'angular2/http';
#Injectable()
class Auth {
constructor( #Inject(Http) private _http: Api) { }
check() {
this._http.get('/Users/LoggedInUser')
}
}
This approach is sound and I don't think that besides some syntactic sugar or minor refactoring that there would be much to improve this and still achieve the same amount of readability / maintainability for this approach.
One other addition that could be made to improve the flow and prevent a potential bug would be to return the observable in CanActivate so that the navigation will wait for the Http request to complete before deciding to continue or cancel.
#CanActivate((next, previous) => {
return isLoggedIn()
})
or for short
#CanActivate(() => isLoggedIn())
(Single statement arrow functions are auto-returning)

Angular 2 dependency injection: Host as parent class

I have a quick question:
Can i bind Interface or abstract class (or just a parent class atleast) as #Host() of component? Seems like DI system can't resolve polymorphism.
I have interface like:
export interface Component {
}
and child component from this interface:
...
export class SomeComponent implements Component {
...
}
Now i want to create Directive, and use Component as host even when i put this directive on SomeComponent.
like:
constructor(private host: Component) { }
In fact, there is nothing at runtime corresponding TypeScript interfaces. This means that you can't use them as types.
If you try this in your service:
export interface SomeInterface {
someMethod();
}
export class HeroService implements SomeInterface {
(...)
}
We will have undefined when trying to import it from another module:
import {HeroService,SomeInterface} from './hello.service';
console.log('service = '+HeroService); // <---- not null
console.log('interface = '+SomeInterface); // <---- undefined
Here is a plunkr describing this: https://plnkr.co/edit/RT59B0tw40lnq85XMMi7?p=preview.
Hope it helps you,
Thierry

Binding a class to an interface

Using typescript, I can easily bind classes to themselves:
bootstrap(MyAppComponent, [MyClass]);
However, I would like to bind my class to an interface, like such:
boostrap(MyAppComponent, [???]);
such that I can inject it as follows:
class MyAppComponent {
constructor(my_class : IMyClass){
}
};
Is this possible in Angular2? If yes, how to I have to specify the binding?
To make it short the problem is that Interfaces disappear when typescript is compiled. So you'd have to use #Inject with a string.
Or there's another option, if you check the last article of Victor Savkin you can find this in the comments :
Some background. In TypeScript, interfaces are structural and are not retained at runtime. So you have to use ILoginService as follows:
constructor(#Inject("ILoginService") s:ILoginService).
You don't have to use a string - any object can be passed in there. We actually provide an object called OpaqueToken that can be used for this purpose.
interface ILoginService { login(credentials);}
const ILoginService = new OpaqueToken("LoginService");
can be used like this:
constructor(#Inject(ILoginService) s:ILoginService).
I dont know if it is possible with interface as interface will not be available at runtime (javascript does not know about interface).
But it can be done using abstract classes.
//abstract-parent-service.ts
export class DatabaseService{
getService: ()=>string;
}
//hibernate.service.ts
import {DatabaseService} from "./abstract-parent-service";
export class HibernateService implements DatabaseService{
constructor() { }
getService() {
return "i am hibernate";
}
}
//jdbc.service.ts
import {DatabaseService} from "./abstract-parent-service";
export class JDBCService implements DatabaseService{
constructor() { }
getService() {
return "i am Jdbc";
}
}
//cmp-a.component.ts
import {DatabaseService} from "./abstract-parent-service";
import {HibernateService} from "./hibernate.service";
#Component({
selector: 'cmp-a',
template: `<h1>Hello Hibernate</h1>`,
providers: [{provide: DatabaseService, useClass: HibernateService}]
})
export class CmpAComponent {
constructor (private databaseService: DatabaseService) {
console.log("Database implementation in CompA :"+this.databaseService.getService());
}
}
//cmp-b.component.ts
import {DatabaseService} from "./abstract-parent-service";
import {HibernateService} from "./hibernate.service";
#Component({
selector: 'cmp-b',
template: `<h1>Hello Jdbc</h1>`,
providers: [{provide: DatabaseService, useClass: JDBCService}]
})
export class CmpAComponent {
constructor (private databaseService: DatabaseService) {
console.log("Database implementation in CompA :"+this.databaseService.getService());
}
}
But the problem with this implementation is HibernateService and
JDBCService are not able to extend any other class now because they
have already got married with DatabaseService.
class A{
constructor(){
console.log("in A");
}
}
class B extends A{
constructor(){
super();
console.log("in B");
}
}
class C extends A{
constructor(){
super();
console.log("in C");
}
}
let c = new C();
//This thing is not possible in typescript
class D extends B, C{//error: Classes can only extend a single class
constructor(){
super();// which constructor B or C
console.log("in D");
}
}
If you are using this pattern for DI, make it sure that your child class services are not going to extend any other functionality in future.

Resources