Видимые данные на стороне обслуживания изначально не обновляются в компоненте Angular - PullRequest
0 голосов
/ 13 марта 2019

Я новичок в Angular и пытаюсь отобразить асинхронные данные из моего сервиса в моем компоненте. Когда я делаю это, кажется, что данные обновляются, но компонент показывает новые данные только после того, как я нажму кнопку. Мне кажется, DOM не обновляется при изменении данных в моем сервисе, а обновляется только тогда, когда я сообщаю об этом, в этом примере одним нажатием кнопки.

Мой app.component.ts :

import { Component } from '@angular/core';
import { AuthserviceService } from './services/authservice.service';
import { Subscription } from 'rxjs';


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

  displayName: string = 'no displayName available';
  subscription: Subscription;

  constructor(public authService: AuthserviceService){}

  ngOnInit(){
    this.subscription = this.authService.getDisplayName().subscribe(displayName => {this.displayName = displayName})
  }

  ngOnDestroy(){
    this.subscription.unsubscribe();
  }

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

  logout(){
    this.authService.logout();
  }

  methodThatDoesNothing(){

  }
}

Мой app.component.html :

<button (click)="logout()">Logout</button>
<button (click)="login()">Login</button>
<button (click)="methodThatDoesNothing()">button that does nothing</button>
<p>{{ displayName }}</p>
<router-outlet></router-outlet>

My authservice.service.ts :

import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import * as firebase from 'firebase/app';
import { Observable, Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthserviceService {

  private displayName = new Subject<any>();

  constructor(public afAuth: AngularFireAuth) { }

  login() {
    this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()).then(data => {
      this.displayName.next(data.user.displayName);
    });
  }

  logout() {
    this.afAuth.auth.signOut();
  }

  getDisplayName(): Observable<any> {
    return this.displayName.asObservable();
  }

}

Я пытаюсь аутентифицироваться с помощью Google (появляется всплывающее окно, я вхожу, данные предоставляются Google (включая displayName)) Затем я хочу отобразить свое отображаемое имя, которое сохраняется в службе, в моем компоненте. Перед тем, как войти, я вижу следующее:

enter image description here

Когда я нажимаю «Войти», я могу войти, но отображаемое имя не обновляется. Только когда я нажимаю кнопку «кнопка, которая ничего не делает» (или любую другую кнопку), отображаемое имя обновляется:

enter image description here

Мне кажется, что DOM изменяется одним нажатием кнопки, но я не знаю, что на самом деле происходит за кулисами (я не могу найти ответ, в основном потому, что не знаю, что искать для).

  • Что-то не так в моем коде?
  • Я что-то забыл?

Как бы я правильно отобразил displayName после входа в систему?

Заранее спасибо.

EDIT:

Этот фрагмент кода является проблемой, которую я решил, я пока не знаю, почему:

login() {

    this._displayName.next('this data will be shown on the template immediately');

    this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()).then(data => {
      this.displayName.next(data.user.displayName); //This data here does not
    });
  }

Первый «displayname.next» изменяет displayName и сразу меняет значение на csreen.

Второй метод во всплывающем окне не отображается сразу и требует от меня нажатия кнопки (которая вызывает обновление ???), чтобы отобразить отображаемое имя.

Ответы [ 2 ]

1 голос
/ 13 марта 2019

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

private displayName: BehaviorSubject<string> = new BehaviorSubject('no displayName available');

создайте функцию get

get _displayName(){
  return this.displayName
}

подписывайте его в шаблоне с помощью асинхронного канала

<p>{{ authService._displayName | async }}</p>

, когда выхотите передать ему новое значение, просто используйте

_displayName.next('new value') 

или если вне службы

authService._displayName.next('new value')

асинхронный канал будет обрабатывать подписку и отписку для вас.

ТакВы можете удалить подписку на OnInit.Я сделал пример стекаблика, который близок к вашему, чтобы продемонстрировать это

https://stackblitz.com/edit/angular-effvqv

То, как вы это сделали, было немного необычным, потому что

Observable → Subject → BehaviorSubject

так что вы делаете Observable из Observable.

Надеюсь, это помогло.

0 голосов
/ 14 марта 2019

Я «исправил» проблему, заставив ее обнаружить изменение.Сначала я попробовал ChangeDetectorRef , но это только решение при использовании внутри компонента, при использовании службы я использовал решение, упомянутое в этом разделе (которое использует ApplicationRef ):

Триггерное обновление вида компонента из службы - нет поставщика для ChangeDetectorRef

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...