Angular: как подписаться на компонент для службы данных?

#angular

#angular

Вопрос:

Я прочитал всю документацию Angular и 89 миллионов сообщений в блогах, и я просто еще больше запутался. У меня в заголовке есть кнопка, позволяющая пользователю выбрать предпочитаемый язык:

   <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">amp;nbsp; 中文</button>
    <button (click)="change_L1_Language('jp')">日本人<img width="50" alt="Flag of Japan" src="../assets/images/flags/jp-flag.svg" class="flag-border">amp;nbsp; 日本人</button>
  </mat-menu>
  

Кнопка отлично работает, язык в заголовке меняется, когда пользователь нажимает на кнопку.

Компонент работает нормально:

 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);
  }
}
  

Я создал службу l1-language.service.ts , которая получает данные от кнопки:

 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)
  }
}
  

Служба тоже работает. Когда я нажимаю кнопку, на консоли появляется новый язык:

 es                     l1-language.service.ts:13
  

Единственное, что я не понимаю, это то, что находится в угловых скобках : Observable<any> . Что-нибудь?

Теперь я хочу отправить данные компоненту. Вот мой компонент:

 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"
  }
}

  

При загрузке приложения регистрируется значение по умолчанию en-US , но при нажатии кнопки из компонента ничего не регистрируется.

Это выглядит правильно для меня:

 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
  

Является ли целью третьей строки создание экземпляра с именем observeLanguage класса Observable , который наблюдает за классом L1LanguageService ?

Конструктор полностью сбивает меня с толку:

  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"
  }
  

Первая строка не выдает ошибку, но и ничего не делает.

Вторая строка выдает «Не удается прочитать свойство ‘subscribe’ неопределенного».

Третья и четвертая строки выдают «не функция».

Почему в простой подписке на службу так много движущихся частей?

Ответ №1:

Единственное, что я не понимаю, это то, что находится в угловых скобках: наблюдаемый. Что-нибудь?

Это определяет, какой тип «возвращается» в наблюдаемом. Итак, в принципе, в этом наблюдаемом принимается любое значение… Чтобы явно описать, какой тип находится в наблюдаемом, вы могли бы сказать Наблюдаемый, потому что ваши языки отправляются в виде строки.

Проблемы с кодом

  1. <button (click)="change_L1_Language('en-US')"> ==> вы используете метод change_L1_Language , который не определен в вашем компоненте
  2. this.observeLanguage = l1LanguageService.changeL1Language(this.L1_Language) as Observable<L1LanguageService>; не имеет никакого смысла… У вас уже есть наблюдаемый в вашем методе обслуживания, к которому вы можете получить доступ через this.l1LanguageService.changeL1Language
  3. this.l1LanguageService.changeL1Language.subscribe(language => console.log(language)); ==> Это было очень близко, но вы подписываетесь на определение вашего метода… вы должны вызвать свою функцию и подписаться на нее (потому что она возвращает observabel)

Что-то вроде приведенного ниже кода должно сработать для того, чтобы консоль регистрировала установленное значение для language:

 ngOnInit() {
    this.l1LanguageService.changeL1Language(this.L1_Language).subscribe(language => {
        console.log(language)
    });
}
  

Обновить:
НО приведенный выше код будет подписываться только на первоначально установленное значение, потому что вы подписываетесь на метод, который вызывается только один раз…

Полным решением для вас было бы расширить ваш L1LanguageService код на что-то вроде приведенного ниже кода (некоторый непроверенный псевдокод, поэтому при необходимости проверьте документацию Observable для получения дополнительной информации). Таким образом, вы можете подписаться на тему L1Language, и вы будете получать уведомления о каждом изменении темы

 export class L1LanguageService {
  public L1Language : Subject;
  
  changeL1Language(language) : void {
    console.log(language);
    this.L1Language.next(language);
  }
}
  

В вашем ngOnInit вы можете подписаться на тему следующим образом
this.L1LanguageService.L1Language.subscribe(...)

Подробнее о https://rxjs-dev.firebaseapp.com/guide/subject

Комментарии:

1. «1.» Извините, я не указал компонент, который отправляет данные в службу. Я просто вставил его.

2. Нет, ваше предложение не сработало. Нет сообщения об ошибке, но когда я нажимаю кнопку, ничего не регистрируется.

Ответ №2:

Это должно сработать для вас:

 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);
    });
  }
}
  

Комментарии:

1. Ваше предложение не сработало. Нет сообщения об ошибке, но когда я нажимаю кнопку, ничего не регистрируется. Я опубликую обновленный код ниже.

Ответ №3:

Наблюдаемый — это для любого типа данных то, что вы не наблюдаете Я еще не видел, чтобы кто-нибудь смотрел службу, попробуйте это:

введите описание изображения здесь

Это результат:

введите описание изображения здесь