What is the best approach for injecting services (local and API) in Angular 13 based on different environments (local and QA)?

api-local.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { LoginRequest } from '../login/login-request';

@Injectable({
  providedIn: 'root'
})

export class ApiLocalService {

  constructor(private httpClient: HttpClient) { }
  
  private headers = new HttpHeaders({
    'Content-Type': 'application/json; charset=utf-8',
    'Accept': 'application/json, text/plain'
  });

  userLoginLocal(){
    console.log("inside LOCAL API service");
    return this.httpClient.get('../assets/data/login.json', {headers:this.headers});
  }

  getUserListLocal(){
    return this.httpClient.get('../assets/data/userList.json' , { headers: this.headers })
  }
}

api.service.ts

import { Inject, Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { LoginRequest } from '../login/login-request';
import { EnvironmentConfig, ENV_CONFIG } from './environment-config.interface';

@Injectable({
  providedIn: 'root'
})

export class ApiService {

    public apiUrl: string;

  constructor(@Inject(ENV_CONFIG) config: EnvironmentConfig,private httpClient: HttpClient,) {
    this.apiUrl = `${config.environment.baseUrl}`;
   }
  
  private headers = new HttpHeaders({
    'Content-Type': 'application/json; charset=utf-8',
    'Accept': 'application/json, text/plain'
  });

  userLoginLocal(){
    console.log("inside LOCAL API service");
    return this.httpClient.get('../assets/data/login.json', {headers:this.headers});
  }

  getUserListLocal(){
    return this.httpClient.get('../assets/data/userList.json' , { headers: this.headers })
  }
}

auth-service.ts

import { EventEmitter, Injectable, Output } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { HttpClient } from '@angular/common/http';

import { LoginRequest } from '../login/login-request';
import { LoginResponse } from '../login/login-response';
import { LocalStorageService } from 'ngx-webstorage';
import { map, tap ,catchError} from 'rxjs/operators';
import { environment } from 'src/environments/environment';

import { ApiLocalService } from './api-local.service';


@Injectable({
  providedIn: 'root'
})
export class AuthService {

  private API_URL = environment.API_URL;
  // private Local_Env = environment.Local_Env;
  private roles: Array<string> = [];

   
  @Output() loggedIn: EventEmitter<boolean> = new EventEmitter();
  @Output() username: EventEmitter<string> = new EventEmitter();
  @Output() admin: EventEmitter<boolean> = new EventEmitter();
  @Output() superAdmin: EventEmitter<boolean> = new EventEmitter();
  @Output() client: EventEmitter<boolean> = new EventEmitter();

  refreshTokenPayload = {
    refreshToken: this.getRefreshToken(),
    username: this.getUserName()
  }
  constructor(private httpClient: HttpClient,private localStorage: LocalStorageService, 
              private apiLocalService:ApiLocalService) { 
}
    
 
adminLogin(loginRequest: LoginRequest): Observable<boolean> {
  console.log("loginrequest:"+loginRequest);
  return this.httpClient.post<any>(this.API_URL+'/auth-service/login', loginRequest)
    .pipe(map(data => {
      console.log(data)
      if(data.roles.find((role: string) => role !='ROLE_SUPER_ADMIN' && role !='ROLE_ADMIN' && role !='ROLE_CLIENT')){
        return false;
      }else{
      this.localStorage.store('authenticationToken', data.authenticationToken);
    this.localStorage.store('username', data.username);
    this.localStorage.store('refreshToken', data.refreshToken);
    this.localStorage.store('expiresAt', data.expiresAt);
    this.localStorage.store('roles', JSON.stringify(data.roles));
    this.loggedIn.emit(true);
    this.username.emit(data.username);
    if(data.roles.find((role: string) => role =='ROLE_ADMIN')){
      this.admin.emit(true);
    }
    if(data.roles.find((role: string) => role =='ROLE_SUPER_ADMIN')){
       this.superAdmin.emit(true);
    }
    if(data.roles.find((role: string) => role =='ROLE_CLIENT')){
      this.client.emit(true);
   }
    
    return true;
      }
    }));
  
}

Auth-service has the adminLogin which is called in 'login' component. My requirement is to call the api-local.service.ts when the environment is local, otherwise call api.service.ts when the environment is qa. These services should be injected in auth-service.ts inside the adminLogin(). Quick assistance would be highly appreciated...

Answer №1

One approach to tackle this issue is as follows:

  1. Start by defining an interface that outlines the methods for your two services:
export interface IApiService {

   userLoginLocal(): Observable<Add type here>;

   getUserListLocal(): Observable<Add type here>;

}
  1. Proceed to have your services implement this interface
...
export class ApiService implements IApiService {
   ....
}

export class ApiLocalService implements IApiService {
  ...
}
  1. Inject both services into your AuthService:
export class AuthService {

    private apiService: IApiService;

    constructor(apiService: ApiService, apiLocalService: ApiLocalService) {
        if (environment.localEnv) {
           this.apiService = apiLocalService;
        } else {
           this.apiService = apiService;
        }
        // you can now utilize this.apiService...
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The Vue property I customized in my component is not being recognized by VSCode(Vetur)

I've successfully implemented a plugin in Vue by declaring it in a main.ts file, defining its type in a plugin.d.ts file, and utilizing it in a component.vue file. Although the compilation is error-free, I am encountering an issue with VSCode intellis ...

Ways to access subscription value in Angular without relying on async await

Is there a way to extract the value inside the subscribe in Angular? I am dealing with this code snippet: async trackingInfo(trackingNumber) { const foo = await this.userService .trackOrderStatus(trackingNumber) .subscribe((status) => ...

Angular 7 ng-select validation with required form control

Currently, I am utilizing the ng-select plugin for a dropdown search feature, but I am encountering issues with validation when a selection is not made from the dropdown menu. Here is how I have implemented it: <div class="form-group"> <ng-sel ...

Angular Material card layout design

I am looking to create a unique gallery layout for my images using polaroid card-based system with multiple rows and columns. The issue I am encountering is with the mat-card attribute stretching to match the size of portrait images, causing distortion in ...

What is the best way to combine data from two rows into one row?

Can someone help me with merging 2 sets of Line data into a single row for each entry? For example, the 'Green Bay Packers @ Chicago Bears' row should display '+3.5000 and -3.5000', while 'Atlanta @ Minnesota' should show &apo ...

When a selection is made in React MUI Virtualized Autocomplete, the autocomplete menu scrolls back to the top

I am currently using reactMUI autocomplete with virtualization because the listbox is expected to contain thousands of items. The virtualization feature works fine, but when I add an onchange function, the listbox automatically scrolls back to the top wh ...

Passing data from child components to parent components in NextJs using Typescript

I have created a new component <ConnectWallet setConnected={(t: boolean) => console.log(t)}> <>test</> </ConnectWallet> The component is initialized as follows import { useState, useEffect } from ' ...

Assign variable data to properties within an immutable object within a React component

I have declared a Const in my config.service.ts file like this: export const mysettings={ userid:"12324", conf:{ sessionDuration:30, mac:"LON124" } } I am using this constant in various components. However, instead of hardcoding these val ...

Displaying search results in various Angular components

On my home page (homePageComponent), I have a search feature. When the user clicks on the search button, they are redirected to a different page called the search list page (searchListComponent). Within the searchListComponent, there is another component c ...

Eliminating Body Tag Margin in Angular 4: A Step-by-Step Guide

In the Angular 4 project, the app.component.html file does not include a body tag that can be styled to eliminate the padding associated with the body tag. https://i.sstatic.net/5QS9x.jpg An attempt was made in the app.component.css file to remove the ma ...

The type '[Images]' cannot be assigned to type 'string'

I am attempting to pass an array of objects through props, but encountered the following error: (property) images: [Images] Type '[Images]' is not assignable to type 'string'.ts(2322) ProductBlock.tsx(4, 5): The expected type co ...

My Angular custom libraries are having issues with the typing paths. Can anyone help me troubleshoot what I might be doing

After successfully creating my first custom Angular library using ng-packagr, I encountered an issue where the built library contained relative paths specific to my local machine. This posed a problem as these paths would not work for anyone else trying to ...

Retrieving Data from Angular Component within a Directive

Currently, I am in the process of creating an "autocomplete" directive for a project. The aim is to have the directive query the API and present a list of results for selection. A component with a modal containing a simple input box has been set up. The ob ...

Issues encountered with sending post requests to a yii2 application when using Angular4

After implementing the following code: this.http.post('http://l.example/angular/create/', {name: 'test'}).subscribe( (response) => console.log(response), (error) => console.log(error) ); I encountered an error on ...

Attempting to incorporate an npm package (specifically Howler) into an Angular 2 application

I'm facing an issue with importing Howler into my Angular 2 app as it doesn't have a typings file. Despite my efforts in searching for a solution, I haven't been able to find anything helpful. Can someone guide me on how to import "howler" i ...

Problem with moving functions from one file to another file via export and import

I currently have the following file structure: ---utilities -----index.ts -----tools.ts allfunctions.ts Within the tools.ts file, I have defined several functions that I export using export const. One of them is the helloWorld function: export const hel ...

Exploring the capabilities of observables in mapping nested dynamic object keys, specifically focusing on manipulating data within angular-calendar events

Perhaps utilizing something like map<T,R> would be a better approach than my current method. I am hoping to receive some advice on how to resolve this issue. Currently, no events are being mapped due to incorrect mapping resulting in an incorrect pat ...

Ways to trigger re-validation of a field in an angular reactive form

Currently, I am working with Angular and utilizing reactive forms along with material UI. One scenario that I have encountered is having a form field that should only be required if another specific field has been selected - such as displaying a text input ...

What is the methodology behind incorporating enumerations in typescript?

I've been curious about how typescript compiles an enumeration into JavaScript code. To explore this, I decided to create the following example: enum Numbers { ONE, TWO, THREE } Upon compilation, it transformed into this: "use strict ...

Having trouble getting Angular 2 animations to fade in

I've been trying to figure out how to make the html fadeIn for hours. Every time ngFor displays it, the opacity stays at 1 immediately, without fading in. FadingOut works fine, but the fadeIn effect is not working as expected. @Component({ selector:& ...