【问题标题】:Angular 4 UI not updating from observable subscriptionAngular 4 UI 未从可观察订阅更新
【发布时间】:2017-10-31 02:33:25
【问题描述】:

我在我的应用程序组件中订阅的服务中有一个 observable。数据正在通过订阅传递,没有问题,但由于某种原因,我无法让 UI 使用新信息进行更新。我知道数据正在到达那里,因为它正在记录到控制台。

这是我的 app.component 代码:

import {Component, OnDestroy, OnInit} from '@angular/core';
import {UserDetailsService} from './services/user-details.service';
import {User} from './shared/models/user';
import {Subscription} from 'rxjs/Subscription';

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

  title = 'the Portfolio';
  user: User;
  userSub: Subscription;

  constructor(public userDetails: UserDetailsService) {
  }

  ngOnInit(): void {
    this.userSub = this.userDetails.user$.subscribe(user => {
      this.user = user;
      console.log(user);
    });
  }

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

我更新 observable 的用户登录组件:

import {Component, AfterViewInit, NgZone} from '@angular/core';
import {UserDetailsService} from '../services/user-details.service';
import {User} from '../shared/models/user';

declare const gapi: any;

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

export class UserLoginComponent implements AfterViewInit {

  constructor(private _zone: NgZone, private userDetails: UserDetailsService) {
    console.log(this);
  }

  ngAfterViewInit() {
    gapi.load('auth2', () => {
      const auth = gapi.auth2.init({
        'clientId': 'YOURID.apps.googleusercontent.com'
      });

      auth.attachClickHandler('google-login-button', {},
        (googleUser) => {
          const profile = googleUser.getBasicProfile();
          // console.log('Token || ' + googleUser.getAuthResponse().id_token);
          // console.log('ID: ' + profile.getId());
          // console.log('Name: ' + profile.getName());
          // console.log('Image URL: ' + profile.getImageUrl());
          // console.log('Email: ' + profile.getEmail());

          this.userDetails.setLoginUser(new User({
            id: profile.getId(),
            name: profile.getName(),
            email: profile.getEmail()
          }));
        },
        (error) => {
          alert(JSON.stringify(error, undefined, 2));
        });
    });
  }
}

用户详情服务:

import {Injectable, OnInit} from '@angular/core';
import {User} from '../shared/models/user';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import 'rxjs/add/operator/map';

@Injectable()
export class UserDetailsService implements OnInit {

  private userSubject = new BehaviorSubject<User>(new User());
  user$ = this.userSubject.asObservable();

  constructor() {
  }

  ngOnInit(): void {
  }

  public setLoginUser(user: User) {
    this.userSubject.next(user);
  }
}

这是我的 UI 代码:

<div *ngIf="user" class="alert alert-success">{{user.name}}</div>
{{user.name}}

我错过了什么?卡在这上面已经一天多了。

任何帮助表示赞赏,在此先感谢。

【问题讨论】:

  • 控制台中有任何消息以及日志吗?
  • 我不完全确定,因为我只是从 angular 2/4 开始,但您不会错过 async 管道吗? *ngIf="user | async"
  • @jonrsharpe 控制台没有错误,只是标准的 XHR 完成消息
  • @maurycy 只有当他们将 observable 直接暴露给组件时才会如此。 user: User; 在这里,而不是 user: Observable&lt;User&gt;;
  • @maurycy 据我所知,如果我没有手动订阅代码,则需要 async 关键字。但我试过 {{(userDetails.user$).name | async}} 并且它仍然没有更新 ui

标签: angular angular2-services


【解决方案1】:

发现问题。当我使用 setLoginUser 函数更新服务时,我这样做了:

this.userDetails.setLoginUser(new User({
              id: profile.getId(),
              name: profile.getName(),
              email: profile.getEmail()
            }));

我需要这样做:

this._zone.run(() =>{
            this.userDetails.setLoginUser(new User({
              id: profile.getId(),
              name: profile.getName(),
              email: profile.getEmail()
            }));
          });

现在这两种方法都起作用了:

<div *ngIf="user" class="alert alert-success">{{user.name}}</div>
{{(userDetails.user$ | async).name}}

感谢你们的帮助!

【讨论】:

  • 请注意,此代码甚至没有出现在您的问题中,并且没有说明为什么会导致此问题以及如何更改修复它;这使得它不太可能对其他人有用。很高兴您解决了问题,但您可能应该删除问题。
  • @jonrsharpe 我认为这不是问题,因为数据正在进入应用程序组件。它只是没有更新 UI。
  • this.userDetails.setLoginUser still 仅出现在答案中。完全不清楚为什么需要将其包装在显式 zone.run 中。
  • @bryan60 非常有建设性的评论,您没有给出任何解释或解决方案。实际上你错了,因为 gapi.js 在导入库时默认暴露在窗口范围内,并且是 Google 的每个文档中使用它的方式。将库作为外部库导入也不是一个坏习惯,并且受到 ng-cli(由 Google)支持。最后,在这种情况下,使用 ngZone 手动触发更改检测是正确的解决方案。
  • 如果您想了解为什么 Zone 在默认情况下未检测到更改,您可以查看 this article
【解决方案2】:

我不确定您是否需要运行该区域,因为在我的应用程序中类似的情况下我不需要。我在服务中使用 getter 和 setter 方法。你能在这里看看吗https://github.com/JanneHarju/MultiSourcePlayList/blob/master/angular2App/app/services/playlist.service.ts getPlaylistsModified() 函数。

【讨论】:

  • 感谢@Janne,但我认为这与我正在使用的 Google 身份验证库有关。正如我所说,服务正在获取数据,只是 UI 没有更新。
猜你喜欢
  • 2016-09-19
  • 2018-02-03
  • 1970-01-01
  • 1970-01-01
  • 2017-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多