Angular项目添加图书分类筛选后出现TypeError读取'books'失败求助
问题:Angular按分类展示图书时出现"Cannot read properties of undefined (reading 'books')"错误
尝试按分类展示图书(如访问http://localhost:4200/books/category/1),原本无分类筛选功能正常,添加分类筛选代码后出现以下错误:
book-list.component.ts:52 Error occured. TypeError: Cannot read properties of undefined (reading 'books')
相关代码
Service类(book.service.ts)
import { Book } from './../common/book'; import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable, map } from 'rxjs'; import { environment } from 'src/environments/environment'; @Injectable({ providedIn: 'root', }) export class BookService { private baseUrl: string = environment.apiUrl + "/book"; constructor(private httpClient: HttpClient) {} getBookList(theCategoryId: number): Observable<Book[]> { const searchUrl = `${environment.apiUrl}/book/category/${theCategoryId}`; return this.httpClient.get<GetResponse>(searchUrl).pipe(map( response => response._embedded.books )); } } interface GetResponse { _embedded: { books: Book[] } }
组件TS文件(book-list.component.ts)
import { environment } from './../../../environments/environment'; import { Book } from './../../common/book'; import { BookService } from './../../services/book.service'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-book-list', templateUrl: './book-list.component.html', styleUrls: './book-list.component.css' }) export class BookListComponent implements OnInit { books: Book[] = []; currentCategoryId: number = 1; constructor( private bookService: BookService, private route: ActivatedRoute ) { } ngOnInit(): void { this.route.paramMap.subscribe(() => { this.listBooks(); }); } listBooks() { const hasCategoryId: boolean = this.route.snapshot.paramMap.has('id'); if (hasCategoryId) { this.currentCategoryId = +this.route.snapshot.paramMap.get('id')!; } else { this.currentCategoryId = 1; } this.bookService.getBookList(this.currentCategoryId).subscribe( data => { this.books = data; console.log(data); }, error => { console.log('Error occured.', error); }); } }
HTML文件(book-list.component.html)
<!-- Product info --> <section class="section has-background-grey-light"> <div class="container"> <div class="columns is-vcentered is-multiline"> <div class="column is-3-desktop is-12-tablet is-12-mobile" *ngFor="let book of books"> <div class="card"> <div class="card-image"> <figure class="image is-4by3"> <img src="{{ book?.imageUrl }}" alt="Placeholder image"> </figure> </div> <div class="card-content has-text-left"> <div class="media"> <div class="media-content"> <p class="is-size-5-tablet is-size-5-mobile is-size-5-desktop title">{{ book?.name }}</p> <p class="is-size-6-tablet is-size-8-mobile is-size-6-desktop subtitle">by {{ book?.author }}</p> </div> </div> </div> <div class="card-footer"> <div class="card-footer-item"> <div class="buttons"> <a class="button is-info"> <strong>Reserve</strong> </a> <a class="button is-light"> Rate </a> </div> </div> </div> </div> </div> </div> </div> </section> <!-- Product info end -->
控制台报错信息
Error occured. TypeError: Cannot read properties of undefined (reading 'books') at book.service.ts:21:38 at map.js:7:1 at OperatorSubscriber._next (OperatorSubscriber.js:13:1) at OperatorSubscriber.next (Subscriber.js:31:1) at map.js:7:1 at OperatorSubscriber._next (OperatorSubscriber.js:13:1) at OperatorSubscriber.next (Subscriber.js:31:1) at filter.js:6:50 at OperatorSubscriber._next (OperatorSubscriber.js:13:1) at OperatorSubscriber.next (Subscriber.js:31:1)
解决方法
问题根源
报错指向book.service.ts第21行的response._embedded.books,说明API返回的响应中**_embedded字段不存在或未定义**。常见原因:
- API接口返回格式不符合预期(如分类无图书时返回空对象,而非包含
_embedded.books的结构) - 请求URL路径错误,导致API返回非预期结果
修复步骤
1. 验证API响应格式
直接通过浏览器或Postman访问${environment.apiUrl}/book/category/1,确认返回的JSON结构是否包含_embedded.books。正常响应示例:
{ "_embedded": { "books": [ { "id": 1, "name": "示例图书", "author": "作者", "imageUrl": "..." } ] } }
如果返回的是直接的图书数组或无_embedded字段,需要调整Service的处理逻辑。
2. 添加空值保护逻辑
修改Service中的getBookList方法,使用可选链操作符和默认值避免崩溃:
getBookList(theCategoryId: number): Observable<Book[]> { const searchUrl = `${environment.apiUrl}/book/category/${theCategoryId}`; return this.httpClient.get<GetResponse>(searchUrl).pipe( map(response => response?._embedded?.books ?? []) ); }
?.:避免访问undefined对象的属性时抛出错误?? []:当books为undefined或null时返回空数组,保证组件能接收到合法的数组类型
3. 检查并修正URL路径
确认environment.apiUrl的取值,避免路径重复。例如如果environment.apiUrl已经包含/book,拼接后会出现/api/book/book/category/1的错误路径,需要调整为:
const searchUrl = `${environment.apiUrl}/category/${theCategoryId}`;
4. 优化模板的空状态提示
在HTML中添加空数组的提示,提升用户体验:
<!-- 在columns容器内添加 --> <div *ngIf="books.length === 0" class="column is-full has-text-centered"> <p class="is-size-4 has-text-grey">该分类下暂无图书</p> </div>
内容的提问来源于stack exchange,提问作者Petar Vukcevic
相关产品推荐
相关产品推荐

