1

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:

  1. Make Ajax calls in ngOnInit of each component that requires these constants
  2. Make a static model to hold these values

Option 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.

3 Answers 3

2

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

Sign up to request clarification or add additional context in comments.

Comments

2

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.

3 Comments

So, if this service class is used in more than one component, only one cal will be made to the server to get the constants and the results cached in a variable? If that is the case, it is a good solution
I think i found a problem with your code, the component code executes before the service ajax call is completed, because you subscribe in your service, so the first time the call is made to the server the component will not get any values. Thereafter, everything is fine as no call is made to the server. I am trying to figure out how to subscribe in the component and update the service variable.
Maybe add the call to the service in the AppComponent (or whatever component you bootstrap the app with) so this call happens right when the application is starting rather than when a component is initialized.
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.