在 Angular 中调用服务后,数据未显示在 NG Bootstrap table 中
Data is not showing in NG Bootstrap table after calling a service in Angular
我正在使用 Angular Bootstrap library to develop my application. I have used the Angular Bootstrap Table to create a page to show some information which is sortable and searchable. So I have followed this link。
以下服务具有调用 API 获取数据的代码。我可以将数据打印到控制台中。但是每当我在我的组件中调用服务时,数据都不会显示在我的组件中。
服务:
interface SearchResultUserRegistrationInfo {
userLists: UserRegistrationInfo[];
total: number;
}
interface UserRegistrationState {
page: number;
pageSize: number;
sortColumn: SortColumnUserRegistrationInfo;
sortDirection: SortDirectionUserRegistrationInfo;
}
const compare = (v1: string | number | boolean, v2: string | number | boolean) => v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
function sort(userLists: UserRegistrationInfo[], column: SortColumnUserRegistrationInfo, direction: string): UserRegistrationInfo[] {
if (direction === '' || column === '') {
return userLists;
}
else {
return [...userLists].sort((a, b) => {
const res = compare(a[column], b[column]);
return direction === 'asc' ? res : -res;
});
}
}
@Injectable({
providedIn: 'root'
})
export class UserRegistrationService {
private apiPATH = 'account/';
public _search$ = new Subject<void>();
private _userInfoLists$ = new BehaviorSubject<UserRegistrationInfo[]>([]);
private _total$ = new BehaviorSubject<number>(0);
private _state: UserRegistrationState = {
page: 1,
pageSize: 5,
sortColumn: '',
sortDirection: ''
};
constructor(private service: ApplicationService) {
this._search$.pipe(
debounceTime(200),
switchMap(() => this._search()),
delay(2000)).subscribe(result => {
this._userInfoLists$.next(result.userLists);
this._total$.next(result.total);
});
this._search$.next();
}
// getter functions
get userInfoLists$() { return this._userInfoLists$.asObservable(); }
get total$() { return this._total$.asObservable(); }
get page() { return this._state.page; }
get pageSize() { return this._state.pageSize; }
// setter functions
set page(page: number) { this._set({ page }); }
set pageSize(pageSize: number) { this._set({ pageSize }); }
set sortColumn(sortColumn: SortColumnUserRegistrationInfo) { this._set({ sortColumn }); }
set sortDirection(sortDirection: SortDirectionUserRegistrationInfo) { this._set({ sortDirection }); }
private _set(patch: Partial<UserRegistrationState>) {
Object.assign(this._state, patch);
this._search$.next();
}
private _search(): Observable<SearchResultUserRegistrationInfo> {
const { sortColumn, sortDirection, pageSize, page } = this._state;
// server call
let allMemberLists: UserRegistrationInfo[] = [];
this.service.get<AccountListResultInfo>(`${this.apiPATH}lists`).subscribe(data => {
if (data) {
allMemberLists = data.Accounts;
console.log("========== From Service ==============");
console.log(allMemberLists);
}
});
// 1. sort
let userLists = sort(allMemberLists, sortColumn, sortDirection);
const total = userLists.length;
// 3. paginate
userLists = userLists.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
return of({ userLists, total });
}
}
在此服务中,下面一行可以打印数据。
console.log("========== From Service ==============");
console.log(allMemberLists);
分量:
export class UserRegistrationListComponent implements OnInit {
userInfoLists$: Observable<UserRegistrationInfo[]>;
total$: Observable<number>;
@ViewChildren(UserRegistrationInfoSortableHeader) headers:
QueryList<UserRegistrationInfoSortableHeader>;
constructor(
public service: UserRegistrationService) {
}
ngOnInit(): void {
this.userInfoLists$ = this.service.userInfoLists$;
this.total$ = this.service.total$;
console.log("---------- In component1 -----------------");
console.log(this.userInfoLists$);
this.service.userInfoLists$.subscribe(data =>{
console.log("---------- In component2 -----------------");
console.log(data);
})
}
}
下面的代码在 ngOnInit 方法中不打印数据。所以我的 Table 没有获取数据。
this.userInfoLists$ = this.service.userInfoLists$;
this.total$ = this.service.total$;
console.log("---------- In component1 -----------------");
console.log(this.userInfoLists$);
this.service.userInfoLists$.subscribe(data =>{
console.log("---------- In component2 -----------------");
console.log(data);
})
请帮我找到问题并解决。这是控制台输出:
问题在于您如何构建 _search() 函数以及您在可观察管道中设置的延迟 (2000)。
在_search函数中,return of()在API get订阅之外。这意味着 return 首先触发 , 然后 API get 订阅中的代码正在执行。
allMemberLists 被初始化为 [ ],所以 return 首先用 [ ] 发射。
但是,由于以下时间线,您看到的是 console.logs 的预期顺序。
- return 在 _search() 中用 [ ] 触发。 API 中的代码获取订阅尚未触发。
- 流水线的 switchmap 捕获 ([ ]) 的结果。但是 delay(2000) 阻止了订阅的代码,即 this._userInfoLists$.next([ ]) 尚未执行。
- API 中的代码现在触发获取订阅,您将获得 ==From 服务== console.log 和数据。
- 现在已经过去了 2000 毫秒。现在 this._userInfoLists$.next([ ]) 被触发了。
- 终于看到component2 console.log了。但是随着 [ ].
解决方案是避免为 API 调用设置这样的计时器。并避免订阅 API get in _search。而是在 _search() 中使用管道和映射运算符。您可以在 rxJS 官方文档中阅读 map() 的工作原理。
private _search(): Observable < SearchResultUserRegistrationInfo > {
// ALL THE CODE GOES INSIDE THE server call
return this.service.get < AccountListResultInfo > (`${this.apiPATH}lists`).pipe(map(data => {
const {
sortColumn,
sortDirection,
pageSize,
page
} = this._state;
let allMemberLists: UserRegistrationInfo[] = [];
if (data) {
allMemberLists = data.Accounts;
console.log("========== From Service ==============");
console.log(allMemberLists);
let userLists = sort(allMemberLists, sortColumn, sortDirection);
const total = userLists.length;
userLists = userLists.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
// map() operator will automatically convert the returned value into an observable for me
return {
userLists,
total
};
} else {
// In case data is null
return null
}
}));
}
让我知道它是否有效!
我正在使用 Angular Bootstrap library to develop my application. I have used the Angular Bootstrap Table to create a page to show some information which is sortable and searchable. So I have followed this link。
以下服务具有调用 API 获取数据的代码。我可以将数据打印到控制台中。但是每当我在我的组件中调用服务时,数据都不会显示在我的组件中。
服务:
interface SearchResultUserRegistrationInfo {
userLists: UserRegistrationInfo[];
total: number;
}
interface UserRegistrationState {
page: number;
pageSize: number;
sortColumn: SortColumnUserRegistrationInfo;
sortDirection: SortDirectionUserRegistrationInfo;
}
const compare = (v1: string | number | boolean, v2: string | number | boolean) => v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
function sort(userLists: UserRegistrationInfo[], column: SortColumnUserRegistrationInfo, direction: string): UserRegistrationInfo[] {
if (direction === '' || column === '') {
return userLists;
}
else {
return [...userLists].sort((a, b) => {
const res = compare(a[column], b[column]);
return direction === 'asc' ? res : -res;
});
}
}
@Injectable({
providedIn: 'root'
})
export class UserRegistrationService {
private apiPATH = 'account/';
public _search$ = new Subject<void>();
private _userInfoLists$ = new BehaviorSubject<UserRegistrationInfo[]>([]);
private _total$ = new BehaviorSubject<number>(0);
private _state: UserRegistrationState = {
page: 1,
pageSize: 5,
sortColumn: '',
sortDirection: ''
};
constructor(private service: ApplicationService) {
this._search$.pipe(
debounceTime(200),
switchMap(() => this._search()),
delay(2000)).subscribe(result => {
this._userInfoLists$.next(result.userLists);
this._total$.next(result.total);
});
this._search$.next();
}
// getter functions
get userInfoLists$() { return this._userInfoLists$.asObservable(); }
get total$() { return this._total$.asObservable(); }
get page() { return this._state.page; }
get pageSize() { return this._state.pageSize; }
// setter functions
set page(page: number) { this._set({ page }); }
set pageSize(pageSize: number) { this._set({ pageSize }); }
set sortColumn(sortColumn: SortColumnUserRegistrationInfo) { this._set({ sortColumn }); }
set sortDirection(sortDirection: SortDirectionUserRegistrationInfo) { this._set({ sortDirection }); }
private _set(patch: Partial<UserRegistrationState>) {
Object.assign(this._state, patch);
this._search$.next();
}
private _search(): Observable<SearchResultUserRegistrationInfo> {
const { sortColumn, sortDirection, pageSize, page } = this._state;
// server call
let allMemberLists: UserRegistrationInfo[] = [];
this.service.get<AccountListResultInfo>(`${this.apiPATH}lists`).subscribe(data => {
if (data) {
allMemberLists = data.Accounts;
console.log("========== From Service ==============");
console.log(allMemberLists);
}
});
// 1. sort
let userLists = sort(allMemberLists, sortColumn, sortDirection);
const total = userLists.length;
// 3. paginate
userLists = userLists.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
return of({ userLists, total });
}
}
在此服务中,下面一行可以打印数据。
console.log("========== From Service ==============");
console.log(allMemberLists);
分量:
export class UserRegistrationListComponent implements OnInit {
userInfoLists$: Observable<UserRegistrationInfo[]>;
total$: Observable<number>;
@ViewChildren(UserRegistrationInfoSortableHeader) headers:
QueryList<UserRegistrationInfoSortableHeader>;
constructor(
public service: UserRegistrationService) {
}
ngOnInit(): void {
this.userInfoLists$ = this.service.userInfoLists$;
this.total$ = this.service.total$;
console.log("---------- In component1 -----------------");
console.log(this.userInfoLists$);
this.service.userInfoLists$.subscribe(data =>{
console.log("---------- In component2 -----------------");
console.log(data);
})
}
}
下面的代码在 ngOnInit 方法中不打印数据。所以我的 Table 没有获取数据。
this.userInfoLists$ = this.service.userInfoLists$;
this.total$ = this.service.total$;
console.log("---------- In component1 -----------------");
console.log(this.userInfoLists$);
this.service.userInfoLists$.subscribe(data =>{
console.log("---------- In component2 -----------------");
console.log(data);
})
请帮我找到问题并解决。这是控制台输出:
问题在于您如何构建 _search() 函数以及您在可观察管道中设置的延迟 (2000)。
在_search函数中,return of()在API get订阅之外。这意味着 return 首先触发 , 然后 API get 订阅中的代码正在执行。 allMemberLists 被初始化为 [ ],所以 return 首先用 [ ] 发射。 但是,由于以下时间线,您看到的是 console.logs 的预期顺序。
- return 在 _search() 中用 [ ] 触发。 API 中的代码获取订阅尚未触发。
- 流水线的 switchmap 捕获 ([ ]) 的结果。但是 delay(2000) 阻止了订阅的代码,即 this._userInfoLists$.next([ ]) 尚未执行。
- API 中的代码现在触发获取订阅,您将获得 ==From 服务== console.log 和数据。
- 现在已经过去了 2000 毫秒。现在 this._userInfoLists$.next([ ]) 被触发了。
- 终于看到component2 console.log了。但是随着 [ ].
解决方案是避免为 API 调用设置这样的计时器。并避免订阅 API get in _search。而是在 _search() 中使用管道和映射运算符。您可以在 rxJS 官方文档中阅读 map() 的工作原理。
private _search(): Observable < SearchResultUserRegistrationInfo > {
// ALL THE CODE GOES INSIDE THE server call
return this.service.get < AccountListResultInfo > (`${this.apiPATH}lists`).pipe(map(data => {
const {
sortColumn,
sortDirection,
pageSize,
page
} = this._state;
let allMemberLists: UserRegistrationInfo[] = [];
if (data) {
allMemberLists = data.Accounts;
console.log("========== From Service ==============");
console.log(allMemberLists);
let userLists = sort(allMemberLists, sortColumn, sortDirection);
const total = userLists.length;
userLists = userLists.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
// map() operator will automatically convert the returned value into an observable for me
return {
userLists,
total
};
} else {
// In case data is null
return null
}
}));
}
让我知道它是否有效!