Reputation: 3322
I am shifting from Razor views to Angular 4, and trying to figure out how to pass global constants from the server to Angular without relying on Ajax calls.
So the server constants will be transaction status for example:
Id: 1->Active
Id: 2-> Inactive
Id: 3->Cancelled etc
So these statuses are saved in the db and are used to query various transactions, Thus will be required in lots of components
In Razor views, I used to pass these values together with the viewmodel
. But in Angular currently I can see two options:
ngOnInit
of each component that requires these constantsOption 1 increases the number of server calls by quite a bit -> so I am trying to avoid this.
Option 2 will require me to change status in multiple places in my application if a new status is added for example, which i am also not fond of.
I am looking for a way to send all my constants to Angular as the application loads or page is reloaded for example.
Upvotes: 1
Views: 211
Reputation: 937
You need to use ReplaySubject
as per rxjs documentation
ReplaySubject:Represents an object that is both an observable sequence as well as an observer. Each notification is broadcasted to all subscribed
Look at this code snippet
export class GlobalConstants{
Status:number[];
}
import { Observable, ReplaySubject } from 'rxjs';
import { GlobalConstants } from '../models/GlobalConstants';
@Injectable()
export class YourService {
//This line will cache the latest list you will get from the server
private dataSubject = new ReplaySubject<GlobalConstants>();
//you will use this observer in your components to subscribe to the getStatus result
yourStatusList$: Observable<GlobalConstants> = this.dataSubject.asObservable();
constructor(private http: Http) {
this.getStatus()
}
getStatus() {
return this.http.get('url').subscribe(res => {
this.dataSubject.next(res);
})
}
export class ExampleComponent {
public statusList;
public constructor(private _yourService: YourService) {
this.getStatus();
}
getStatus(): void {
this._yourService.yourStatusList$.subscribe(
result => {
this.statusList = result;
}
)
}
}
what will happen is when angular create the service it will call getStatus method one time per the app life cycle and then fetch your status list from the server then u will need to subscribe in your components to yourStatusList$ , for each subscrbition you will get latest cached list and if the list changed in your server u just need to call YourService.getStatus then u will fetch the status list again and all component subscribed to this observer will get notified by the new list
let's take your two challenges
1-Make Ajax calls in ngOnInit of each component that requires these constants
-by using this code your app will make one call to the server to fetch status list so u don't need to make Ajax call in ngOnInit of each component
2-Make a static model to hold these values will require me to change status in multiple places in my application if a new status is added
-if new status is added you just need to call YourService.getStatus one time in any place in your code and all components subscribed to your yourStatusList will get notified by the new status list
NOTE: you must n't use providers: [yourService] in your component cause if u used it it will create a new object and will not use the global object , just add your service in @NgModule providers and use component constructor to inject the service object
Upvotes: 2
Reputation: 323
You can add you constants as attributes on your app element inside you razor view
<app someatt="{ your json data here }">Loading...</app>
then on you app's root component access them like this:
export class AppComponent implements OnInit {
constructor(
private el: ElementRef
) {
}
ngOnInit() {
console.log(this.el.nativeElement.attributes["someatt"].value);
}
}
then you can have a global service with its statuses data set here on ngOnInit and consumed in all your components
Upvotes: 1
Reputation: 25161
It may be best to have a service cache the information in a local variable. Then, when you inject the service into your components, and one calls a service function, the service checks the local variable. If something is in the variable, use it, if not, load the data and cache it for later use.
Since the service is a singleton, the data should only load once unless you create some mechanism to timeout the value. So, the first time the service is called, the data will be fetched. After that, the local variable (below called globals
) should be used.
Service:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class GlobalsService {
private globals: any;
constructor(private httpClient: HttpClient) { }
getGlobals(): any {
if (this.globals) {
return this.globals;
} else {
// call your API to get global data from DB
this.httpClient.get<any>('...').subscribe((data: any) => {
this.globals = data;
return this.globals;
});
}
}
}
Component using the service:
import { GlobalsService } from './../globals.service';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-tester',
templateUrl: './tester.component.html',
styleUrls: ['./tester.component.css']
})
export class TesterComponent implements OnInit {
constructor(private globalsService: GlobalsService) { }
ngOnInit() {
// Do something here with the globals from the service
const gbls = this.globalsService.getGlobals();
if (gbls) {
// ... maybe put these in a variable for later use, what ever you need
}
}
}
Doing this will keep you from having to do the Ajax call you mention, and avoid you have to keep code in more than one place. The service pattern offers a nice central place to keep this data for the lifetime of the application. All you need to do is inject the service into the component, or other services, where it is needed.
Upvotes: 2