Angular 访问服务的异步变量

Angular 访问服务的异步变量,angular,observable,angular2-services,Angular,Observable,Angular2 Services,这是我第一个Angular 4项目的一部分。我目前可以从搜索栏调用searchCall函数,但存储在tweetsData中的数据似乎不在app.component.html中我的*ngFor调用的范围内,也不属于对twitter api的异步后端调用。我得到这个错误:TypeError:无法读取未定义的属性'subscribe',因此我必须没有正确的可观察设置。非常感谢您的帮助 twitter.service.ts import { Injectable } from '@angular/cor

这是我第一个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;
    });
  }

}
从'@angular/core'导入{Injectable};
从'@angular/Http'导入{Http,Headers};
从“rxjs/Observable”导入{Observable};
从'rxjs/Subject'导入{Subject};
@可注射()
导出类推文服务{
searchQuery:string='';
推特数据;
构造函数(专用http:http){
log('TwitterService created');
this.getBealerToken();
}
getBearerToken(){
//从twitter api获取承载令牌
var headers=新的headers();
headers.append('Content-Type','application/x-www-form-urlencoded');
this.http.post('http://localhost:3000/authorize“,{headers:headers}).subscribe((res)=>{
控制台日志(res);
});
}
getTweetsData():可观察{
返回此.tweetsData;
}
searchCall(){
console.log(“发出搜索呼叫”);
console.log(this.searchQuery);
var headers=新的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.status;
});
}
}
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);
  }
}
从'@angular/core'导入{Component,OnInit,TemplateRef};
从'@angular/Http'导入{Http,Headers};
从“/twitter.service”导入{TwitterService};
从“ngx引导/模式”导入{BsModalRef,BsModalService};
@组成部分({
选择器:'应用程序根',
templateUrl:“./app.component.html”,
styleUrls:['自定义样式/app.component.css'],
提供者:[推特服务]
})
导出类AppComponent实现OnInit{
searchQuery:string='';
推特数据;
expandedNewWeetBox:boolean=false;
公共modalRef:BsModalRef;
构造函数(私有http:http,私有twitterService:twitterService,私有modalService:BsModalService){}
恩戈尼尼特(){
此.twitterService.getTweetsData().subscribe(
data=>this.tweetsData=data
)
}
公共OpenModel(模板:TemplateRef){
this.modalRef=this.modalService.show(模板);
}
}
app.component.html

...
<div *ngIf="tweetsData">
  <div *ngFor="let item of tweetsData" class="col-12">
...
<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>
。。。
...
navbar.component.html

...
<div *ngIf="tweetsData">
  <div *ngFor="let item of tweetsData" class="col-12">
...
<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>

走!

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

   getTweetsData():Observable<any> 
    {
    return this.tweetsData;
    } 
getTweetsData():可观察
{
返回此.tweetsData;
} 
这个函数是否返回一个可观察值? 如果这不是一个可观察的,您可以返回observable.of(this.tweetsData)

getTweetsData():可观察{
可观测的返回(本推特数据);
}

第一个问题,正如评论中指出的,将提供者数组放在组件级别将意味着您有单独的服务实例,因此它根本不被共享。所以把这些都拿走

你也有比赛条件,就像在评论中提到的一样

我知道当
tweetsData
有值时,您希望订阅者收听。您需要做的是为这些订阅者提供可观察到的内容您现在正在做的事情:


getTweetsData():可观察的

你永远不会调用
searchCall
@Aluan Haddad我是这样做的。这个调用位于app.component.html的另一部分,我省略了它,因为我测试了对搜索函数的调用,它按预期工作。你不应该假设这样的缓存。您可能有竞争条件或其他原因。很抱歉,对searchCall的调用是在另一个组件“navbar.component”中进行的。我已从该文件中添加了相关代码。希望这有帮助。啊,我明白了问题所在,在组件级别有
提供者:[TwitterService]
,这意味着组件将获得一个单独的服务实例,并具有自己的状态。这通常很好,但您的服务是有状态的,并且希望是单例。不幸的是,
属性对于
Observable
不存在。我对
getWeetsData
的意图是监视变量
tweetsData
,并在对该变量进行更改时通知订阅的组件。我可能是错的,我应该知道这一点,但我相信
tweetsData
在调用
searchCall
后不久将保存一个JSON对象数组(不是立即的,因此是异步的)。在最新版本的RxJS中,我们可以这样导入它:导入“RxJS/add/observable/of”,of({})tweetsData将保存一个JSON对象数组,但它不是可观察的。要观察/观察tweetsData中的更改,必须从函数getTweetsData()返回一个Oservable。您可以使用Obeservable.of或创建行为主体,并使用AJT_82的评论中提到的对象进行观察。这解决了问题!你是最棒的,非常感谢。我必须更改的一件事是
tweetsData$
必须是公共的,这样我才能在
app.component.ts
中引用它。哦,对不起,你完全正确,它必须是
public
!很高兴听到解决方案奏效,祝您周末愉快,编码愉快!:)