访问服务的异步变量

时间:2017-11-01 23:13:50

标签: angular observable angular2-services

这是我第一个Angular 4项目的一部分。我目前能够从搜索栏中调用searchCall函数,但是存储在tweetsData中的数据似乎与app.component.html中的* ngFor调用无关,并且是一个异步后端调用twitter api。我收到此错误:TypeError:无法读取属性' subscribe'未定义的,所以我必须没有正确的可观察设置。非常感谢任何帮助。

twitter.service.ts

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class TwitterService {
  searchQuery: string = '';
  tweetsData;

  constructor(private http: Http) {
    console.log('TwitterService created');
    this.getBearerToken();
  }

  getBearerToken() {
    // get bearer token from twitter api
    var headers = new Headers();

    headers.append('Content-Type', 'application/x-www-form-urlencoded');

    this.http.post('http://localhost:3000/authorize', {headers: headers}).subscribe((res) => {
      console.log(res);
    });
  }

  getTweetsData():Observable<any> {
    return this.tweetsData;
  }

  searchCall() {
    console.log('searchCall made');
    console.log(this.searchQuery);
    var headers = new Headers();
    var searchTerm = 'query=' + this.searchQuery;

    headers.append('Content-Type', 'application/x-www-form-urlencoded');

    this.http.post('http://localhost:3000/search', searchTerm, {headers: headers}).subscribe((res) => {
      this.tweetsData = res.json().data.statuses;
    });
  }

}

app.component.ts

import { Component, OnInit, TemplateRef } from '@angular/core';
import { Http, Headers } from '@angular/http';

import { TwitterService } from './twitter.service';
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: [ 'custom-styles/app.component.css' ],
  providers: [TwitterService]
})
export class AppComponent implements OnInit {
  searchQuery: string = '';
  tweetsData;
  expandedNewTweetBox: boolean = false;

  public modalRef: BsModalRef;

  constructor(private http: Http, private twitterService: TwitterService, private modalService: BsModalService) {}

  ngOnInit() {
    this.twitterService.getTweetsData().subscribe(
      data => this.tweetsData = data
    )
  }

  public openModal(template: TemplateRef<any>) {
    this.modalRef = this.modalService.show(template);
  }
}

app.component.html

...
<div *ngIf="tweetsData">
  <div *ngFor="let item of tweetsData" class="col-12">
...

navbar.component.html

<div class="input-group">
   <input type="text" class="form-control" placeholder="Search Chiller" aria-label="Search Chiller" [(ngModel)]="twitterService.searchQuery" [ngModelOptions]="{standalone: true}">
   <span class="input-group-btn">
      <button class="btn btn-secondary" type="button" (click)="twitterService.searchCall()">Go!</button>
   </span>
</div>

2 个答案:

答案 0 :(得分:1)

第一个问题,就像在评论中指出的那样,将您的提供者数组放在组件级别意味着您有单独的服务实例,因此它根本不共享。所以删除那些!

你也有竞争条件,比如评论中也提到过。

我知道您希望订阅者在tweetsData具有值时收听。您需要做的是为这些订阅者提供 observables 您现在正在做的事情:

getTweetsData():Observable<any> {
  return this.tweetsData;
}

返回一个数组(假设),而不是可观察数组。您无法订阅&#34;常规&#34;阵列。

所以我要做的是在服务中声明一个Observable:

import { BehaviorSubject } from 'rxjs/BehaviorSubject';

// don't use 'any', type your data instead
// you can also use a 'Subject' if the subscribers are always listening
private tweetsData = new BehaviorSubject<any>(null);
public tweetsData$ = this.tweetsData.asObservable();

然后,当您获得数据时,请致电next()

searchCall() {
  // ....
  this.http.post(...)
    .subscribe((res) => {
      this.tweetsData.next(res.json().data.statuses)
    });
}

然后你让你的订阅者听这个观察,比如:

constructor(private twitterService: TwitterService) {
  twitterService.tweetsData$
    .subscribe(data => {
       this.tweetsData = data;
    });
}

应该这样做。进一步阅读文档:https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service

答案 1 :(得分:-1)

twitter.service.ts中tweetsData的类型是什么

   getTweetsData():Observable<any> 
    {
    return this.tweetsData;
    } 

这个函数是否返回了一个可观察的? 如果这不是一个可观察的,你可以返回Observable.of(this.tweetsData)

 getTweetsData():Observable<any> {
    return Observable.of(this.tweetsData) ;
    }