Angular service instantiated twice? - javascript

somehow I've got a service that seems to be instantiated twice (its properties are not in sync), by doing the following:
#Component
export class MyComponent extends someOtherComponent {
constructor(service: Service, service2: Service2) {
super(service, service2);
}
isStateEqual() {
return this.service.serviceState === this.service2.service.serviceState;
}
}
#Injectable
export class Service {
serviceState = {}
}
#Injectable
export class Service2 {
constructor(service: Service) {}
}
This is just a very basic example, but that's what it comes down to. To be more precise: We're building our own datepicker and extending NgbDatepicker component which has KeyMapService (this uses NgbDatepickerService) and a local NgbDatepickerService.Here is a link to the component: https://ng-bootstrap.github.io/#/components/datepicker/examples
In our app isStateEqual will always return false (even right after initialising the component) while in the demo you can find in the link above it will always return true (which is how it should be).
Anyone knows why it could be like that?
Thanks in advance.
Regards
Dennis

Application wide singletons must be defined on the bootstrapped module:
platformBrowserDynamic()
.bootstrapModule(AppModule)
#NgModule({
providers: [SingletonService1, SingletonService2],
bootstrap: [AppComponent]
})
export class AppModule {}
source
or by setting providedIn: 'root' on the service decorator:
#Injectable({
providedIn: 'root',
})
export class UserService {
}
source

In my case the service was instantiated twice, because I imported the service using two different approaches (my IDE (VS2019) mishelped me here by automatically generating the incorrect import):
import { Service } from '#mycompany/mymodule'
and
import { Service } from '../../../dist/#mycompany/mymodule/#mycompany-mymodule';

Visual code import my service in this way automatically
import { ConfigService } from 'src/app/services/config.services.js';
And the correct way is:
import { ConfigService } from 'src/app/services/config.services';

It depends where you declare the provider for your services - this determines the scoping. You don't specify in your question where you've done this - try doing it in AppModule, for example.

"service" must be a public propertie of Service2.
#Injectable
export class Service2 {
service:Service
constructor(service: Service)
{
this.service=service;
}
}

Related

How to properly inject provider in NestJS?

I create a Firebase provider like below(without using module file with exports and imports):
#Injectable()
export class FirebaseProvider {
public app: admin.app.App;
constructor() {
this.app = admin.initializeApp(config);
}
}
and add this provider to providers in AppModule:
providers: [AppService, FirestoreProvider, ClientService],
and in ClientModule:
providers: [CustomersService, FirestoreProvider],
so, now i want to use this provider in my ClientService, so I inject this provider via constructor like below:
constructor(
private readonly firestoreProvider: FirestoreProvider,
) {}
and now i have a problem, can somone tell me why NestJs inject me this provider more than one time and because of this firebase throw me this error:
The default Firebase app already exists. This means you called initializeApp() more than once without providing an app name as the second argument. In most cases you only need to call initializeApp() once. But if you do want to initialize multiple
apps, pass a second argument to initializeApp() to give each app a unique name.
I initialize this firebase only in this provider, so how to properly use this provider in services across the whole project?
thanks for any help!
I don't think you want to declare your FirestoreProvider in the provider:[] array of a module more than once. Try something like this:
#Module({
imports: [
FirestoreModule
],
})
export class AppModule{}
Now that you've imported the FirestoreModule, you can use it in any class that is in this AppModule. Example:
#Injectable()
export class FooService {
constructor(private firestore: FirestoreProvider) {}
}
The key here is to define your provider in its own module, then export it via the exports:[] array, and provide it via the providers:[] array of that module.
import { FirestoreProvider } from './FirestoreProvider'
#Module({
providers: [ FirestoreProvider ],
exports: [ FirestoreProvider ],
})
export class FirestoreModule{}
#Injectable()
export class FirestoreProvider {
public app: admin.app.App;
constructor() {
this.app = admin.initializeApp(config);
}
}

Avoid Multiple Instances of Service in Angular

I have done some research on the net, and I have figured out that the problem I am facing is that multiple instances of service are being created, and I want to avoid that. Can some one please look at my code and spot the change I need to make.
Second service that uses the primary service that is being duplicated.
export class SecondaryService {
constructor(private primarySvc: IPrimaryService){
this.primarySvc.someSubject.subscribe(() => {});
}
}
Primary Service (the one that is being duplicated)
export class PrimaryService {
someSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
constructor(){}
}
Primary Service Provider
#Injectable()
export class PrimaryServiceProvider extends PrimaryService {
constructor(){
super();
}
}
Secondary Service Provider
#Injectable()
export class SecondaryServiceProvider extends SecondaryService {
constructor(private PrimaryProvider: PrimaryServiceProvider){
super(PrimaryProvider);
}
}
app.module.ts
#NgModule({
declaration: [SecondaryComponent],
exports: [SecondaryComponent],
imports: [BrowserModule],
providers: [SecondaryServiceProvider, PrimaryServiceProvider ]
})
export class SearchModule{}
Now I am trying to use the component I made in a local environment which looks something like this:
app.module.ts
#NgModule({
declaration: [AppComponent, HomeComponent],
imports: [SearchModule, BrowserModule],
providers: [PrimaryServiceProvider, SecondaryServiceProvider],
bootstrap: [AppComponent]
})
export class AppModule{}
home.component.ts
export class HomeComponent {
constructor( primarySvc: PrimaryServiceProvider,
secondarySvc: SecondaryServiceProvider) {
this.primarySvc.someSubject.next(false);
}
}
Now I know for sure the Primary Service has two instances since someSubject is not in sync, and the subscribe in SecondarySvc is not fetching any values from home.component.ts
Please tell me where do i need to make the changes
Thanks!!
Answering my own Question:
The services were duplicated due to incorrect file path while importing. Windows lets you use case-insensitive file paths, which may create multiple instances for every time the module is used.
I think you are overengineering using the PrimaryServiceProvider and SecondaryServiceProvider services.
To create a singleton service just set providedIn: 'root' option in the Injectable decorator, like this:
#Injectable({ providedIn: 'root' })
export class SecondaryService {}
At last, be sure to not register a singleton service at any providers array.
Check out the official documentation about this here.

Why is a singleton service instantiated on every route change and not only once in Angular 6?

I have a service which is defined like this:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable, of, Subscription, combineLatest } from 'rxjs';
import { map, catchError, retry } from 'rxjs/operators';
#Injectable({
providedIn: 'root',
})
export class MyDataService {
constructor(private http: HttpClient) {
console.log('Called MyDataService constructor');
}
}
As far as I understand this service should be singleton throughout the runtime of the apllication.
Now, when the page refreshes, it logs "Called DataService constructor" correctly.
Unfortunately when I navigate to another page (new routes with lazy loading modules) the constructor is run again and it logs "Called DataService constructor" on each route change.
Did I miss something?
providedIn: 'root' means that it will only be instantiated once and the same instance will be provided to all dependency requests. If you are see the constructor run more than once then you are providing it somewhere else. Search for where you are providing it as providedIn: 'root' does not need to be listed in a provides list. Search for "provides : [" and see what is providing the MyDataService and remove it. If you are using VS Code you can right click on the class name and select find all references and see where it is in a provides array.

Angular4/5 dependency injection docs not working

https://angular.io/guide/architecture#services
I'm following the docs on angular.io to inject dependencies like services, etc. I did everything they said and when I try to run it, the console keeps telling me:
Uncaught ReferenceError: LedgerService is not defined
I am doing nothing crazy except creating a simple component with a service where both constructors have console.log commands (constructors in both the component and service). I've done everything Angular says to do in their 2 paragraphs that details this feature of Angular.
The component itself is being injected into the main app module (with the service being injected into the component) and both the component and service were created with the Angular CLI. So there isn't much I've even done at all minus trying to inject the service. So I'm not sure where it is going wrong but it is definitely not working and just shows a blank page (when it previously had basic content by default).
I created both units, tried to specify providers in both the app.module and the component.ts file and neither works and yields the same error--when Angular claims either could work. I've also specified it as a private service within the constructor of the component.ts file.
Everything I've seen relating to this is always for Angular 1 or 2. Neither of which are even remotely similar to Angular 4/5.
If you really want to see this code, fine but it's literally just framework and nothing else:
bookkeeper.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-bookkeeper',
templateUrl: './bookkeeper.component.html',
styleUrls: ['./bookkeeper.component.css'],
providers: [LedgerServiceService]
})
export class BookkeeperComponent implements OnInit {
constructor(private service: LedgerServiceService) { }
ngOnInit() {
console.log("Ledger component works!");
}
}
app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { InterfaceComponent } from './interface/interface.component';
import { BookkeeperComponent } from './bookkeeper/bookkeeper.component';
#NgModule({
declarations: [
AppComponent,
InterfaceComponent,
BookkeeperComponent
],
imports: [
BrowserModule
],
providers: [
LedgerServiceService
],
bootstrap: [AppComponent]
})
export class AppModule { }
ledger-service.service.ts:
import { Injectable } from '#angular/core';
#Injectable()
export class LedgerServiceService {
constructor() {
console.log("wtf");
}
}
LedgerService is actually called LedgerServiceService because I initially created LedgerService manually and then tried to use the AngularCLI to generate a service and named it LedgerService and it created a service called LedgerServiceService. Naming is not what is wrong. I only initially called it simply LedgerService because I figured it would be confusing.
Your examples are missing the import.
Anywhere we use a custom type, we also need to import that type.
For that reason, in both the module and component you will need to add:
import { LedgerServiceService } from './your-path-here'
You can see this in the examples they give on https://angular.io/guide/dependency-injection

Javascript Angular using code from different .ts file

I'm working on an Angular4 project and I have created a filter on my app.component.ts which I'm currently using on my app.component.html.
<button (click)="filterBy('cars')">Cars</button>
This works fine in this file by I want to use this same filter on my nav.component.html but I'd like to avoid recreating the filter code again on the nav.component.ts.
Is there a way of using this filter on my nav.component.html from app.component.ts ?
Migrate your created filter code in some new .ts file. Import this file in your app.component and other components by using import {ClassName} from file.ts syntax and then easily implement it in your component html code
You can create service, for example "filter.service.ts". Good thing in service is - it will create only one instance. So you use less memory, and app is faster.
Then - you can include it to the parent module:
import { FilterService } from "some/filter.service.ts";
#NgModule({
declarations: [ AppComponent, NavComponent],
providers: [ FilterService ]
})
export class MyModule { }
And use in your components like this:
import { FilterService } from "some/filter.service.ts";
constructor(filter: FilterService) {
this.filter = filter;
}
And then your html:
<button (click)="filter.filterBy('cars')">Cars</button>
#Injectable()
export class Service{
//create all the logic here for all the things you want to be shared across compponents
}
call this in the component you want to use like
import {Service} from "../shared/service";
#Component({
selector: 'app-angular4'
})
export class Angular4Component implements OnInit {
constructor(private service:Service) {
// resuse all the methods
}

Categories