Service class is not injected in Angular2 - dependency-injection

I already had everything working yesterday. And today, after I restarted the environment, one of the services that I am trying to inject, is now always null.
Here is my top level component (app.component.ts):
#Component({
selector: 'priz-app',
moduleId: module.id,
templateUrl: './app.component.html',
directives: [ROUTER_DIRECTIVES, SecureRouterOutlet],
providers: [ROUTER_PROVIDERS, AuthenticationService]
})
The template of that component contains:
<secure-outlet signin="Login" unauthorized="AccessDenied"></secure-outlet>
Where the secure-outlet implementation is as follows:
#Directive({
selector: 'secure-outlet'
})
export class SecureRouterOutlet extends RouterOutlet {
#Input()
signin: string;
#Input()
unauthorized:string;
#Input()
nameAttr: string;
constructor(_elementRef: ElementRef, _loader: DynamicComponentLoader,
private parentRouter: Router,
private authService: AuthenticationService,
public injector: Injector) {
super(_elementRef, _loader, parentRouter, null);
}
...
In the constructor, as well as anywhere else in the directive, authService is always null. I tried, defining providers with AuthenticationService inside the directive, in the main component, even in the bootstrap, nothing works.
What am I missing?
Thanks,

Don't add providers: [ROUTER_PROVIDERS] to components, only to bootstrap()
Try providing the same parameters as the original RouterOutlet class and add your own dependencies behind them.
Not sure if this helps though but I think it was mentioned not too long ago that there is a weird issue:
constructor(
_elementRef: ElementRef,
_loader: DynamicComponentLoader,
private parentRouter: Router,
#Attribute('name') nameAttr: string, // <= added
private authService: AuthenticationService,
public injector: Injector) {

Related

Angular 6+ providedIn: 'root' raising a StaticInjectorError

I have googled extensively and I can't seem to find anyone else with this issue, so I must be missing something. I am converting all of my AppModule services to use the providedIn: 'root' method, but it doesn't seem to be working.
import { Injectable } from '#angular/core';
Injectable({
providedIn: 'root'
})
export class CommonService{
UserName : string = 'Guest';
Roles : Array<any> = [];
Theme: string = 'standard';
constructor(){}
}
Here is one of the components that uses the service:
import { CommonService } from './Services/common.service';
#Component({
selector: 'navBar',
templateUrl: './navbar.html'
})
export class NavBar {
constructor(private session: CommonService) {}
At runtime, this is the error in the console:
StaticInjectorError(AppModule)[NavBar -> CommonService]:
StaticInjectorError(Platform: core)[NavBar -> CommonService]:
NullInjectorError: No provider for CommonService!
I've checked the documentation, and I don't see where I am going wrong. What am I missing?
Forgot to mention, NavBar is a component declared in SharedModule, SharedModule is imported in AppModule.
You may be missing the leading "#" on Injectable:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class CommonService{
UserName : string = 'Guest';
Roles : Array<any> = [];
Theme: string = 'standard';
constructor(){}
}
There may not be an error in the IDE, but that looks like it might be the issue

Can Injectable Services have a providers list?

I was doing some code with a component class and a service class.
#Injectable()
class MyService extends Object {
...
}
#Component(
...
providers: const [MyService]
)
class myCompoment implements onInit {
final MyService _service;
MyComponent(this._service);
...
}
Is there a way to say, give a provider to my injectable service such that it can consume? When looking online, it had shown that Component comes from Injectable, so I was thinking to create a component out of the service, but that doesnt quite make sense as to me a component would also have UI.
Ideally, I wanted to do something like:
#Injectable()
class AnotherClass {}
#Injectable(providers: const [AnotherClass])
class MyService extends Object {
...
}
#Component(
...
providers: const [MyService]
)
class myCompoment implements onInit {
final MyService _service;
MyComponent(this._service);
...
}
but Injectable doesnt allow the providers property it seems.
You can add providers: const [MyService, AnotherClass] to components and MyService can inject AnotherClass by just listing it as constructor parameter
#Injectable()
class AnotherClass {}
#Injectable()
class MyService extends Object {
final AnotherClass _anotherClass;
MyService(this._anotherClass);
}
#Component(
...
providers: const [MyService, AnotherClass]
)
class myCompoment implements onInit {
final MyService _service;
MyComponent(this._service);
...
}

What is the difference between #Inject and #Injectable in Angular 2 typescript

I don't understand When to use #Inject and when to use #Injectable ?
import {Component, Inject, provide} from '#angular/core';
import {Hamburger} from '../services/hamburger';
export class App {
bunType: string;
constructor(#Inject(Hamburger) h) {
this.bunType = h.bun.type;
}
}
And..
import {Injectable} from '#angular/core';
import {Bun} from './bun';
#Injectable()
export class Hamburger {
constructor(public bun: Bun) {
}
}
The #Injectable decorator aims to actually set some metadata about which dependencies to inject into the constructor of the associated class. It's a class decorator that doesn't require parameters. Without this decorator no dependency will be injected...
#Injectable()
export class SomeService {
constructor(private http:Http) {
}
}
The #Inject decorator must be used at the level of constructor parameters to specify metadata regarding elements to inject. Without it, the type of parameters is used (obj:SomeType is equivalent to #Inject(SomeType) obj).
#Injectable()
export class SomeService {
constructor(#Inject(Http) private http:Http, #Inject('sometoken') obj) {
}
}
You must read this difference- #Inject and #Injectable
#Inject()
is a manual mechanism for letting Angular know that a parameter must be injected.
When using TypeScript, #Inject is only needed for injecting primitives.
For eg:
export class AppComponent {
encryption = this.chatWidget.chatSocket.encryption;
constructor(#Inject(ChatWidget) private chatWidget) { }
}
#Injectable()
lets Angular know that a class can be used with the dependency
injector.
For eg:
#Injectable()
export class ChatWidget {
constructor(
public authService: AuthService,
public authWidget: AuthWidget,
public chatSocket: ChatSocket) { }
}
In the above example Angular's injector determines what to inject into ChatWidget's constructor by using type information

How to instantiate/inject class declared in main component to another component

My AppComponent sample:
///other imports here
import { ApplyColor } from './../../shared/directives/applycolor';
import { SomeComponent} from './../../components/somecomponent';
#Component({
selector: 'my-app',
directives: [ApplyColor, ROUTER_DIRECTIVES],
providers: [ROUTER_PROVIDERS],
templateUrl: 'myurl.html'
})
#RouteConfig([
//routes here
{ path: '/main', name: 'Main', component: SomeComponent, useAsDefault: true },
])
export class AppComponent {
}
In order to instantiate ApplyColor in SomeComponent
Import ApplyColor
Add to directives: [ApplyColor]
Instantiate with a new keyword
Which is:
import {Component, AfterViewInit, ViewChild} from 'angular2/core';
import { ApplyColor } from './../../shared/directives/applycolor';
#Component({
selector: 'my-selector',
directives: [ApplyColor],
templateUrl: 'app/components/mycomponenturl.html'
})
export class MyComponent implements AfterViewInit {
constructor() { }
ngAfterViewInit() {
var color = new ApplyColor();
color.apply(2);
}
}
How can I instantiate/inject ApplyColor without there 3 steps above?
Directive instances are managed by Angular2. This means that you only need to specify it into the directives attribute. So if ApplyColor is a directive just add it into the directives attribute.
If ApplyColor isn't a directive, you can explicitly instantiate into the provide to the child component using #Input.
In your case, it's a bit particular since you leverage routing. In this case, you need to rely on a shared service. Such service needs to be defined when bootstrapping the application to be able to share a single instance for all components. You can set your instance of ApplyColor into a field of this service. So both component (AppComponent and SomeComponent) can access it.
Define the service
export class SharedService {
color:ApplyColor;
}
Bootstrapping the service
bootstrap(AppComponent, [ SharedService ]);
Set color from AppComponent
#Component({
(...)
})
export class AppComponent {
constructor(private service:SharedService) {
var color = new ApplyColor();
this.service.color = color;
}
}
Get color from SomeComponent
#Component({
(...)
})
export class AppComponent {
constructor(private service:SharedService) {
this.service.color.apply(2);
}
}
I have just started working angular2 but as I can understand:
import ApplyColor => you can't remove that, it required by the compiler to know which class you are referenced to
directives : [ApplyColor] => that means you will use the selector (the one you have defined in applycolor.ts) in the template (app/components/mycomponenturl.html). it is only to know where the component will be in the view.
new ApplyColor => you are creating the object yourself, it is not injected.
To inject your component,
export class MyComponent implements AfterViewInit {
constructor(private color:ApplyColor) { }
ngAfterViewInit() {
this.color.apply(2);
}
}
I hope it helped you ?

Accessing a dataset map in angular2

I have the following:
.html template
<name-view data-topic='id'></name-view>
.dart component
import 'dart:html';
class NameView implements AfterViewInit
{
String topic;
void ngAfterViewInit( ) {
// datset is not reference below - works in polymer-1.x attached() method
topic = this.datset['topic'];
}
}
However, the code in ngAfterViewInit does not work.
How can I retrieve the data-topic attribute in angular2?
I wasn't able to make #Input('data-topic') work but the other ways are working
#Component(
selector: 'app-element',
template: '''
<h1>app-element</h1>
<name-view data-topic='id' topic='topicid'></name-view>
''',
directives: const [NameView])
class AppElement {}
#Component(
selector: 'name-view',
template: '''
<h1>test-element</h1>
<div>data-topic: {{topic}}</div>
<div>topic: {{topic2}}</div>
<div>topicFromRef: {{topicFromRef}}</div>
''')
class NameView implements OnInit {
#Input('data-topic')
String topic;
#Input('topic')
String topic2;
String topicFromRef;
ElementRef _elementRef;
TestElement(this._elementRef);
void ngOnInit() {
topicFromRef = (_elementRef.nativeElement as Element).dataset['topic'];
}
}
Using ElementRef is discouraged because this prevents running the code in a WebWorker or on server rendering.

Resources