use AngularJS service for Angular component - javascript

I have AngularJS service :
var id = 'authService';
angular.module('app')
.service(id, ['$http', '$q', '$injector', 'storageSvc', 'notifyHub', 'sysSettings', '$rootScope', 'crudSvc', authService]);
and would like to use it inside my angular component SignInComponent :
import { Component, Inject } from '#angular/core';
import { Account } from '../../../../shared/models/account';
import { AuthService } from "../../../../shared/angularJS-upgraded-providers";
#Component({
selector: 'sign-in',
templateUrl: './sign-in.component.html'
})
export class SignInComponent {
constructor(
#Inject(AuthService) private authService: any) {
this.authService = authService;
}
model = new Account('admin02', 'Admin#002', true);
onLogin() {
this.authService.login(this.model).then(response => {
if (response != null) {
alert("Seems it works");
}
});
}
}
For this purpose I created angularJS-upgraded-providers.ts file :
import { InjectionToken } from "#angular/core";
export const AuthService = new InjectionToken<any>('authService');
export function authServiceFactory(i: any) {
return i.get('authService');
}
export const authServiceProvider = {
provide: AuthService,
useFactory: authServiceFactory,
deps: ['$injector']
};
and trying to reuse it inside app.module.ts :
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { UpgradeModule } from '#angular/upgrade/static';
import { SignInComponent } from "./modules/login/components/sign-in/sign-in.component";
import { authServiceProvider } from './shared/angularJS-upgraded-providers';
#NgModule({
declarations: [
SignInComponent
],
imports: [
BrowserModule,
UpgradeModule,
FormsModule
],
entryComponents: [
SignInComponent
],
providers: [authServiceProvider
],
bootstrap: [SignInComponent]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngOnInit() {
this.upgrade.bootstrap(document.body, ['app']);
}
}
My start file - main.ts looks like this :
import { enableProdMode } from '#angular/core';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
But when I am trying to run my program I have an error :
ERROR Error: Trying to get the AngularJS injector before it being set.
at injectorFactory (static.js:690)
at _callFactory (core.js:10956)
at _createProviderInstance$1 (core.js:10910)
at resolveNgModuleDep (core.js:10892)
at _callFactory (core.js:10958)
at _createProviderInstance$1 (core.js:10910)
at resolveNgModuleDep (core.js:10892)
at NgModuleRef_.push../node_modules/#angular/core/esm5/core.js.NgModuleRef_.get (core.js:12129)
at resolveDep (core.js:12619)
at createClass (core.js:12481)
Could please anybody provide algorithm or at least give an idea what i am doing wrong and why i am getting the error : Error: Trying to get the AngularJS injector before it being set?
Which template or pattern I could use to be able to consume AngularJS service inside my Angular5 app?
AngularJS version : 1.6.8,
Angular version : 5.2.11
Thank you for your time

Related

Inject a service into another service in the same module

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
}
]

Angular 4 HttpClient in Component Can't resolve all parameters

I started learning Angular 4 and got to the part with HTTP Client. Right now I'm trying to make an http call from the component (yes, I know I should transfer it to service, but still)
But for some reason, when I try to inject HttpClient into my Component I get the next error:
Uncaught Error: Can't resolve all parameters for PromocodeComponent:
(?).
Here's the code of my component:
import { Ticket } from '../../classes/Ticket.class'
import { Component, Input } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'promocode',
templateUrl: './promocode.template.html',
styleUrls: ['./promocode.styles.scss']
})
export class PromocodeComponent {
#Input() ticket: Ticket;
state: String = "normal";
promocode: String = "";
constructor(private http: HttpClient) {}
promocodeValidate(event): void{
console.log(this.promocode);
console.log(event);
this.http.get('/promocode/asdasda').subscribe(data => {
console.log(data);
});
}
}
And my app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { MovieBadgeComponent } from './movie-badge/movie-badge.component';
import { TicketComponent } from './ticket/ticket.component';
import { PromocodeComponent} from './promocode/promocode.component';
import { FormsModule } from '#angular/forms';
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [
AppComponent,
MovieBadgeComponent,
TicketComponent,
PromocodeComponent
],
imports: [
BrowserModule,
HttpClientModule,
FormsModule
],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule {}
It turned out, for me, that I forgot the #Injectable decorator on my service. In earlier angular (>=2), i remember the #Injectable as being optional... Guess not anymore?
Turns out, I missed
"emitDecoratorMetadata": true
in tsconfig
fml...
I got the same error when I ran unit testing (a spec.ts file) with Angular.
The following is what I did:
import { HttpClientModule, HttpClient } from '#angular/common/http';
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ],
imports: [
HttpClientModule
],
schemas: [NO_ERRORS_SCHEMA],
providers: [
HttpClient,
]
})
.compileComponents();
}));
and the error was gone.

Angular2 Loading the api configuration from the server side before the app bootstrap starts shows

I am using the angular 2 web app. In that, i am getting app configuration details from the api before the app bootsrap. For that i searched on the browser and find out these links
How to call an rest api while bootstrapping angular 2 app
https://gist.github.com/fernandohu/122e88c3bcd210bbe41c608c36306db9
And followed them. In the angular-cli and also on the browser console i didn't get any error. But my page comes empty with loading text, that was i displayed in the before loading angular.
Here is my code
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, APP_INITIALIZER } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HttpModule, Http} from '#angular/http';
import { SocketIoModule, SocketIoConfig } from 'ng2-socket-io';
import { SharedModule } from './shared/shared.module';
import { TranslateModule, TranslateLoader} from '#ngx-translate/core';
import { TranslateHttpLoader} from '#ngx-translate/http-loader';
import { AppRoutingModule } from './app.route';
import { AppComponent } from './app.component';
import { ChatComponent } from './chat/chat.component';
import { ChatService } from './chat/chat.service';
import { AddressComponent } from './address/address.component';
import { HomeComponent } from './home/home.component';
import { SettingService } from './shared/service/api/SettingService';
import { FilterByPipe } from './filterPipe';
import { Ng2ScrollableModule } from 'ng2-scrollable';
import { AppConfig } from './app.config';
import {Injectable} from '#angular/core';
import {Observable} from 'rxjs/Rx';
const config: SocketIoConfig = { url: 'http://192.168.1.113:7002', options: {} };
export function HttpLoaderFactory(http: Http) {
return new TranslateHttpLoader(http, "http://192.168.1.114:7001/frontend-translation/", "");
}
export function SettingServiceFactory(setting: SettingService) {
return () => setting.load();
//return true;
}
#NgModule({
declarations: [
AppComponent,
ChatComponent,
AddressComponent,
HomeComponent,
FilterByPipe
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
AppRoutingModule,
Ng2ScrollableModule,
SocketIoModule.forRoot(config),
SharedModule,
TranslateModule.forRoot({
loader: {
provide : TranslateLoader,
useFactory: HttpLoaderFactory,
deps : [Http]
}
}),
],
providers: [
ChatService,
AppConfig,
SettingService,
{
provide : APP_INITIALIZER,
useFactory: SettingServiceFactory,
deps : [SettingService],
multi : true
}
/*SettingService,
{
provide : APP_INITIALIZER,
useFactory: (setting:SettingService) => () => setting.load(),
//deps : SettingService,
multi : true
}*/
],
bootstrap: [AppComponent]
})
export class AppModule { }
SettingService.ts
In this file, i am loading the api configuration from the server side
import {Injectable} from '#angular/core';
import {Http, Response} from '#angular/http';
import {Observable} from 'rxjs/Rx';
#Injectable()
export class SettingService {
public setting;
constructor(private http: Http) {}
/**
* Retrieves the setting details of the website
* #return {Object} language tranlsation
*/
public load()
{
return new Promise((resolve, reject) => {
this.http
.get('http://192.168.1.114:7001/settings')
.map( res => res.json() )
.catch((error: any):any => {
console.log('Configuration file "env.json" could not be read');
resolve(true);
return Observable.throw(error.json().error || 'Server error');
})
.subscribe( (envResponse) => {
this.setting = envResponse;
});
});
}
}
When i replace the load() api service within below code it works fine
public load() {
return {
"test": "works well"
}
}
But with api call, it doesn't.
What i found was, when i am returning the json object it works, but when i am making api call return the promise object it won't. I don't know how to solve this.
Thanks in advance.
My project was little bigger, so i can't put in plunker
Try to use promise object like this:
load(): Promise<Object> {
var promise = this.http.get('./app.json').map(res => res.json()).toPromise();
promise.then(res=> this.label= res);
return promise;
}

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