Angular RxJS 可观察服务不会在没有 Map 语句的情况下返回响应



我正在尝试在我的代码中使用 Observable 从数据库中获取数据对象列表以填充用户界面中的下拉列表。 我最初的方法每次都有效。 从 Pluralsight 视频中,我尝试了第二种方法来清理我的代码,但它不起作用。 尽管我逐字逐句地遵循视频,但我没有知识来理解为什么。

HttpErrorResponse

HttpErrorResponse {headers: HttpHeaders, status: 200, statusText: "OK", url: "http://localhost:4200/BusinessContinuity/", ok: false, …}
error:
error: SyntaxError: Unexpected token < in JSON at position 0 at JSON.parse (<anonymous>) at XMLHttpRequest.onLoad (http://localhost:4200/BusinessContinuity/vendor.js:29337:51) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (http://localhost:4200/BusinessContinuity/polyfills.js:10149:35) at Object.onInvokeTask (http://localhost:4200/BusinessContinuity/vendor.js:87812:33) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (http://localhost:4200/BusinessContinuity/polyfills.js:10148:40) at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (http://localhost:4200/BusinessContinuity/polyfills.js:9916:51) at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (http://localhost:4200/BusinessContinuity/polyfills.js:10231:38) at invokeTask (http://localhost:4200/BusinessContinuity/polyfills.js:11399:18) at XMLHttpRequest.globalZoneAwareCallback (http://localhost:4200/BusinessContinuity/polyfills.js:11436:25)
__proto__: Object
headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
message: "Http failure during parsing for http://localhost:4200/BusinessContinuity/"
name: "HttpErrorResponse"
ok: false
status: 200
statusText: "OK"
url: "http://localhost:4200/BusinessContinuity/"
__proto__: HttpResponseBase

这是我的服务代码:Department.service.ts

import { Injectable } from '@angular/core';
import { AppConfigService } from 'app/core/app-config.service';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import { IDepartmentEntity } from 'app/department/shared/models/department-entity';
@Injectable({
providedIn: 'root'
})
export class DepartmentService {
private _appConfig: AppConfigService;
private _appHost = '';
private _baseUrl = '';

constructor(private http: HttpClient, appConfig: AppConfigService) {
this._appConfig = appConfig;
this._appHost = this._appConfig.getConfig().appHost;
this._baseUrl = `${ this._appHost }departments`;
}
// **Approach #1 - works every single time**
getDepartmentDataSource(): Observable<IDepartmentEntity[]> {
return this.http.get<IDepartmentEntity[]>(`${ this._baseUrl }`)
.pipe(
map((response: any) => response.result)
);
}
// **Approach #2 - will not work**
departmentDataSource$ = this.http.get<IDepartmentEntity[]>(this._baseUrl)
.pipe(
tap(data => console.log('Departments', JSON.stringify(data)))
);
}

这是我的组件代码:Department.component.ts(为简洁起见,删除一些代码(


import { IDepartmentEntity } from 'app/department/shared/models/department-entity';
import { DepartmentService } from 'app/department/shared/services/department.service';

@Component({
selector: 'department-locations-list',
templateUrl: './department-locations-list.component.html',
styleUrls: ['./department-locations-list.component.css'],
})

export class DepartmentLocationsListComponent implements OnInit {
pageTitle = 'Department Locations';
departmentDataSource: IDepartmentEntity[] = [];
constructor(
private departmentService: DepartmentService,
private locationService: LocationService,
private fb: FormBuilder,
pageTitleService: PageTitleService
) {
pageTitleService.setTitle(this.pageTitle);
// ******* some code was removed for brevity *******
// ** Approach #1 - works every single time **
getDepartmentDataSource() {
this.departmentService.getDepartmentDataSource()
.subscribe(result => {
this.departmentDataSource = result;
});
}  
// ** Approach #2 **
departmentDataSource$ = this.departmentService.departmentDataSource$
.map(response => response);
getLocationDataSource() {
this.locationService.getLocations()
.subscribe(result => {
this.locationDataSource = result;
});
}
ngOnInit(): void {
this.departmentLocationsForm = this.fb.group({
departmentSelect: {},
locationSelect: {}
});

this.getDepartmentDataSource();
this.getLocationDataSource();
}
}

这是我的HTML(仅显示下拉逻辑(

对于方法 #2,我将部门数据源替换为部门数据源$ | 异步

<label for="departmentSelect">
<span class="aac-bold-text  mx-2">Department</span>
</label>
<select class="form-control"
id="departmentId"
formControlName="departmentSelect">
<option *ngFor="let dept of departmentDataSource$ | async"
[value]="dept.id">{{ dept.name }}
</option>
</select>

在方法#1中,您将response映射到response.result。您可以在服务的管道中执行此操作。

在方法 #2 中,您只需将response映射到组件中的response。所以这个map((基本上没有效果,因为它保持相同的对象。我想这是导致问题的错误。

// ** Approach #2 **
departmentDataSource$ = this.departmentService.departmentDataSource$
.map(response => response);

试试这样:

// ** Approach #2 **
departmentDataSource$ = this.departmentService.departmentDataSource$
.map(response => response.result);

订阅服务中可观察的从来都不是一种好的做法,因此您修改了在组件中订阅它的代码是件好事。

您应该进行以下更改

departmentDataSource$ = this.departmentService.departmentDataSource$ 
.map(response => response.result);

感谢大家回答我的问题。 我弄清楚了为什么方法#2不起作用。 事实证明,我的代码存在 2 个问题。

  1. 我的this._baseUrl在服务的构造函数内
  2. 我的回答没有@Lynx 242和@Mahaveer提到的"结果"。

溶液:

我将this._baseUrl移到服务中的构造函数之外,并将".result"添加到组件中的映射语句中。

export class DepartmentService {
private _appConfig: AppConfigService;
private _appHost = '';
private _baseUrl = 'http://localhost:xxxxx/Departments';

constructor(private http: HttpClient, appConfig: AppConfigService) {
// this._appConfig = appConfig;
// this._appHost = this._appConfig.getConfig().appHost;
// this._baseUrl = `${ this._appHost }departments`;
}
departmentDataSource$ = this.http.get<IDepartmentEntity[]>(this._baseUrl)
.pipe(
tap(data => console.log('departmentDataSource$', data))
);
}

元件

departmentDataSource$ = this.departmentService.departmentDataSource$
.map(
(data: any) => data.result as IDepartmentEntity[]
);

最新更新