Angular点击点赞按钮时出现Cannot read properties of undefined报错
问题排查:Angular组件点赞后触发"Cannot read properties of undefined (reading 'value')"错误
错误现象
- 触发时机:用户点击点赞按钮时触发,页面初始加载无此错误
- 错误日志:
news-section.component.ts:296 ERROR TypeError: Cannot read properties of undefined (reading 'value') at NewsSectionComponent_div_1_div_4_div_1_Template (news-section.component.html:35:14) at ReactiveLViewConsumer.runInContext (core.mjs:10425:13) at executeTemplate (core.mjs:10968:22) at refreshView (core.mjs:12489:13) at detectChangesInView (core.mjs:12653:9) at detectChangesInEmbeddedViews (core.mjs:12597:13) at refreshView (core.mjs:12513:9) at detectChangesInView (core.mjs:12653:9) at detectChangesInEmbeddedViews (core.mjs:12597:13) at refreshView (core.mjs:12513:9)
- 补充说明:
featuredImages已在模板正常显示,点赞函数toggleLike看似与初始加载逻辑无关
相关组件代码
初始化加载逻辑
featuredImages = []; featureNids = []; constructor( private restService: RestService, private gtmService: GtmService, private jsonApiService: JsonApiService, public hubService: HubDataService, private http: HttpClient, public router: Router ) {} ngOnInit() { this.getStoriesToDisplay(); } public getStoriesToDisplay() { // Try to pull from saved articles const index = this.newsFilterOptions.indexOf(this.currentOption); if (this.savedResults[index] && this.savedResults[index].length > 0) { this.storiesToDisplay = this.savedResults[index]; } else { let restType; if (this.currentOption === 'Current') { restType = RestServiceType.GlobalNews; } else { restType = RestServiceType.GlobalNewsCategory + this.currentOption; } const responsePromise = this.restService.getPagedJsonApiContent( window.location.protocol + '//' + window.location.host, restType, this.amountToShow, 0 ); responsePromise.then((resp) => { if (!resp.ok) { return Promise.reject(resp.statusText); } else { this.http .get('/get-featured-news-data?_format=json') .subscribe((res) => { if (Object.values(res)?.length > 0) { let sortedItemIds = Object.values(res); let splitedArray = sortedItemIds[0]['field_top_featured_news'].split('+'); splitedArray = [...new Set(splitedArray)]; let topFeaturedNews: string = res[0]['field_top_featured_news']; this.http .get( '/get-featured-news-details-rev/' + topFeaturedNews + '?_format=json' ) .subscribe((res) => { if (Object.values(res['rows'])?.length > 0) { const obj = {}; this.featuredImages = res['imagerows']; console.log('this.featureImages', this.featuredImages); Object.values(res['rows']).forEach((o: any) => { obj[o.nid[0]['value']] = o; }); // sorted according to added from back-end let sortedFeaturedNewsList = splitedArray.map((e) => Object.assign({}, obj[e]) ); // remove the empty object if it is unpublished news sortedFeaturedNewsList = sortedFeaturedNewsList.filter( (value) => Object.keys(value).length !== 0 ); for (let i = 0; i < Object.values(res)[0]?.length; i++) { this.featureNids.push( Object.values(res)[0][i].nid[0]['value'] ); } this.fnLoaded = true; this.featurednewstoDisplay.push(sortedFeaturedNewsList); this.featuredStoriesToDisplay = this.featurednewstoDisplay[0]; console.log('this.featuredStoriesToDisplay', this.featuredStoriesToDisplay); if (this.featuredStoriesToDisplay?.length > 0) { let ids = this.featuredStoriesToDisplay .map((a) => a.nid[0]['value']) .map((i) => Number(i)); this.story(resp, index, ids); } else { this.story(resp, index); } } else { this.story(resp, index); } }); } else { this.story(resp, index); } }); } }); } }
点赞触发函数
toggleLike(userId: string, featurednews): void { if (featurednews && featurednews.nid) { if (this.isLikedBy(userId, featurednews.field_users_that_liked)) { // remove current user like let i = 0; while (i < featurednews.field_users_that_liked.length) { if (featurednews.field_users_that_liked[i].value === userId) { featurednews.field_users_that_liked.splice(i, 1); } i++; } } else { featurednews.field_users_that_liked.push({ value: userId }); } // featurednews.nid = featurednews.nid[0].value; if (featurednews.nid[0] === undefined || featurednews.nid[0] === null) { featurednews.nid = featurednews.nid; } else { featurednews.nid = featurednews.nid[0].value; } let usersThatLiked = []; featurednews['field_users_that_liked'].forEach((element) => { usersThatLiked.push(element); }); featurednews.usersThatLiked = usersThatLiked; this.restService.getRestSessionToken().subscribe((token) => { const requestBody = JSON.stringify(featurednews); this.restService .patchResource( `${RestServiceType.NodeData}${featurednews.nid}?_format=json`, requestBody, token ) .subscribe(); }); } }
排查原因
错误根源是点赞函数中修改了featurednews对象的nid结构:
- 初始加载时,
featurednews.nid是数组格式(例如[{value: "123"}]),模板中大概率直接引用了featurednews.nid[0].value - 在
toggleLike函数里,你将featurednews.nid从数组替换成了字符串值(例如"123") - 点赞操作触发Angular变更检测,模板重新渲染时,尝试读取
featurednews.nid[0].value,但此时nid已经是字符串,nid[0]是字符串的第一个字符(例如"1"),这个字符没有value属性,因此抛出错误
解决方法
不要直接修改原始featurednews对象的nid结构,而是为API请求创建一个副本:
toggleLike(userId: string, featurednews): void { if (featurednews && featurednews.nid) { // 创建对象副本,避免修改原始数据影响模板渲染 const updatedNews = { ...featurednews }; if (this.isLikedBy(userId, updatedNews.field_users_that_liked)) { // remove current user like let i = 0; while (i < updatedNews.field_users_that_liked.length) { if (updatedNews.field_users_that_liked[i].value === userId) { updatedNews.field_users_that_liked.splice(i, 1); } i++; } } else { updatedNews.field_users_that_liked.push({ value: userId }); } // 仅在副本中调整nid格式用于API请求 let newsId; if (updatedNews.nid[0] === undefined || updatedNews.nid[0] === null) { newsId = updatedNews.nid; } else { newsId = updatedNews.nid[0].value; } let usersThatLiked = []; updatedNews['field_users_that_liked'].forEach((element) => { usersThatLiked.push(element); }); updatedNews.usersThatLiked = usersThatLiked; // 替换副本的nid为字符串版本 updatedNews.nid = newsId; this.restService.getRestSessionToken().subscribe((token) => { const requestBody = JSON.stringify(updatedNews); this.restService .patchResource( `${RestServiceType.NodeData}${newsId}?_format=json`, requestBody, token ) .subscribe(() => { // 更新本地数据时,只修改需要的字段,保留原始nid结构 featurednews.field_users_that_liked = [...updatedNews.field_users_that_liked]; }); }); } }
额外建议:在模板中添加空值保护,避免类似错误,比如将{{ featurednews.nid[0].value }}改为{{ featurednews.nid?.[0]?.value }}
内容的提问来源于stack exchange,提问作者Rajdatta Sarwade
相关产品推荐
相关产品推荐

