我的服务
search (packageName: string, refresh = false): Observable<PackageInfo>
{
const options = createHttpOptions(packageName, refresh);
this.searchResults = this.http.get(searchUrl + packageName, options) as Observable<PackageInfo>;
return this.searchResults
}
我能做
this.searchResults.subscribe(repoUrl => console.log(repoUrl.repos_url))
这将显示“我的观察”中的URL。我需要保存repos_url,以便可以进行第二个http.get调用。我不确定该怎么做。我的想法是将订阅保存到哪里,但是在console.log中返回未定义。这意味着从我读取的内容中什么都没有返回,因为值只有在Observable处于活动状态时才存在。我现在被困住了。我可以使用“个人档案”搜索组件和“回购列表”组件,但是我需要“个人档案”组件将回购网址传递给“回购列表”组件。
profile-search.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, BehaviorSubject } from 'rxjs';
import { HttpErrorHandler, HandleError } from '../error-handler.service';
export interface PackageInfo {
login: string
name: string
avatar_url: string
repos_url: string
}
export const searchUrl = 'https://api.github.com/users/';
const httpOptions = {
headers: new HttpHeaders({
'x-refresh': 'true'
})
};
function createHttpOptions(packageName: string, refresh = false) {
const headerMap = refresh ? {'x-refresh': 'true'} : {};
const headers = new HttpHeaders(headerMap) ;
return { headers };
}
@Injectable({
providedIn: 'root'
})
export class PackageSearchService {
searchResults: Observable<PackageInfo>;
private handleError: HandleError;
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler
) {
this.handleError = httpErrorHandler.createHandleError('Service');
}
search (packageName: string, refresh = false): Observable<PackageInfo>
{
const options = createHttpOptions(packageName, refresh);
this.searchResults = this.http.get(searchUrl + packageName, options) as Observable<PackageInfo>;
return this.searchResults
}
}
我的第一个想法是创建一个字符串类型的空白变量。
export class PackageSearchService {
searchResults: Observable<PackageInfo>;
private handleError: HandleError;
repoUrl: string; <== new
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler
) {
this.handleError = httpErrorHandler.createHandleError('Service');
}
search (packageName: string, refresh = false): Observable<PackageInfo>
{
const options = createHttpOptions(packageName, refresh);
this.searchResults = this.http.get(searchUrl + packageName, options) as Observable<PackageInfo>;
this.repoUrl = this.searchResults.subscribe(userRepo => userRepo.repo_url)
return this.searchResults
}
repo-list.component.ts
import { Component, OnInit } from '@angular/core';
import { RepoListComponent } from './repo-list.services';
import { PackageSearchService } from '../profile-search/profile-search.service';
import { RepoList } from '../repoList';
import { Observable, Subscription } from 'rxjs';
@Component({
selector: 'repo-list',
templateUrl: './repo-list.html',
styleUrls: ['../profile-search/profile-search.component.css']
})
export class UsersRepoComponent implements OnInit {
repo: RepoList[] = [];
constructor( private repoService : RepoListComponent,
private searchService: PackageSearchService){}
ngOnInit(){
this.getRepoList();
}
getRepoList(): void {
this.repoService.getRepoReturn()
.subscribe(repo => this.repo = repo);
}
getRepoUrl(){
this.searchService.repoUrl;
}
}
答案 0 :(得分:0)
您可以在服务类中定义具有URL的构造函数,该URL可以进一步使用。下面是代码段
repoUrl:string
constructor(private httpClient:HttpClient) {
this.repoUrl ="http://localhost:3990/"
}
getProjects(packageName:string):Observable<Project[]>{
return this.httpClient.get(this.repoUrl+packageName)
}
答案 1 :(得分:0)
您的代码没有多大意义:
string
的变量,但是subscribe()
返回的是Subscription,而不是字符串。之所以使用Observable,是因为http调用是异步,因此您无法期望在调用httpClient.get()
之后立即获得结果。只有在响应可用时,它才会稍后可用,然后可观察对象将其结果通知给其订户。searchService.repoUrl
字段,而无需调用初始化该字段的方法。要链接返回Observable的异步调用,最简单的方法是使用switchMap()
运算符:
getRepoUrl().pipe(
switchMap(url => getSomethingUsingTheUrl(url))
).subscribe(something => doWhateverYouWant(something));
这样做的缺点是,每个要加载内容的主题都将首先发出请求以获取存储库URL,然后发出第二个请求以获取内容。
您只能获取一次URL,并使用shareReplay
运算符使用单个可观察到的URL对其进行缓存:
class UrlService {
url$: Observable<string>;
constructor(httpClient: HttpClient) {
this.url$ = httpClient.get(...).pipe(shareReplay());
}
}
以及您的组件中
this.urlService.url$.pipe(
switchMap(url => getSomethingUsingTheUrl(url))
).subscribe(something => doWhateverYouWant(something));
可观察性很难掌握,但是如果您想正确有效地使用Angular,您肯定需要花一些时间来学习它们。第一步是了解异步性,这是为什么首先出现可观察对象的主要内容。
答案 2 :(得分:0)
因此,JB,我正在尝试遵循您的示例。
url $:可观察;
我得到一个错误,this.url $是对象,不能分配给字符串,所以我做了
url$: Observable<object>;
我还必须将URL和搜索词组合成一个字符串。
export class PackageSearchService {
searchResults: Observable<PackageInfo>;
private handleError: HandleError;
url$: Observable<Object>;
fulluserUrl: string;
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler
) {
this.handleError = httpErrorHandler.createHandleError('Service');
this.url$ = http.get(this.fulluserUrl).pipe(shareReplay());
}
search (packageName: string, refresh = false): Observable<PackageInfo>
{
const options = createHttpOptions(packageName, refresh);
this.searchResults = this.http.get(searchUrl + packageName, options) as Observable<PackageInfo>;
return this.searchResults
}
userRepo (packageName: string)
{
this.fulluserUrl = searchUrl + packageName;
return this.fulluserUrl;
}
}
关于组件示例
this.urlService.url$.pipe(
switchMap(url => getSomethingUsingTheUrl(url))
).subscribe(something => doWhateverYouWant(something));
我的profile-search.component中有一个类似的switchMap
switchMap(packageName =>
this.searchService.search(packageName, this.withRefresh)
)
).subscribe(
user => this.user = user
);
只是不确定getSomethingUsingTheUrl或doWhateverWant应该是什么,或者我应该如何编辑
答案 3 :(得分:0)
如果您尝试使用第二个可观察调用中的第一个可观察对象的结果,将两个Observables调用依次链接,您将寻求FlatMap:Chaining RxJS Observables from http data in Angular2 with TypeScript
如果您尝试保存其他非立即呼叫的url字符串,则服务中的ReplaySubject是我过去使用的方式。
快速说明:您可以直接返回this.http.get(...),无需将其参数化为“ searchResults”。
答案 4 :(得分:0)
好的,感谢基南和JB。我可以通过点击并使用BehaviorSubject来解决此问题。
MyService
export class ProfileSearchService {
profile: BehaviorSubject<ProfileInfo> = new BehaviorSubject({ login: '', name: '', avatar_url: '', repos_url: '' });
repos: BehaviorSubject<any[]> = new BehaviorSubject([]);
constructor(private http: HttpClient) {
this.profile.subscribe(({ repos_url }) => {
if (repos_url) {
// http request, set repoFetch to return value
this.http.get(repos_url).pipe(
tap(repos => this.repos.next(repos as any[]))
).subscribe();;
}
});
}
search (packageName: string) {
this.http.get(searchUrl + packageName).pipe(
tap(user => {
this.profile.next(user as ProfileInfo)
})
).subscribe();
}
}
MyComponent
export class UsersRepoComponent implements OnInit {
repo$: Observable<any>;
constructor(private searchService: ProfileSearchService){}
ngOnInit() {
this.repo$ = this.searchService.repos;
}
}
还要感谢Corey Pyle握住我的手,并带领我逐步完成。