Angular 如何在等待从服务中获取数据时显示加载微调器
我已经建立了一个可观察的服务来帮助我持久化数据,但是我需要一种方法来显示加载微调器,同时数据等待来自可观察的服务 我的服务:Angular 如何在等待从服务中获取数据时显示加载微调器,angular,Angular,我已经建立了一个可观察的服务来帮助我持久化数据,但是我需要一种方法来显示加载微调器,同时数据等待来自可观察的服务 我的服务: imports [...] import { Observable, BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class OrganisationsService { private organisations$ = new BehaviorSubjec
imports [...]
import { Observable, BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class OrganisationsService {
private organisations$ = new BehaviorSubject<Organisation[]>([
{
[...]
}
]);
constructor(private http: HttpClient) {
this.http
.get(
environment.apicall
)
.subscribe((data) => this.organisations$.next(data['organisations']));
}
getList(): Observable<Organisation[]> {
return this.organisations$.asObservable();
}
以下是我的组件:
imports ...
import UIkit from 'uikit';
import { Observable } from 'rxjs';
@Component({
selector: 'app-organisationlist',
templateUrl: './organisationlist.component.html',
styleUrls: ['./organisationlist.component.css']
})
export class OrganisationlistComponent implements OnInit {
public loading = true;
public organisations$: Observable<Organisation[]>;
constructor(public organisationsService: OrganisationsService) {}
ngOnInit() {
this.getData().then(() => {
this.loading = false;
});
}
async getData() {
this.organisations$ = this.organisationsService.getList();
}
}
以下是我使用Uikit的布局:
<div *ngIf="loading" uk-spinner></div>
<div>
<ul class="uk-list">
<li *ngFor="let organisation of organisations$ | async">
{{ organisation.name }}
</li>
</ul>
</div>
显然,getData函数虽然声明为异步,但实际上不是异步的,并且会立即返回。因此,这个.loading在init上是'false',因此它不会显示
有很多答案表明,当订阅发生在组件中时,这可能是如何工作的,但由于这是服务中的共享数据,我无法找到在将this.loading设置为false之前等待数据的方法
非常感谢。您可以在OrganizationListComponent中进行更多更改
您可以在OrganizationListComponent中进行更多更改
更改下面的行
async getData() {
this.organisations$ = this.organisationsService.getList();
}
到
这应该是可行的,因为这是您正在等待完成的可观察对象,而不是getData方法更改下一行
async getData() {
this.organisations$ = this.organisationsService.getList();
}
到
这应该是可行的,因为这是您正在等待完成的可观察到的,而不是getData方法谢谢大家的回答,但是这些建议都没有达到问题中所述的目的,但我确实制定了一个解决方案,最终得到了一个可行的解决方案。我们开始: 在该服务中,我创建了一个名为loading$的新可观察对象,并将其设置为一个新的BehaviorSubjecttrue 然后我创建了一个getter: getLoading:可观察{ 返回此。正在加载$; } 然后,我在订阅函数的第三个参数中将HTTP调用包装为true,然后将loading设置为false 因此,该服务如下所示:
import { Observable, BehaviorSubject, of } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class OrganisationsService {
private organisations$ = new BehaviorSubject<Organisation[]>([
{
[...]
}
]);
//initiate the new Loading variable via BehaviorSubject and set it to "true" from the beginning.
public loading$ = new BehaviorSubject<boolean>(true);
constructor(private http: HttpClient) {
//set the loading$ to true again just before we start the HTTP call
this.loading$.next(true);
this.http
.get(environment.apicall)
.subscribe(
//onNext method, where we get the data
(data) => this.organisations$.next(data['organisations']),
//onError method (Blank for now)
() => {},
//onComplated method, now that we have the data we can set the loading to false
() => {
this.loading$.next(false);
}
);
}
getLoading(): Observable<boolean> {
return this.loading$;
}
getList(): Observable<Organisation[]> {
return this.organisations$;
}
在我看来:
<div>
<div uk-spinner *ngIf="loading$ | async"></div>
<ul class="uk-list">
<li *ngFor="let organisation of organisations$ | async">
{{ organisation.name }}
</li>
</ul>
</div>
谢谢大家的回答,但这些建议都没有达到问题中所述的目的,但我确实制定了一个解决方案,最终得到了一个可行的解决方案。我们开始: 在该服务中,我创建了一个名为loading$的新可观察对象,并将其设置为一个新的BehaviorSubjecttrue 然后我创建了一个getter: getLoading:可观察{ 返回此。正在加载$; } 然后,我在订阅函数的第三个参数中将HTTP调用包装为true,然后将loading设置为false 因此,该服务如下所示:
import { Observable, BehaviorSubject, of } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class OrganisationsService {
private organisations$ = new BehaviorSubject<Organisation[]>([
{
[...]
}
]);
//initiate the new Loading variable via BehaviorSubject and set it to "true" from the beginning.
public loading$ = new BehaviorSubject<boolean>(true);
constructor(private http: HttpClient) {
//set the loading$ to true again just before we start the HTTP call
this.loading$.next(true);
this.http
.get(environment.apicall)
.subscribe(
//onNext method, where we get the data
(data) => this.organisations$.next(data['organisations']),
//onError method (Blank for now)
() => {},
//onComplated method, now that we have the data we can set the loading to false
() => {
this.loading$.next(false);
}
);
}
getLoading(): Observable<boolean> {
return this.loading$;
}
getList(): Observable<Organisation[]> {
return this.organisations$;
}
在我看来:
<div>
<div uk-spinner *ngIf="loading$ | async"></div>
<ul class="uk-list">
<li *ngFor="let organisation of organisations$ | async">
{{ organisation.name }}
</li>
</ul>
</div>
补充我的评论使用。我喜欢这个解决方案,因为它是透明的,看到一个调用是简单的,例如
return this.httpClient.get('.....').pipe(
indicate(this.loading$))
此外,您可以使用任何可观察的,而不仅仅是调用http。使用rxjs运算符进行,例如,使用forkJoin进行多个http调用,或者使用switchMap进行两个调用您只有一个管道,不要使调用过载,也不要导致flick
接线员是
export const prepare = <T>(callback: () => void) => {
return (source: Observable<T>): Observable<T> =>
defer(() => {
callback();
return source;
});
};
export const indicate = <T>(indicator: Subject<boolean>) => {
let alive = true;
return (source: Observable<T>): Observable<T> =>
source.pipe(
prepare(() =>
timer(500)
.pipe(
takeWhile(() => alive),
take(1)
)
.subscribe(() => {
indicator.next(true);
})
),
finalize(() => {
alive = false;
indicator.next(false);
})
);
};
export const toClass = <T>(ClassType: { new(): T }) => (
source: Observable<T>
) => source.pipe(map(val => Object.assign(new ClassType(), val)));
更新
我将$loading设置为属于服务,但您可以将$loading设置为属于组件,并在组件中使用管道
loading$ = new Subject<boolean>()
loadData2()
{
this.data="";
this.dataService.getData2().pipe(
indicate(this.loading$))
.subscribe(res=>{
this.data=res
})
}
<div *ngIf="(loading$ | async)">
loading...
</div>
您可以在中看到使用的补充我的评论。我喜欢这个解决方案,因为它是透明的,看到一个调用是简单的,例如
return this.httpClient.get('.....').pipe(
indicate(this.loading$))
此外,您可以使用任何可观察的,而不仅仅是调用http。使用rxjs运算符进行,例如,使用forkJoin进行多个http调用,或者使用switchMap进行两个调用您只有一个管道,不要使调用过载,也不要导致flick
接线员是
export const prepare = <T>(callback: () => void) => {
return (source: Observable<T>): Observable<T> =>
defer(() => {
callback();
return source;
});
};
export const indicate = <T>(indicator: Subject<boolean>) => {
let alive = true;
return (source: Observable<T>): Observable<T> =>
source.pipe(
prepare(() =>
timer(500)
.pipe(
takeWhile(() => alive),
take(1)
)
.subscribe(() => {
indicator.next(true);
})
),
finalize(() => {
alive = false;
indicator.next(false);
})
);
};
export const toClass = <T>(ClassType: { new(): T }) => (
source: Observable<T>
) => source.pipe(map(val => Object.assign(new ClassType(), val)));
更新
我将$loading设置为属于服务,但您可以将$loading设置为属于组件,并在组件中使用管道
loading$ = new Subject<boolean>()
loadData2()
{
this.data="";
this.dataService.getData2().pipe(
indicate(this.loading$))
.subscribe(res=>{
this.data=res
})
}
<div *ngIf="(loading$ | async)">
loading...
</div>
您可以在中看到,您可以创建自己的服务,其中包括行为主体和公共加载功能。app.service.ts
public loading: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false)
public isLoading(state: boolean): void { this.loading.next(state) }
在app.component.html视图中,导入共享微调器,如下所示:
<spinner [showSpinner]="loading$ | async"></spinner>
共享组件@input showSpinner带有*ngIf标志以决定
是否显示微调器
最后,在返回的api中,调用可以编写如下内容:
this.appService.isLoading(true)
return this.callApiByMethod(options).pipe(
finalize(() => this.appService.isLoading(false)),
shareReplay(),
) as Observable<T>
我在这里使用rx finalize,因此它将创建一个回调函数,可以处理成功和错误响应。您可以创建自己的服务,其中包括行为主体和公共加载函数。app.service.ts
public loading: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false)
public isLoading(state: boolean): void { this.loading.next(state) }
在app.component.html视图中,导入共享微调器,如下所示:
<spinner [showSpinner]="loading$ | async"></spinner>
共享组件@input showSpinner带有*ngIf标志以决定
是否显示微调器
最后,在返回的api中,调用可以编写如下内容:
this.appService.isLoading(true)
return this.callApiByMethod(options).pipe(
finalize(() => this.appService.isLoading(false)),
shareReplay(),
) as Observable<T>
我在这里使用rx finalize,因此它将创建一个回调函数,可以处理成功和错误响应。最好的:感谢Eliseo。。。由于某些原因,带有ng模板的指示器对我不起作用。我用一个答案和一个例子来补充评论,我希望这能帮助你回答你的问题吗?最好的:谢谢Eliseo。。。由于某些原因,带有ng模板的指示器对我不起作用。我用一个答案和一个例子来补充评论,我希望这能帮助你回答你的问题吗?谢谢你,维杰。但这也不行。。。因为getData会立即返回,所以then块会被插入
立即返回,因此此.loading立即为假。谢谢Vijay。但这也不行。。。因为getData会立即返回,所以then块会立即返回,因此this.loading立即为false。谢谢Vilsad,但这也不起作用。。。同样,getData会立即返回,因此此.loading立即为false。谢谢Vilsad,但这也不起作用。。。同样,getData会立即返回,因此this.loading立即为false。