访问服务的异步变量
Accessing async variable of service
这是我第一个 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>
twitter.service.ts
中 tweetsData 的类型是什么
getTweetsData():Observable<any>
{
return this.tweetsData;
}
这个函数 return 是可观察的吗?
如果这不是一个 observable ,你可以 return Observable.of(this.tweetsData)
getTweetsData():Observable<any> {
return Observable.of(this.tweetsData) ;
}
第一个问题,如评论中指出的那样,将您的提供程序数组置于组件级别将意味着您拥有单独的服务实例,因此根本不共享。所以删除那些!
你也有竞争条件,就像评论中提到的那样。
我知道您想在 tweetsData
有值时让订阅者收听。您需要做的是为这些订阅者提供 observables 您现在正在做的事情:
getTweetsData():Observable<any> {
return this.tweetsData;
}
returns 一个数组(假设),而不是一个 数组的可观察对象 。您不能订阅 "regular" 数组。
所以我要做的是在服务中声明一个 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
这是我第一个 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>
twitter.service.ts
中 tweetsData 的类型是什么 getTweetsData():Observable<any>
{
return this.tweetsData;
}
这个函数 return 是可观察的吗? 如果这不是一个 observable ,你可以 return Observable.of(this.tweetsData)
getTweetsData():Observable<any> {
return Observable.of(this.tweetsData) ;
}
第一个问题,如评论中指出的那样,将您的提供程序数组置于组件级别将意味着您拥有单独的服务实例,因此根本不共享。所以删除那些!
你也有竞争条件,就像评论中提到的那样。
我知道您想在 tweetsData
有值时让订阅者收听。您需要做的是为这些订阅者提供 observables 您现在正在做的事情:
getTweetsData():Observable<any> {
return this.tweetsData;
}
returns 一个数组(假设),而不是一个 数组的可观察对象 。您不能订阅 "regular" 数组。
所以我要做的是在服务中声明一个 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