Inject a service into another service in the same module - javascript

I have a ChatService A that depends upon an interface.
import { Injectable, Inject } from '#angular/core';
import { NGXLogger } from 'ngx-logger';
import { TokenHttpService } from '#lib/interfaces';
#Injectable({
providedIn: 'root'
})
export class ChatService {
constructor(
#Inject('TokenHttpService') private tokenFetchService: TokenHttpService,
private logger: NGXLogger
) {
this.logger.debug('Confirmed ctor for ChatService called');
}
}
I have a HttpService B that implements the TokenHttpService interface.
import { Injectable } from '#angular/core';
import { CoreDataService } from '#app/core/async-services/http/core.data';
import { TokenHttpService } from 'he-common';
import { NGXLogger } from 'ngx-logger';
#Injectable()
export class HttpService implements TokenHttpService {
constructor(
private _coreDataService: CoreDataService,
private logger: NGXLogger
) {
this.logger.debug("Confirmed ctor for HttpService called");
}
}
Then I try to combine them both in MessagingModule C
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { Routes, RouterModule } from '#angular/router';
import { IonicModule } from '#ionic/angular';
import { MessagingPage } from './messaging.page';
import { TranslateModule } from '#ngx-translate/core';
import { ChatService } from 'my-common-lib';
import { SharedModule } from '#app/shared';
import { HttpService } from '#app/core/async-services/http/versioned/http';
const routes: Routes = [
{
path: '',
component: MessagingPage
}
];
#NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
TranslateModule.forChild(),
RouterModule.forChild(routes),
SharedModule
],
declarations: [MessagingPage],
providers: [
{ provide: 'TokenHttpService', useValue: HttpService },
{ provide: ChatService, deps: ['TokenHttpService'] }
]
})
export class MessagingPageModule {}
If I'm not mistaken this code should work like this: C attempts to construct A and is told it needs B, B is provided to the module as well so it should provide B to A so that it can be constructed and used in component D.
import { Component } from '#angular/core';
import { ChatService } from 'he-common';
import { NGXLogger } from 'ngx-logger';
#Component({
selector: 'app-messaging',
templateUrl: './messaging.page.html',
styleUrls: ['./messaging.page.scss']
})
export class MessagingPage {
constructor(
private ChatService: ChatService,
private logger: NGXLogger
) {
// This line logs undefined.
this.logger.debug(this.twilioChatService);
}
}
How can I provide the TokenHttpService B to Service A? Can I do it in the same module?

I found out what my problems were:
I needed to use the useClass property instead of the useValue property. useClass expects a constructor (or factory function) while the useValue property expects a simple object.
In the deps section you are basically overriding what values you want to pass into the constructor for the service. So, in my case, I had the 'TokenHttpService' injected but no logger, so my service threw an error when it tried to call this.logger.debug. After adding NGXLogger to the deps array the service worked flawlessly.
Here's my final providers array:
providers: [
{
provide: 'TokenHttpService',
useClass: HttpService
},
{
provide: ChatService,
deps: ['TokenHttpService', NGXLogger],
useClass: ChatService
}
]

Related

How do I Access AppModule Module imports from Lazy-loaded Modules?

How do I Access AppModule imports from Lazy-loaded Modules ?
My Angular10 App imports AngularMaterial and NXTranslate Modules in to the AppModule.
NxTranslate calls an ApiService to get a large Lookup object of thousands of translations.
This is translated at the initial loading of the AppModule.
The App has multiple lazy-loaded routes that also need to use the AnagularMaterial and NXTranslate Modules in their features.
If I use a SharedModule to load the Modules then the ApiService is called multiple times. This is obviously not good.
It should only call the ApiService & AngularMaterial once and be available for all modules.
How do I resolve this? I am struggling.
Thanks.
Update
(sorry for the long post)
This is the NXTranslate implementation - it uses a custom class.
import { environment } from './../../../../environments/environment';
import { OSCITranslateService } from './translate.service';
import { NgModule, Injector } from '#angular/core';
import { CommonModule } from '#angular/common';
import {TranslateLoader, TranslateModule} from '#ngx-translate/core';
import {TranslateHttpLoader} from '#ngx-translate/http-loader';
import {HttpClient, HttpClientModule} from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
export class CustomLoader implements TranslateLoader {
localeResourcesUrl =
`${environment.baseUrl}${environment.apiUrl.localeResources}`;
constructor(private http: HttpClient) {}
getTranslation(lang: string): Observable<any> {
let options;
const uri = `${this.localeResourcesUrl}${options && options.key ?
'/' + options.key : ''}`;
let mapped = this.http.get(uri).pipe(
map((response: any) => {
let localeData = {};
let languageCode = response?.languageVariantCode;
response.resources.forEach(item => {
localeData[item.keyName] = item.keyValue;
});
return localeData;
})
);
return mapped;
}
}
#NgModule({
declarations: [],
imports: [
CommonModule,
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: CustomLoader,
deps: [HttpClient]
}
})
],
exports: [ TranslateModule ]
})
export class NxTranslateModule {
constructor(private http: HttpClient) {
}
}
This is the sharedRootModule that imports the AngularMaterial & NXTranslate
import { SharedModule } from './shared.module';
import { NgModule, ModuleWithProviders } from '#angular/core';
#NgModule({
})
export class SharedRootModule {
static forRoot(): ModuleWithProviders<SharedModule> {
return {
ngModule: SharedModule
};
}
}
In AppModule SharedRootModule is imported
...
#NgModule({
declarations: [
AppComponent
],
imports: [
...
SharedRootModule.forRoot()
],
exports: [
...
SharedRootModule
]
....
Are you concerned about the multiple ApiService instances you might end up with? Provide the ApiService within AppModule only, or even better, use the providedIn property right in your service's decorator so it gets injected at application level. (https://angular.io/api/core/Injectable#providedIn)
I would just use a SharedModule that exports the mentioned lazy loaded modules.

I am using angular code to call the rest api and display it on the screen

The following code is my viewall.ts code
import { Component, OnInit } from '#angular/core';
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-viewall',
templateUrl: './viewall.component.html',
styleUrls: ['./viewall.component.css']
})
#Injectable()
export class RestComponent {
constructor(private http: HttpClient) { }
configUrl = "http://34.201.147.118:3001/getAllData";
getConfig() {
return this.http.get(this.configUrl);
}
}
This is my app.module.ts code
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import {FormsModule} from'#angular/forms';
import { AppComponent } from './app.component';
import { RestComponent } from './rest/rest.component';
import { ViewallComponent } from './viewall/viewall.component';
import { HttpClientModule} from '#angular/common/http';
#NgModule({
declarations: [
AppComponent,
RestComponent,
ViewallComponent
],
imports: [
BrowserModule,FormsModule,
HttpClientModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
it is giving e the following error ERROR in src/app/app.module.ts(6,10): error TS2305: Module '"E:/paramount/paramount/src/app/viewall/viewall.component"' has no exported member 'ViewallComponent'.
Where is the exported class inside viewall.component.ts? You should be exporting a class from the component.
Haven't you declared RestComponent as Injectable and that too inside viewall.ts, and then you are importing it from rest.component file inside app.module.ts.
Try to move the RestComponent from the declarations array to providers array and also the import from the correct file.
Hope it helps.
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import {FormsModule} from'#angular/forms';
import { AppComponent } from './app.component';
import { RestComponent } from './rest/rest.component';
import { ViewallComponent } from './viewall/viewall.component';
import { HttpClientModule} from '#angular/common/http';
#NgModule({
declarations: [
AppComponent,
ViewallComponent
],
imports: [
BrowserModule,FormsModule,
HttpClientModule,
],
providers: [
RestComponent,
],
bootstrap: [AppComponent]
})
export class AppModule { }
Your viewall.component.ts should be exporting a class and look like this:-
import { Component, OnInit } from '#angular/core';
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-viewall',
templateUrl: './viewall.component.html',
styleUrls: ['./viewall.component.css']
})
export class ViewallComponent{}
injectable service is in providers
you can try with this solution.
providers: [
RestComponent,
],
declarations: [
AppComponent,
ViewallComponent
],
In viewall component.ts
import { Component, OnInit } from '#angular/core';
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-viewall',
templateUrl: './viewall.component.html',
styleUrls: ['./viewall.component.css']
})
export class ViewallComponent{
constructor() { }
}
#Injectable()
export class RestComponent {
constructor(private http: HttpClient) { }
configUrl = "http://34.201.147.118:3001/getAllData";
getConfig() {
return this.http.get(this.configUrl);
}
}

http service hit not working in Angular

I am using JSONPlaceholder to get data in service, but I am unable to get data at all. Please, help me out.
user.component.html
<p (click)="getUsers()">Click Me!</p>
<ul *ngFor="let x of users">
<li>{{x.name}}, {{x.age}}</li>
</ul>
user.component.ts
import { Component, OnInit } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { DataService } from '../../services/data.service';
import { Http } from '#angular/http';
#Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
constructor(private http:Http) { }
ngOnInit() {
}
getUsers(){
console.log(this.http.get("https://jsonplaceholder.typicode.com/posts"));
}
}
app.module.ts
//Basic File Inclusions
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
//Additional files inclusion
import { AppComponent } from './app.component';
import { UserComponent } from './components/user/user.component';
import { DataService } from './services/data.service';
import { Http } from '#angular/http';
#NgModule({
declarations: [
AppComponent,
UserComponent
],
imports: [
BrowserModule
],
providers: [ Http ],
bootstrap: [AppComponent]
})
export class AppModule { }
Please, can someone help me out making a successfull service call via http and get data on console.
Import
import { HttpModule } from '#angular/http';
in app.module.ts
imports: [HttpModule]
Rest of code will be same as you posted.
calling http like
this.http.get(`https://jsonplaceholder.typicode.com/posts`).subscribe(
data => {
console.log(data)
});
user.component.ts
import { Component, OnInit } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { DataService } from '../../services/data.service';
import { Http } from '#angular/http';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
constructor(private http: HttpClient) { }
ngOnInit() {
}
this.http.get(`https://jsonplaceholder.typicode.com/posts`).subscribe(
data => {
console.log(data)
});
}
app.module.ts
//Basic File Inclusions
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
//Additional files inclusion
import { AppComponent } from './app.component';
import { UserComponent } from './components/user/user.component';
import { DataService } from './services/data.service';
import { Http } from '#angular/http';
import { HttpModule } from "#angular/http";
#NgModule({
declarations: [
AppComponent,
UserComponent
],
imports: [
BrowserModule,
HttpModule
],
providers: [ Http ],
bootstrap: [AppComponent]
})
export class AppModule { }
Hope this may help you..
You are just calling http.get(url) and expecting something in return is like calling ajax method without success and error callback methods.
Kindly check Http documentation and usage of get and post methods
Mistake/Wrong Assumptions:
this.http.get(https://jsonplaceholder.typicode.com/posts) will not return http response which are expecting
Reality/Correct Approach:
You can use either pipe(can be used in the service) or subscribe(can be used in Component) method on http's get method whose return type is Observable.
Based on your requirement, you can use either of them
http.get('https://jsonplaceholder.typicode.com/posts')
// Call map on the response observable to get the parsed people object
.pipe(map(res => res.json()))
// Subscribe to the observable to get the parsed people object and attach it to the
// component
.subscribe(posts => this.posts = posts)
Hence your component code becomes:
user.component.ts
import { Component, OnInit } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { DataService } from '../../services/data.service';
import { Http } from '#angular/http';
#Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
constructor(private http:Http) { }
ngOnInit() {
}
getUsers(){
this.http.get("https://jsonplaceholder.typicode.com/posts")
.subscribe(posts=> console.log(posts))
}
}

TypeError: Cannot set property stack of [object Object] which has only a getter

When I am trying to use the service in my componenet and declatring it in constructor , I am getting this error TypeError: Cannot set property stack of [object Object] which has only a getter
I have below my code
import { Component } from '#angular/core';
import { FormBuilder,FormGroup} from '#angular/forms';
import { LoginService } from '../../services/login.service';
#Component({
selector: 'login-selector',
templateUrl: './app/components/login/login.component.html',
})
export class LoginComponent {
form:FormGroup;
items:Object;
constructor(
private formBuilder:FormBuilder,
private loginService:LoginService){
}
ngOnInit() {
this.form=this.formBuilder.group({
userName:this.formBuilder.control(''),
password:this.formBuilder.control(''),
remember:this.formBuilder.control(''),
textCaptcha:this.formBuilder.control('')
});
}
onSubmit(loginForm:FormGroup){
this.loginService.getTestJson().subscribe(mediaItems => {
this.items = mediaItems;
});
}
}
Service is
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class LoginService{
constructor(private http: Http) {}
getTestJson(){
return this.http.get('http://geo.groupkt.com/ip/172.217.3.14/json').map(response => {
return response.json();
});
}
}
and app module ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { ReactiveFormsModule } from '#angular/forms';
import { AppComponent } from './app.component';
import { LoginComponent } from './components/login/login.component';
import { LoginService } from './services/login.service';
#NgModule({
imports: [ BrowserModule,ReactiveFormsModule ],
declarations: [ AppComponent,LoginComponent ],
bootstrap: [ AppComponent ],
providers:[LoginService]
})
export class AppModule { }
import { HttpModule} from '#angular/http'; in app module ts
and add it in NgModule imports
It is likely you have ngModel in your Html, to do so, you need to be very careful.
You can't just use ngModel by itself in formGroup. It only works with formGroupName

Creating a angular2 service that displays a processing overlay

I am trying to create a reusable component that serves as a processing overlay when making asynchronous calls across my site. I have a service in place but the OverlayComponent doesn't seem to get invoked when showOverlay is invoked:
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { HashLocationStrategy, LocationStrategy } from '#angular/common';
import { HttpModule } from '#angular/http';
import { AppRoutingModule } from './app-routing.module';
import { MainComponent } from './app.mysite.component';
import { OverlayComponent } from './app.mysite.overlay.component';
import { TrackerComponent } from './pages/tracker/mysite.tracker.component';
import { OverlayService } from "./overlay.service";
#NgModule({
imports: [ BrowserModule, AppRoutingModule, HttpModule ],
declarations: [
MainComponent,
OverlayComponent,
NavbarComponent,
TrackerComponent,
],
providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}, OverlayService],
bootstrap: [ MainComponent ]
})
export class AppModule { }
TrackerComponent.ts
import { Component, OnInit } from '#angular/core';
import { OverlayService } from '../../overlay.service.js';
#Component({
moduleId: module.id,
selector: 'tracker-component',
templateUrl: '/public/app/templates/pages/tracker/mysite.tracker.component.html',
providers: [ OverlayService]
})
export class TrackerComponent implements OnInit{
constructor(private http: Http, private overlayService: OverlayService) {
}
ngOnInit(): void {
this.overlayService.showOverlay('Processing...'); //This kicks everything off but doesn't show the alert or overlay
this.overlayService.test(); //does exactly what i'd expect
}
}
overlay.service.ts
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
#Injectable()
export class OverlayService {
private message: string;
private subject: Subject<any> = new Subject<any>();
showOverlay(msg: string) : void { //When this gets invoked, shouldn't it be invoking a change to this.subject and therefore invoking getMessage()
this.message = msg;
this.subject.next(msg);
}
getMessage(): Observable<any> {
return this.subject.asObservable();
}
test() {
return 'test good'; //if I call this function, it works
}
}
app.mysite.overlay.component
import { Component, OnInit } from '#angular/core';
import { OverlayService } from './overlay.service';
#Component({
selector: 'overlay-component',
templateUrl: '/public/app/templates/mysite.overlay.component.html',
styleUrls: ['public/app/scss/overlay.css'],
providers: [OverlayService]
})
export class OverlayComponent implements OnInit {
private processingMessage: string;
constructor(private overlayService: OverlayService) {}
ngOnInit() {
this.overlayService.getMessage().subscribe((message: string) => { //since i'm subscribed to this, i'm expecting this to get called. It doesn't
this.processingMessage = message;
alert(this.processingMessage); //never gets hit
$('.overlay-component-container').show(); // never gets hit
},
error => {
alert('error');
})
}
}
Specifying providers in the Component metadata actually creates a new injectable, scoped to that component tree.
If you want to share the overlay service across the app, you'll need to declare the overlay provider in the NgModule, and not in the components. Alternatively, you can declare it only as a provider on the top-level entry component (eg. AppComponent), though it may cause confusion when used in other entry components/lazy-loaded modules.
See https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html for a better explanation

Categories