Reputation: 10930
I've read all the Angular documentation and 89 million blog posts and I just get more confused. I have a button in my header for the user to select their preferred language:
<mat-menu>
<button (click)="change_L1_Language('en-US')">English<img width="50" alt="Flag of the United States" src="../assets/images/flags/us-flag.svg"></button>
<button (click)="change_L1_Language('es')">Español<img width="50" alt="Flag of Spain" src="../assets/images/flags/es-flag.svg"></button>
<button (click)="change_L1_Language('zh')">中文<img width="50" alt="Flag of China" src="../assets/images/flags/ch-flag.svg"> 中文</button>
<button (click)="change_L1_Language('jp')">日本人<img width="50" alt="Flag of Japan" src="../assets/images/flags/jp-flag.svg" class="flag-border"> 日本人</button>
</mat-menu>
The button works great, the language in the header changes when the user clicks the button.
The component works fine:
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { L1LanguageService } from '../l1-language.service';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css'],
})
export class HeaderComponent implements OnInit {
public L1_Language: string = 'en-US';
constructor(
private l1LanguageService: L1LanguageService,
) {}
change_L1_Language(language: string) {
this.l1LanguageService.changeL1Language(language);
}
}
I made a service l1-language.service.ts
that receives the data from the button:
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class L1LanguageService {
changeL1Language(language): Observable<any>{
console.log(language);
return of(language)
}
}
The service works too. When I click the button, the new language appears on the console:
es l1-language.service.ts:13
The only bit that I don't understand is what's in the angle brackets: Observable<any>
. Any what?
Now I want to send the data to a component. Here's my component:
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { L1LanguageService } from '../../l1-language.service';
@Component({
selector: 'app-landing-computer',
templateUrl: './landing-computer.component.html',
styleUrls: ['./landing-computer.component.css']
})
export class LandingComputerComponent implements OnInit{
L1_Language: string = 'en-US'; // English is the initial or default language
observeLanguage: Observable<L1LanguageService>; // the service to be observed
constructor(
private l1LanguageService: L1LanguageService,
) {
this.observeLanguage = l1LanguageService.changeL1Language(this.L1_Language) as Observable<L1LanguageService>;
}
ngOnInit() {
this.observeLanguage.subscribe(language => console.log(language)); // does nothing
this.observeLanguage.changeL1Language.subscribe(language => console.log(language)); // "Cannot read property 'subscribe' of undefined"
this.l1LanguageService.subscribe(language => console.log(language)); // "not a function"
this.l1LanguageService.changeL1Language.subscribe(language => console.log(language)); // "not a function"
}
}
This logs the default value en-US
when the app loads, but nothing logs from the component when I click the button.
This looks right to me:
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { L1LanguageService } from '../../l1-language.service';
Nothing wrong with this:
@Component({
selector: 'app-landing-computer',
templateUrl: './landing-computer.component.html',
styleUrls: ['./landing-computer.component.css']
})
The third line I'm not so sure about:
export class LandingComputerComponent implements OnInit{
L1_Language: string = 'en-US'; // English is the initial or default language
observeLanguage: Observable<L1LanguageService>; // the service to be observed
Is the purpose of the third line to create an instance named observeLanguage
of the class Observable
that observes the class L1LanguageService
?
The constructor completely baffles me:
constructor(
private l1LanguageService: L1LanguageService,
) {
this.observeLanguage = l1LanguageService.changeL1Language(this.L1_Language) as Observable<L1LanguageService>;
}
Huh? What's the smelly dumpster fire in the curly brackets?
Every blog post has a different way to subscribe to a service so I put in four, none of which work:
ngOnInit() {
this.observeLanguage.subscribe(language => console.log(language)); // does nothing
this.observeLanguage.changeL1Language.subscribe(language => console.log(language)); // "Cannot read property 'subscribe' of undefined"
this.l1LanguageService.subscribe(language => console.log(language)); // "not a function"
this.l1LanguageService.changeL1Language.subscribe(language => console.log(language)); // "not a function"
}
The first line doesn't throw an error but it doesn't do anything.
The second line throws "Cannot read property 'subscribe' of undefined".
The third and fourth lines throw "not a function".
Why are there some many moving parts to a simple service subscription?
Upvotes: 0
Views: 295
Reputation:
Observable is for any type of data what You wnt observeI haven't seen anyone watching the service yet try this:
This is result:
Upvotes: 0
Reputation: 714
The only bit that I don't understand is what's in the angle brackets: Observable. Any what?
This defines which type is 'returned' in the observable. So basically, in this Observable any value is accepted... To describe explicitly what type is in the observable, you could say Observable, cause your languages are sent as a string.
Code problems
<button (click)="change_L1_Language('en-US')">
==> you're using the method change_L1_Language
which isn't defined in your componentthis.observeLanguage = l1LanguageService.changeL1Language(this.L1_Language) as Observable<L1LanguageService>;
doesn't make any sense... You already have an observable in your service method which you can access via this.l1LanguageService.changeL1Language
this.l1LanguageService.changeL1Language.subscribe(language => console.log(language));
==> This one was very close, but you're subscribing to the definition of your method... you should call your function and subscribe to it (cause it returns an observabel)Something like below code should work for you to console log the set value for language:
ngOnInit() {
this.l1LanguageService.changeL1Language(this.L1_Language).subscribe(language => {
console.log(language)
});
}
UPDATE: BUT above code will only subscribe to the initially set value, because you're subscribing to a method which is called only once...
A complete solution for you would be to extend your L1LanguageService
to something like below code (some untested pseudo code, so check Observable documentation for more info if needed). This way you can subscribe to the L1Language subject and you will be notified on every change of the subject
export class L1LanguageService {
public L1Language : Subject;
changeL1Language(language) : void {
console.log(language);
this.L1Language.next(language);
}
}
In your ngOnInit you can subscribe to the subject like this
this.L1LanguageService.L1Language.subscribe(...)
More info on https://rxjs-dev.firebaseapp.com/guide/subject
Upvotes: 1
Reputation: 8492
This should work for you:
export class LandingComputerComponent implements OnInit{
L1_Language: string = 'en-US'; // English is the initial or default language
constructor(
private l1LanguageService: L1LanguageService
) { }
ngOnInit() {
this.l1LanguageService.changeL1Language(this.L1_Language).subscribe(language => {
console.log(language);
});
}
}
Upvotes: 0