Dawid Zbiński
Dawid Zbiński

Reputation: 5826

Listen to changes on mock-service in Angular 2

I'm building an app where you can change between two languages any time you want. I've got a mock-service that provides me the phrases I use. When the user clicks on language link, the language in mock-service is changed, but I need to somehow listen to the changes when I'm getting the phrases, so service is returning me the updated phrase in Language I want.

LangService.ts:

activeLang :string = 'EN';
getPhrase(phrase :string) :string{
    if(this.activeLang == 'EN'){
      return this.EN[phrase]; 
    } else {
      return this.CZ[phrase];
    }
  }

  changeLanguage(lang :string) :void{
    if(lang == 'EN' || lang == 'CZ'){
      this.activeLang = lang;
    }
  }

Then some OtherComponent.ts:

setPhrase(phrase :string){
    this._langService.getPhrase(phrase);
    // Here I need to subscribe to getPhrase to get the latest updates
    // If I'm right and if it's possible
  }

UPDATE

I made some corrections. LangService now has the Observable that we can listen to, but listener only works for component that triggers the method changeLanguage(). I want to be able to change the language from my NavigationComponent and catch the change in some OtherComponent.

LangService.ts:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class LangService {
private activeLang = 'EN';
private activeLangSubject = new Subject<string>();
activeLang$ = this.activeLangSubject.asObservable();

// Objects EN and CZ with properties, etc.

getPhrases(phrases :Array<string>){
  if(this.activeLang == 'EN'){
    let response = <any>{};
    for(let i = 0; i < phrases.length; i++){
      response[phrases[i]] = this.EN[phrases[i]];
    }
    console.log('refresh');
    return JSON.stringify(response);
  } else {
    let response = <any>{};
    for(let i = 0; i < phrases.length; i++){
      response[phrases[i]] = this.CZ[phrases[i]];
    }
    return JSON.stringify(response);
  }
}

changeLanguage(lang :string){
  if(lang == 'EN' || lang == 'CZ'){
    this.activeLang = lang;
    this.activeLangSubject.next(lang);
  }
}

NavComponent.ts:

import { Component, OnInit } from '@angular/core';
import { LangService } from '../lang.service';

@Component({
  moduleId: module.id,
  selector: 'app-nav',
  templateUrl: 'nav.component.html',
  styleUrls: ['nav.component.css'],
  providers: [LangService]
})
export class NavComponent implements OnInit {
  langs :Array<string> = ['EN', 'CZ'];

  constructor(
    private _langService :LangService) {
  }

  changeLanguage(lang :string) :void{
    this._langService.changeLanguage(lang);
  }
}

with NavComponent.html:

<li *ngFor="let lang of langs">
  <a (click)="changeLanguage(lang)">{{ lang }}</a>
</li>

OtherComponent.ts:

import { Component, OnInit } from '@angular/core';
import { LangService } from '../lang.service';
import { NavComponent } from '../nav/nav.component';

@Component({
  moduleId: module.id,
  selector: 'all-notes',
  templateUrl: 'notes.component.html',
  providers: [NoteService, LangService],
  directives: [NavComponent]
})
export class NotesComponent implements OnInit {

  mode = 'Observable';

  postPhrases :Array<string> = [
    "alertTitle", "alertText", "options", "detailsBtn","editBtn","deleteBtn", 
    "addBtn", "serverResp", "actionMessage", "responseMessage", "note"
  ];

  getPhrases :Object;

  constructor(
    private _langService :LangService) {
  }

  ngOnInit() {
    this.updatePhrases(this.postPhrases);

    // This one doesn't work 
    this._langService.activeLang$.subscribe(
      success => this.updatePhrases(this.postPhrases),
      error => console.log(error),
      () => console.log('complete')
    );
  }

  updatePhrases(phrases :Array<string>) :void {
    this.getPhrases = JSON.parse(this._langService.getPhrases(phrases));
  }

}

My question now is how can I listen for the changes on OtherComponent, so I can use method updatePhrases() to update phrases.

Upvotes: 0

Views: 218

Answers (2)

Dawid Zbiński
Dawid Zbiński

Reputation: 5826

So basically the whole thing I needed was to create a service LangService with 3 variables.

activeLang: string 'EN';
activeLangSubject: Subject<string> = new Subject<string>();
activeLangObservable: Observable<string> = this.activeLangSubject.asObservable();
  1. activeLang - variable for comparing the languages,
  2. activeLangSubject - variable for creating an Observable,
  3. activeLangSubject - variable that we can subscribe to

After that, I needed to add the LangService to the right scope. I wanted that to be global, so I put it as a provider to bootstrap method in main.ts file.

bootstrap(AppComponent, [LangService]);

Of course I needed to import it before providing it to bootstrap.

After providing it in bootstrap all I needed to do was:

  • Import it to every component that needed to listen to the changes,
  • NOT to provide it there as we have global instace of it and we don't want to create other,
  • Inject it in constructor constructor(private _langService: LangService) {},
  • Subscribe to it

    ngOnInit() { this._langService.langServiceObservable.subscribe( response => console.log('Changed! Active Language: ' + response), error => console.log('Error! Description: ' + error) ); }

In case you don't use ngOnInit() you can also subscribe to changes inside constructor()

Upvotes: 0

Philippe Plantier
Philippe Plantier

Reputation: 8073

This sounds like something you would use a pipe for:

import { Pipe, PipeTransform, Injectable } from '@angular/core'

@Injectable()
@Pipe({ name: 'myTranslatePipe' })
export class IndicatorHeadersPipe implements PipeTransform {
  public transform(
    phrase: string,
    activeLang: string
  ) {
    if(activeLang == 'EN'){
      return this.EN[phrase]; 
    } else {
      return this.CZ[phrase];
    }
  }
}

Do not forget to add the pipe to your NgModule declarations

And then, in your component

@Component({
  selector: 'my-selector',
  template: `
    <div>{{ 'My text' | myTranslatePipe : activeLang }}</div>
  `,
})
export class PageIndicatorComponent {
  private activeLang: string

  changeLanguage(lang :string) :void{
    if(lang == 'EN' || lang == 'CZ'){
      this.activeLang = lang;
    }
  }
}

However, I would recommend just using a translation module, like ng2-translate

Upvotes: 1

Related Questions