Inject service in service in Angular2 - javascript

I'm unable to inject a (global) service into another service.
boot.ts
import {bootstrap} from 'angular2/platform/browser';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {HTTP_PROVIDERS} from 'angular2/http';
import {AppComponent} from './app.component';
import {GlobalService} from './common/global.service';
bootstrap(AppComponent, [
GlobalService,
ROUTER_PROVIDERS,
HTTP_PROVIDERS
]);
global.service.ts
import {Injectable} from 'angular2/core';
#Injectable()
export class GlobalService {
api_url: string = 'hello';
}
api.service.ts
import {Injectable, Inject} from 'angular2/core';
import {GlobalService} from '../common/global.service';
#Injectable()
export class ApiService {
//constructor(#Inject(GlobalService) globalService: GlobalService) { // doesnt work
//constructor(#Inject(GlobalService) public globalService: GlobalService) { // doesnt work
constructor(public globalService: GlobalService) { // doesnt work
console.log(globalService); // undefined
console.log(this.globalService); // undefined
}
}
It works fine when injecting GlobalService into an Component.
Thank you in advance!

You need to add ApiService to bootstrap as well
bootstrap(AppComponent, [
ApiService,
GlobalService,
ROUTER_PROVIDERS,
HTTP_PROVIDERS
]);

Related

Created a simple component now i get an error about a provider

doing this project and i created a simple component to place my allert, and now i have this error, that i cant solve:
StaticInjectorError(AppModule)[DiscountAllertComponent]:
StaticInjectorError(Platform: core)[DiscountAllertComponent]:
NullInjectorError: No provider for DiscountAllertComponent!
I created the component like i always do, and i dont understand what i have to do to fix it!
component:
import { Component, OnInit } from '#angular/core';
import {AngularFireDatabase} from '#angular/fire/database';
import {AlertController} from '#ionic/angular';
import {Router} from '#angular/router';
#Component({
selector: 'app-discount-allert',
templateUrl: './discount-allert.component.html',
styleUrls: ['./discount-allert.component.scss'],
})
export class DiscountAllertComponent implements OnInit {
constructor(
// public af: AngularFireDatabase,
public alertController: AlertController) { }
ngOnInit() {}
}
component module:
mport {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '#angular/core';
import {CommonModule} from '#angular/common';
import {SharedHeaderComponent} from './shared-header/shared-header.component';
import {AlertController, IonicModule} from '#ionic/angular';
import {UserInfoComponent} from './user-info/user-info.component';
import {AddressComponent} from './address/address.component';
import {FormsModule, ReactiveFormsModule} from '#angular/forms';
import {TranslateModule} from '#ngx-translate/core';
import {PasswordStrengthBarModule} from 'ng2-password-strength-bar';
import {SchedulerComponent} from './scheduler/scheduler.component';
import {OrderConfigurationComponent} from './order-configuration/order-configuration.component';
import {OrderComponent} from './order/order.component';
import {MenuComponent} from './menu/menu.component';
import {DishOptionsComponent} from './dish-options/dish-options.component';
import {PasswordResetComponent} from './password-reset/password-reset.component';
import {OrderResumeComponent} from './order-resume/order-resume.component';
import {PaymentMethodComponent} from './payment-method/payment-method.component';
import {OnlinePaymentComponent} from './online-payment/online-payment.component';
import {PipesModule} from '../pipes/pipes.module';
import {ChangePasswordComponent} from './change-password/change-password.component';
import {CardsManagerComponent} from './cards-manager/cards-manager.component';
import {LocationSelectComponent} from './location-select/location-select.component';
import {MbrefComponent} from './mbref/mbref.component';
import {MbwayComponent} from './mbway/mbway.component';
import {CardModule} from '../directives/card/module';
import {DiscountAllertComponent} from './discount-allert/discount-allert.component';
const COMPONENTS = [
AddressComponent,
CardsManagerComponent,
ChangePasswordComponent,
DishOptionsComponent,
LocationSelectComponent,
MbrefComponent,
MbwayComponent,
MenuComponent,
OrderComponent,
OrderConfigurationComponent,
OrderResumeComponent,
PasswordResetComponent,
SchedulerComponent,
SharedHeaderComponent,
UserInfoComponent,
PaymentMethodComponent,
OnlinePaymentComponent,
DiscountAllertComponent
];
#NgModule({
declarations: [COMPONENTS],
imports: [
IonicModule,
CardModule,
CommonModule,
FormsModule,
PasswordStrengthBarModule,
ReactiveFormsModule,
TranslateModule,
PipesModule,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
exports: [COMPONENTS],
entryComponents: [COMPONENTS],
})
export class ComponentsModule {
}
When you create a component for a page, you have to declare it in .module.ts file in declarations: [] of the page that you are using. Eg.
declarations: [DiscountAllertComponent]
If still does not work, try to add it in:
entryComponents: [DiscountAllertComponent]

How do I get data to display in Angular from API in Express?

I am trying to use Nodejs/Express as my back end for producing data from a database. I currently have an api route setup so that a database query will result in its directory. So if I visit localhost:3000/api currently I will see the following:
{"status":200,"data":[{"Issuer_Id":1,"Data_Id":2,"Data_Name":"Name 1"},{"Issuer_Id":2,"Data_Id":14,"Data_Name":"Name 2"},{"Issuer_Id":2,"Data_Id":1,"Data_Name":"Name 3"}],"message":null}
This leads me to believe I have everything setup correctly on the back end.
Now how do I get this data to display on my Angular front end?
I have been through hours of tutorials and this is what I have come up with:
nav.component.ts
import { Component, OnInit } from '#angular/core';
import { DataService } from '../../data.service';
import { Series } from '../../data.service';
import {Observable} from 'rxjs/Rx';
#Component({
selector: 'app-fixed-nav',
templateUrl: './fixed-nav.component.html',
styleUrls: ['./fixed-nav.component.css']
})
export class FixedNavComponent implements OnInit{
serieses: Series[] ;
constructor(private dataService: DataService) {}
ngOnInit() {
this.dataService.getSeries().subscribe((serieses: Series[]) => this.serieses = serieses);
}
}
data.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from'#angular/common/http';
import { Http, Headers, RequestOptions, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/toPromise';
export class Series {
Issuer_Id: number;
Data_Id: number;
Data_Name: string;
}
#Injectable()
export class DataService {
constructor(private _http: Http) {}
getSeries(): Observable<Series[]> {
return this._http.get("http://localhost:3000/api/")
.map((res: Response) => res.json());
}
}
app.module.ts
import { Form1Module } from './modules/form1/form1.module';
import { FixedNavModule } from './modules/fixed-nav/fixed-nav.module';
import { HeaderModule } from './modules/header/header.module';
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { NgbModule } from '#ng-bootstrap/ng-bootstrap';
import { AppComponent } from './app.component';
import { HttpClientModule } from '#angular/common/http';
import { HttpModule } from '#angular/http';
import { DataService } from './data.service';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpModule,
HttpClientModule,
HeaderModule,
FixedNavModule,
Form1Module,
NgbModule.forRoot()
],
providers: [DataService],
bootstrap: [AppComponent]
})
export class AppModule { }
What do I need to enter in the nav.component.html to see the results?
Also note that when I refresh my angular page on lcoalhost:4200 I can see that the GET request is hitting the /apiu/ on the 3000 express server.
I am trying to help with best practices which might help get the intended result. I will amend this answer as we troubleshoot and hopefully arrive at the right answer.
So in your dataServices service I wanted to point out a couple things. Angular recommends we use the httpClient and not http and warn that http will soon be depreciated. I am fairly new to angular myself and have only ever used httpClient and have gotten great results so I recommend using that. I think this means that the promise that you are returned is changed too. Namely, you pust use a .pipe method inorder to use rxjs operators like map on the result. So this is what your dataService file would look like:
import { Injectable } from '#angular/core';
import { HttpClient } from'#angular/common/http';
import { Http, Headers, RequestOptions, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/toPromise';
export class Series {
Issuer_Id: number;
Data_Id: number;
Data_Name: string;
}
#Injectable()
export class DataService {
constructor(private _http: HttpClient) {}
getSeries(): Observable<Series[]> {
return this._http.get<Series[]>("http://localhost:3000/api/")
.pipe(
map((res) => {
console.log(res);
return <Series[]> res
})
)
}
}
Note that I have imported map in a different rxjs/operators.
In actuality you dont even need to pipe or map the return since you have already declared the type of return in the get method of _http. HttpClient will cast the return into a Series[] for you so this one liner: return this._http.get("http://localhost:3000/api/") would work. I've written the code how it is however to console.log the return that your getting.
In the comments, could you tell me what is logged?
I am unable to correct your code I am providing my own setup Works for Me
In server.js
module.exports.SimpleMessage = 'Hello world';
Now in App.js
var backend = require('./server.js');
console.log(backend.SimpleMessage);
var data = backend.simpleMessage
In index html include App.js
<script src = '/App.js'></script>
alert(simpleMessage)
And you should get 'hello world'

Lazy loaded module create multiples instance of the parent service each time is loaded

Every time I navigate from MainComponent to TestListComponent the TestListComponent constructor is triggered and a new instance of the ObservableServiceis created. When I click the link the console show the duplicated messages. Maybe is an angular issue, any help?
main.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import {MainRoutingModule} from "./main-routing.module";
import {MainComponent} from './main.component';
import {ObservableService} from "../../core/services/observable.service";
#NgModule({
imports: [
BrowserModule,
MainRoutingModule,
],
declarations: [MainComponent],
providers: [ObservableService],
bootstrap: [
MainComponent
]
})
export class MainModule { }
main.routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
export const routes: Routes = [
{ path: 'tests', loadChildren: 'angular/app/modules/test-list/test-list.module#TestListModule'},
{ path: '**', redirectTo: '' }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class MainRoutingModule {}
observable.service.ts
import { Injectable } from '#angular/core';
import {Subject} from "rxjs/Rx";
import 'rxjs/add/operator/map'
#Injectable()
export class ObservableService {
// Observable string sources
private changeLanguageStatus = new Subject<Object>();
// Observable string streams
changeLanguageStatus$ = this.changeLanguageStatus.asObservable();
constructor(){}
/**
* Change language event
* #param params
*/
changeLanguageEvent(params: Object){
this.changeLanguageStatus.next(params);
}
}
test-list.module.ts
import { NgModule } from '#angular/core';
import {TestListComponent} from "./test-list.component";
#NgModule({
declarations: [
TestListComponent
]
})
export class TestListModule {}
test-list.component.ts
import {Component} from '#angular/core';
import 'rxjs/Rx';
import {ObservableService} from "../../core/services/observable.service";
#Component({
moduleId: module.id,
selector: 'st-test-list',
templateUrl: 'test-list.component.html'
})
export class TestListComponent {
constructor(private observableService:ObservableService) {
observableService.changeLanguageStatus$.subscribe(
data => {
console.log('Test', data);
});
}
}
main.component.ts
import {Component, ViewChild} from '#angular/core';
import 'rxjs/Rx';
import {ObservableService} from "../../core/services/observable.service";
#Component({
moduleId: module.id,
selector: 'st-main',
templateUrl: 'main.component.html'
})
export class MainComponent {
constructor(private observableService:ObservableService) {}
changeLanguage(lang){
this.observableService.changeLanguageEvent({type: lang});
}
}
main.component.html
<!--Dynamic content-->
<router-outlet></router-outlet>
It should be expected behavior that when you navigate to a component via routing it is created and when you navigate back it is destroyed. As far as I know you are experiencing this issue because you are creating what is called an Infinite Observable i.e. you are subscribing to it and waiting for a stream of events, in your case changing language. Because you never unsubscribe from your Observable, the function subscribed to it is kept alive for each new instance of your component. Therefore, rxjs won't handle disposing of your subscription and you will have to do it yourself.
First off I'd suggest you read about Lifecycle hooks. Check out the OnInit and OnDestroy lifecycle hooks.
Use ngOnInit to subscribe to your Observable and use ngOnDestroy to unsubscribe from it as such:
import { Component, OnInit, OnDestroy } from '#angular/core';
import { Subscription } from 'rxjs/Subscription';
#Component({ .... })
export class TestListComponent implements OnInit, OnDestroy
{
private _languageSubscription : Subscription;
ngOnInit(): void
{
this._languageSubscription = observableService.changeLanguageStatus$.subscribe(
data => {
console.log('Test', data);
});
}
ngOnDestroy() : void
{
this._languageSubscription.unsubscribe();
}
}
I hope this will solve your problem.

Understanding Angular2 Dependency Injection in modules

I have written a feature module , and below is the code
app.ticket.service.ts, this is my service which i would like to inject
'use strict';
import { Injectable } from '#angular/core'
Injectable()
export class AppTicketService {
SaveTicket(): string {
return "service saved ticket";
}
}
app.tickets.module.ts, this is my feature module
'use strict';
import { NgModule } from '#angular/core';
import { SharedModule } from '../shared/app.shared.module';
import { AppCreatTicketComponent } from './app.create-ticket.component';
//-- import services
import { AppTicketService } from './app.ticket.service';
//-- import routing
import { ticketRouting } from './app.ticket.routing';
#NgModule({
declarations:[ AppCreatTicketComponent],
imports:[ SharedModule,
ticketRouting],
exports:[],
providers:[AppTicketService]
})
export class TicketsModule { }
app.create-ticket.component.ts , this is my component ,
which belongs to feature module
'use strict';
import { Component , OnInit , Inject} from '#angular/core';
//-- import service
import { AppTicketService } from './app.ticket.service';
#Component({
templateUrl: '/tickets/create'
})
export class AppCreatTicketComponent implements OnInit{
ngOnInit(){}
constructor(public service1 :AppTicketService) {
let test = this.service1.SaveTicket();
}
}
At runtime I am getting:
"Can't resolve all parameters for AppCreatTicketComponent:" error in browser console
What needs to be modified to resolve this issue?
To fix this issue I had to modify constructor paramter in app.create-ticket.component.ts file
Original
constructor(public service1 :AppTicketService)
Modified
constructor(#Inject(AppTicketService) private service1: AppTicketService)
You can find reason for this here

How to import Javascript library in angular2 globally

I'm trying to import the moment.js library in angular2.
I found the following solution as:
import {Component} from 'angular2/core';
import * as moment from 'moment';
#Component({
selector: 'app',
template: require('./app.component.html')
})
export class AppComponent {
moment:any = moment;
constructor() {}
}
However, I do not want to import this to every component I have. Is there a way to inject it globally so I can use it in all my components?
From what I read here, I can provide the momentjs library when bootstrap the whole application like this:
import * as moment from 'moment';
import {provide} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
bootstrap(App, [
provide("moment", {useValue:moment})
])
Then I can use it in my own component by using DI, like this:
import {Component, OnInit, Inject} from 'angular2/core';
#Component({
selector: 'app',
template: require('./app.component.html')
})
export class AppComponent {
constructor(#Inject("moment") private moment) {}
}
Derive your components from a common base type that imports moment.
Parent
import * as moment from 'moment';
export class MomentAwareClass {
moment:any = moment;
constructor() {}
}
Child
import {Component} from 'angular2/core';
#Component({
selector: 'app',
template: require('./app.component.html')
})
export class AppComponent extends MomentAwareClass {
constructor() {}
}
Update
A better way is to use Dependency Injection to write a service with the Injectable() decorator, this is better as composition is preferred over inheritance.
import { Injectable } from '#angular/core';
import * as moment from 'moment';
#Injectable()
export class SomeClass {
public moment: any = moment;
}

Categories

Resources