【问题标题】:Angular2 Observable not get called if there is access to result attribute如果可以访问结果属性,则不会调用 Angular2 Observable
【发布时间】:2017-03-31 16:33:38
【问题描述】:

我有一个这样的 HTTP 服务来检索用户列表:

@Injectable()
export class UserService {
    private _dataStore: {
         users: User[]
    };
    private _users: BehaviorSubject<User[]> = new BehaviorSubject<User[]>();
    public usersObservable: Observable<User[]> = this._users.asObservable();

    ...

    public list(): void {
    this
        .http
        .get('/users')
        .subscribe((res) => {
            this._dataStore.users = res.json() as User[];
            this._users.next(Object.assign({}, this._dataStore).users);
        });
    }
}

然后在我的组件中:

export class UsersComponent {
    public users: User[] = [];
    private usersObservable: Observable<User[]>;

    constructor(private userService: UserService) {
        this.usersObservable = this.userService.usersObservable;
    }

    public listUsers(): void {
        this.usersObservable.subscribe(data => {
            this.users = data;
            console.log(this.users.length); // <- this line cause the mysterious bug, 
            // a replace with console.log(this.users) makes the app works correctly
        }));
        this.userService.list();
    }
}

而这个组件的视图只是一个表格,其中的行如下

<tr *ngFor='let user of users'>
........ <!-- Display data here -->
</tr>

问题是,如果我调用任何访问 data 或 this.users 属性的函数,observable 将不会被调用。如果我只是 console.log(this.users) 或 console.log(data),一切都很好。

你知道问题出在哪里吗? 提前谢谢你。

【问题讨论】:

    标签: angular observable


    【解决方案1】:

    您执行了 2 个异步操作,但您将它们混合在一起。

    首先您订阅usersObservable,它最初只是一个BehaviorSubject,没有任何价值。

    然后你调用 async list() 方法来填充你的 Subject 以便你的 observable 可以有值。

    在你的 observable 接收它的值之前,你试图显示它没有的值的长度。

    【讨论】:

      【解决方案2】:

      echonax 是对的,不知道为什么有人反对它。

      澄清一点:当你设置BehaviorSubject 时,你必须设置一个默认值,一旦有人订阅它就会产生。 如果您查看您的代码,您会在发送调用 (this.userService.list();) 之前订阅主题 (this.usersObservable.subscribe(...),因此 BehaviorSubject 不可能包含您想要的值。如果您将 BehaviorSubject 替换为 ReplaySubject,它可能会解决您的问题。

      现在您提到的“错误”是此问题和调试器性质的副作用。当你console.log(this.users.length) 时,控制台只打印一个数字作为结果,即 0。当this.users 被填充时,调试器上的这个数字不会改变,因为它只是一个数字。 但是,console.log(this.users) 打印了对该对象的引用,因此可以对其进行探索(那些小箭头可以查看内容),因此当它被填充后,您可以立即在调试器中看到这些更改。 尝试console.log(JSON.stringify(this.users)),你会看到它在记录对象时将是一个空数组(因为它是一个字符串,当对象更新时它不会更新)

      另外,避免使用主题。 publish()ing 源代码可能会改进您的解决方案。查看这篇文章以获得更多信息:http://davesexton.com/blog/post/To-Use-Subject-Or-Not-To-Use-Subject.aspx

      【讨论】:

      • 谢谢,反对者是一个“讨厌”反对者。如果你查看我的活动,我在同一分钟内被否决了 10 次,哈哈。
      • @echonax 非常感谢。我花了一些时间来理解 echonax 的答案(结构很好),但是当事情到达时,我发现你确实解释了问题出在哪里。
      • @olivarra1 谢谢你非常详细的解释。
      猜你喜欢
      • 2018-04-07
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 2015-08-11
      • 2023-02-17
      • 2017-04-17
      • 2014-02-15
      相关资源
      最近更新 更多