Потратили весь день и больше, пытаясь заставить Angular Observable работать

#angular #rxjs

#angular #rxjs

Вопрос:

Помогите! Я потратил весь день и большую часть вчерашнего дня, пытаясь заставить observable работать в моем приложении Angular. У меня есть компонент, который используется для изменения пользовательских настроек / config для приложения, и я хочу иметь возможность уведомлять другие компоненты при изменении настроек. Чем больше я читаю, тем больше запутываюсь. Вот мои настройки-контейнерный код:

 import { Component, OnInit, Input } from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import { Observable } from 'rxjs';
import { MatSelectModule, SELECT_ITEM_HEIGHT_EM } from     '@angular/material/select';


import { AppSettings } from '../../shared/app-settings'
import { AppSettingsService } from '../../services/app-settings.service';
import { APPSETTINGS } from '../../shared/defaultSettings';
import { ThemeService } from '../../services/theme.service';
import { LogService } from 'src/app/services/app-log.service';

@Component({
  selector: 'app-settings-container',
  templateUrl: './settings-container.component.html',
  styleUrls: ['./settings-container.component.scss']
})
export class SettingsContainerComponent implements OnInit {
  className: string;

  settings: AppSettings;

  @Input()
  defaultSettings = APPSETTINGS;

  themes = [
    { value: 'DEFAULT-THEME', label: 'blue' },
    { value: 'LIGHT-THEME', label: 'light' },
    { value: 'NATURE-THEME', label: 'nature' },
    { value: 'BLACK-THEME', label: 'dark' }
  ];

  wings = [
        { value: 'ALWG', label: 'Alabama Wing' },
        { value: 'WYWG', label: 'Wyoming Wing' },
  ];

  @Input()
  title: string;

  constructor(private appSettingsService: AppSettingsService,
              private logger: LogService,
              private themeService: ThemeService) { }

  ngOnInit() {  
    this.className = this.constructor.toString().match(/w /g)[1];
    this.settings = this.appSettingsService.getSettings();
  }

  saveSettings( event ) {
    this.logger.debug(this.className, 'saveSettings, settings:', this.settings);
    this.appSettingsService.saveSettings(this.settings);

  }

}
  

Все это работает нормально, и все мои обратные вызовы (удаленные для краткости) работают нормально. Служба настроек короткая и приятная, как показано ниже:

 import { Input } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { BehaviorSubject } from 'rxjs';
import { AppSettings } from '../shared/app-settings';
import { APPSETTINGS } from "../shared/defaultSettings";
import { Inject, Injectable } from '@angular/core';
import { LOCAL_STORAGE, StorageService } from 'angular-webstorage-service';
import { LogService } from 'src/app/services/app-log.service';


@Injectable()
export class AppSettingsService {

  @Input()
  defaultSettings = APPSETTINGS;
  settings: Observable<AppSettings>;
  newSettings: AppSettings;
    // Use of BehavioirSubject. This is where you post values into
    private _settings$: BehaviorSubject<AppSettings> = new     BehaviorSubject(APPSETTINGS)
    // Settings observer. This is where you read from outside
    settings$: Observable<AppSettings> = this._settings$.asObservable();

    constructor(private logger: LogService,
                @Inject(LOCAL_STORAGE) private storage: StorageService) {
       this.newSettings = this.storage.get('TRACS3_SETTINGS');

       if ( this.newSettings !== null ) {
           this._settings$.next(this.newSettings);
       } else {
               this.storage.set('TRACS3_SETTINGS', APPSETTINGS);
           this.newSettings = this.storage.get( 'TRACS3_SETTINGS');
           console.log('about to change observable');
           this._settings$.next( this.newSettings );
           console.log('just changed observabe to ', this.newSettings);
       }
    }
    public saveSettings(settings: AppSettings): void{
      console.log('saving settings in service');
      //this._settings$.post(settings)
      this._settings$.next(settings);
      this.storage.set('TRACS3_SETTINGS', settings);
    }


  public getSettings(): Observable<AppSettings> {
    return this.storage.get('TRACS3_SETTINGS');
  }

}
  

Настройки должным образом сохранены в локальном хранилище и считываются при запуске, как и должны. Однако чего я пытаюсь добиться, так это уведомления моего app.component при изменении настроек (заголовок панели навигации — одна из настроек). Но я бился головой о стену, пытаясь понять, как это сделать. Вот мое приложение.код компонента:

 import { Component, OnInit } from '@angular/core';
import { MatIconRegistry } from "@angular/material/icon";
import { DomSanitizer } from "@angular/platform-browser";
import { Inject } from '@angular/core';
import { Observable } from 'rxjs';
import { AdalService } from 'adal-angular4';
import { environment } from '../environments/environment';

import { AppSettings } from './shared/app-settings'
import { AppSettingsService } from './services/app-settings.service';
import { APPSETTINGS } from './shared/defaultSettings';
import { LogService } from 'src/app/services/app-log.service';

import {LOCAL_STORAGE, WebStorageService} from 'angular-webstorage-service';

import { Aircraft } from "./shared/aircraft";
import { Content } from '@angular/compiler/src/render3/r3_ast';
import {TitleService } from './services/title.service';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent implements OnInit{
  className: string;
  aircraft: Aircraft[];
  isAuthenticated$:         Observable<boolean>;
  settings$: Observable<AppSettings>;
  newSettings: AppSettings;
  defaultSettings: AppSettings;



  constructor(
    private titleService: TitleService,
    public appSettingsService: AppSettingsService,
    private matIconRegistry: MatIconRegistry,
    private domSanitizer: DomSanitizer,
    private adalService: AdalService,      
    private logger: LogService,
    @Inject(LOCAL_STORAGE) private storage: WebStorageService
    ){
    this.settings$ = this.appSettingsService.getSettings();
    console.log('settings$: ', this.settings$);
    adalService.init(environment.config);

    this.matIconRegistry.addSvgIcon(
      "historical-tracking-black-48",
      this.domSanitizer.bypassSecurityTrustResourceUrl("../assets/historical-    tracking-black-48.svg")
);
    this.matIconRegistry.addSvgIcon(
      "historical-tracking-black-48-inactive",
      this.domSanitizer.bypassSecurityTrustResourceUrl("../assets/historical-tracking-black-48-inactive.svg")
    );
    //this.appSettingsService.getSettings().subscribe(newSettings =>     this.settings = newSettings);
  } 

  ngOnInit(){
    this.className = this.constructor.toString().match(/w /g)[1];

    this.adalService.handleWindowCallback();
    this.logger.debug(this.className, "adal userInfo: ",     this.adalService.userInfo);

        this.settings$ = new Observable(observer => {
          console.log('in observer');
        })

    let subscription = this.settings$.subscribe(
      newSettings => console.log('NewSettigns: ',newSettings),      
    )
    this.logger.log(this.className, "Settings at startup: ", this.settings);

    this.appSettingsService.getSettings().subscribe((newSettings) => {
      console.log('settings have changed, new settings are:', newSettings);
    })
  }

  login() {
    this.adalService.login();
  }

  logout() {
    this.adalService.logOut();
  }

  get authenticated(): boolean {
    return this.adalService.userInfo.authenticated;
  }

}
  

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

Спасибо….

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

1.Из документации, я думаю, this.storage.get('TRACS3_SETTINGS') не возвращается observable . Скорее его any npmjs.com/package/angular-webstorage-service#api . Проверьте .get() на npmjs.com/package/angular-webstorage-service#usage .Попробуйте то, что предложил @BizzyBob, и дайте мне знать

Ответ №1:

Вы очень близки! Ваша проблема в том, что вы фактически не подписываетесь на observable из AppSettingsService.

Раскомментируйте эту строку:

 \this.appSettingsService.getSettings().subscribe(newSettings => this.settings = newSettings);
  

но измените его на:

 this.appSettingsService.settings$.subscribe(newSettings => this.settings = newSettings);
  

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

1. Когда я вношу это изменение, я получаю следующую ошибку из this.settings $=newSettings: Тип ‘AppSettings’ не может быть присвоен типу ‘Observable<AppSettings>’.ts(2322) В типе ‘AppSettings’ отсутствуют следующие свойства из типа ‘Observable<AppSettings>’: _isScalar, source, operator, lift и еще 6.ts(2740)

2. В вашем компоненте приложения измените свое объявление settings$ на settings$: AppSettings; , поскольку оно не является observable . Вы также можете захотеть переименовать без $ .