Nestjs Custom configService for Applications in Nx Monorepo - configuration

Im trying to create a custom configuration service for each of the nestjs applications within my nx monorepo. So far, this is the solution that I have come up with.
Each custom config service will inject the default nest configService, pass the nestjs configService a generic to indicate the list of configurations for that application. and wrap the retrieval of each configuration variable in a getter method. An example of such a service will look like this:
#Injectable()
export class AppConfigService {
constructor(private readonly configService: ConfigService<envVars>) {}
get nodeEnv(): Environment | undefined {
return this.configService.get('NODE_ENV');
}
}
The main config module for each application will be set as a global module and will use an alias provider so libraries that are used in multiple applications can access the config service by the same name regardless of the application that is using them:
const RootAppConfigModule = ConfigModule.forRoot({
isGlobal: true,
validate,
envFilePath: './.env',
});
#Module({
imports: [RootAppConfigModule],
providers: [
AppConfigService,
{
provide: 'AppConfigService',
useClass: AppConfigService,
},
],
})
Each service that requires the configService will then inject the config service token. The type of the value being injected will be a custom interface describing the configurations that are required in that service. The class’s constructor will also assert that the configurations exist on the injected configService:
#Injectable()
export class sessionThatUsesConfig {
constructor(
#Inject('AppConfigService') configService: configurations,
) {
assert(configService.confgValue);
}
somethingThatNeedsAConfig() {
console.log(this.configService.configVal)
}
}
The main issue I am running into is that the injected appConfigService value on the is not recognized by the service injecting it. Has anyone done something like this before and if so, is there another way to go about this?

Related

There is no `$ rootScope` in` Angular9`. What can be used?

In AngularJS i used$ rootScope to pass user data, for example:
$ rootScope.user = {
id: '4',
username: 'user'
...
};
$ rootScope.user.authenticated = false;
the data in $ rootScope was filled in every time a page was opened or updated using a query toSQL.
In Angular 9 i did not find the use of$ rootScope.
Tell me, where can such data be stored in Angular 9 and with what help can this functionality be implemented?
In angular, if you need anything like that, you create a service, provide it in root and inject it wherever you want it. For example:
The service:
// Create the service (providedIn: 'root') makes it available globally
#Injectable({providedIn: 'root'})
export class UserService {
user: any ={
id: '4',
username: 'user'
...
};
}
Using the service in a component:
#Component({...})
export class MyComponent implements OnInit {
_isAuthenticated: boolean;
// Inject the service
constructor(private _userService: UserService) {}
ngOnInit() {
// Using the service
this._isAuthenticated = _useService.user?.authenticated ?? false;
}
}
PS: The code above uses two interesting typescript features (which are new as I write this answer): optional chaining and Nullish Coalescing. You can always use a regular ternary operator instead of that:
this._isAuthenticated = _useService.user ? _useService.user?.authenticated : false
When my team and I migrated one of the projects from AngularJS to Angular, I took a look at when $rootScope was being used in the old app and it turns out it was used for identity/authentication 95% of the time. A few other use cases were regarding the spinner, browser related settings and edge cases.
It seems like your use case is similar to ours as well. I just folded that $rootScope.user into an existing AngularJS service called identity (or it could be auth, or whatever). So in each component that referred to that $rootScope.user, I replaced it with the following. The constructor is just dependency injection, allows you to use the variables within the identity service anywhere.
whatever.component.ts
currentUser = this.identity.currentUser
constructor(private identity: IdentityService) {}
The identity service looks something like the below. There's a getter function for the current user, and when it's not available, you look into the cookie, or otherwise, it's blank object (unauthenticated).
identity.service.ts
private _currentUser; //should only obtain currentUser via get currentuser()
constructor(private cookieService: CookieService) {}
get currentUser() {
if (!this._currentUser) {
this._currentUser = this.getUserFromCookie() || {}; //get from cookie
}
return this._currentUser;
}
getUserFromCookie() {
return this.cookieService.get('currentUser') ? JSON.parse(this.cookieService.get('currentUser')) : {};
}
Hopefully this gets you started and helps others as well.

How can I install separate mixpanel projects for development and production in angular5/angularitics

I have already configured mixpanel in my angular 5 app. Now I want to separate mixpanel project for production and development. I have already added mixpanel script snippet in index.html in head section containing token of production project. Now I need to add another token and select one based upon selected environment, but environment variable is not accessible in index.html. I don't want to have two separate index.html in my project. In another way as suggested here (How to integrate mixpanel with angular2).I set token from main.ts, but it is unable to access environment variable.Is there any way to set token in index.html based upon selected environment?
I am getting following error:
ERROR in /home/Project/src/main.ts (9,27): Property 'mixpanel' does not exist on type '{ production: boolean; }'.
exported api key from environment.ts:
export const mixpanel= {
apikey: 'MY_PROJECT_TOKEN_HERE'
}
main.ts
import { enableProdMode } from '#angular/core';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
declare const mixpanel: any;
enableProdMode();
mixpanel.init(environment.mixpanel.apikey);
platformBrowserDynamic().bootstrapModule(AppModule);

Angular 4 404 error - Call json file using http get method angular 4 webpack

I have a local json file and trying to read from Http get method.The application throwing an exception on console(404). I have read if you use webpack the assets/data are not available as for the angular-cli.json. I'm using webpack. Do you know where to put the json file so it can be read?
import {IProduct} from './product.model';
#Injectable()
export class ProductService {
private productUrl = require('./product.json');
constructor(private _http: HttpClient) { }
getProducts(): Observable<IProduct[]> {
return this._http.get<IProduct[]>(this.productUrl)
.do((data) => console.log('products: ' + JSON.stringify(data)))
.catch(this.handleError);
}
}
where product.json is in the same dir of the ProductService.
With webpack, no matter where you have stored your json file, you can access it from anywhere, but always starting from the src folder.
So it should look something like this:
return this._http.get<IProduct[]>('src/app/services/product.json')
i.e just mark the complete path to your json file starting from src.
If using angular cli
AFAIK there is one way to do this.
Save the file (say file.json) in assets folder.
In you angular-cli.json file, go to node: apps> assets and verify that name "assets" exists.
Now access:
http://localhost:[PORT_NUMBER]/assets/file.json
BTW, your web app should not be your api. Instead of consuming json file, create variables in your services.
Example:
import { Injectable } from "#angular/core";
#Injectable()
export class DataMockService {
public GetObjects(): any {
return {
name: "nilay", ...
};
}
}

Angular 2 functions library

In my application I'll need to create a functions library to be accessed from different components. What is the best way to do this? Do I need to make a service with all the functions or a class or a module or a component?
In this library if I call a function from a component and this function need to access a variable in the caller, will it be possible to do?
If it's just a set of one off helper functions the easiest way is create an #Injectable service with your helper methods then inject that into any component that requires them. You can provide public vars as well so they're accessible in your html.
#Injectable()
export class Helpers {
helper1() { return "hello"; }
helper2(x) { return x + 1 }
}
#Component({
providers: [Helpers],
template: "<div>{{helper1()}}</div>" // will display 'hello'
)}
export class MyComponent {
public helper1: Function = Helpers.helper1;
constructor() {
console.log(Helpers.helper2(5)); // will output '6'
}
}
This works great for a simple set of random utility functions. If you need something more in depth please explain and we can provide alternate solutions.

angular 2 RC4 create component

So here is the problem, I am attempting to create a new component from within a service that is injected within the App Component. I need the new component to be placed within the app component html tag not outside. The thing is I really do not want the app component to have to provide anything to the service I may need to inject the service into other places and hence not have it tightly coupled to the app component. So far I have created a DIV at the end of the app component html and then used #ViewChild to read the ViewContainerRef from this element located within the app component. This is then provided to the service via a function call so that it can make use of createComponent. This allows for the NEW component to be placed within the scope of the app component, not within the body. Unfortunately this is too dependant on the app component providing the ViewContainerRef. Any ideas of how I can create the new component as described.
Code Example
app.component.html
<app-component>
<div #newCompHook></div>
</app-component>
app.component.ts
#ViewChild('newCompHook', {read: ViewContainerRef}) newCompViewRef: ViewContainerRef;
constructor(appService: AppService) {
appService.setViewRef(this.newCompViewRef);
}
app.service.ts
private myViewRef;
constructor(private compiler: ComponentResolver){
this.myViewRef = null;
}
public setViewRef(vr: ViewContainerRef): void {
this.myViewRef = vr; // <-- DO NOT WANT TO DO THIS !!!
}
public createNewComp(childCmp: Type): void {
if (this.myViewRef !== null){
this.compiler.resolveComponent( childCmp ).then((compFactory:ComponentFactory) => this.myViewRef.createComponent(compFactory) )
}
}
createNewComp is called by an external source and may or may not provide the childCmp type to be resolved.
So any ideas of how I can do this without needing to provide anything from the app component ???
If you need to have the viewContainerRef in your service that is the only solution...
But it is not a good practice to generate HCI components in a service. It's the role of other components.
Let's take an exemple : your server send you a list of objects (a list of strings for exemple) and you want to generate a button for each string.
In your service you just manage the string list :
#Injectable()
export class MyService {
private myModel : Array<String> = new Array();
public get MyModel () : Array<String> {
return this.myModel;
}
/// Assume you have method in the service to populate the model...
}
Then it's your component which generate the HCI :
export class AppComponent {
/// Use dependency injection to get service :
constructor (private _myService : MyService){}
public get MyModel () : Array<String> {
return this.myService.MyModel;
}
}
Finally in your component template :
<div>
<ul>
<li *ngFor="let s of MyModel">
<!-- Button with your model text -->
<button>s</button>
</li>
</ul>
</div>
That is a better solution than generate the components in the service because just imagine you don't want buttons list but a togglebuttons list in your HCI, here you just have to change the HTML. The service is still the same, and the components typescipt part is still the same too !