AngularJS中判断API返回变量是否存在的问题排查
media.metadata.date_time_original存在性避免报错的问题 我在使用AngularJS、CoffeeScript和HAML进行前端开发时,遇到了一个问题:从API获取包含图片属性的JSON元数据对象后,需要判断media.metadata.date_time_original属性是否存在来决定是否显示,但控制台一直抛出TypeError: Cannot read property 'date_time_original' of null的错误。下面是我的现有代码、报错信息,以及对应的解决办法:
现有CoffeeScript数据获取代码
getImages = -> listImage = [] for sheet in $scope.report.report_sheets() for composed in sheet.report_fragments() for fragment in composed.report_fragments() if fragment.fragment_type is 'images' for media in fragment.media() if media.metadata.date_time_original media.metadata.date_time_original = moment.utc(media.metadata.date_time_original).local().format('DD-MMM-YYYY h:mm A') listImage.push media listImage
现有HAML视图代码
.directive-report-images{ ng_show: 'conditionIsChecked && fragment._parentConditionChecked' } .row .col-md-4 .title %h5.black {{ fragment.title }} .col-md-8 %report_fragment_visibility .row{ ng_if: 'fragment.media().length <= 2' } .col-md-6.thumbnail{ ng_repeat: "img in fragment.media() | notArchived | orderBy:'order'" } %img.pointer{ ng_src: "{{ img.contentUrl() }}", ng_click:'openCarouselModal(img)' } %p {{ img.comment }} .photo-date{ng_if: "img.metadata.date_time_original" } %p {{ img.metadata.date_time_original}} .row{ ng_if: 'fragment.media().length > 2' } .col-md-12 .row .col-md-4.thumbnail{ ng_repeat: "img in fragment.media() | notArchived | orderBy:'order'" } %img.pointer{ ng_src: "{{ img.contentUrl() }}", ng_click:'openCarouselModal(img)' } %p {{ img.comment }} %p.photo-date {{ img.metadata.date_time_original }}
当前控制台报错
TypeError: Cannot read property 'date_time_original' of null
问题根源
报错的核心原因是:部分media对象的metadata属性为null,当代码直接访问null.date_time_original时,就会触发类型错误。我们需要在数据预处理阶段和视图渲染阶段都添加防御性检查,双管齐下解决问题。
解决方案
1. 在CoffeeScript中提前处理metadata为null的情况
修改数据获取的循环逻辑,先确保media.metadata不是null/undefined,再去判断date_time_original是否存在:
getImages = -> listImage = [] for sheet in $scope.report.report_sheets() for composed in sheet.report_fragments() for fragment in composed.report_fragments() if fragment.fragment_type is 'images' for media in fragment.media() # 用CoffeeScript安全导航符先校验metadata存在,再判断日期属性 if media.metadata?.date_time_original media.metadata.date_time_original = moment.utc(media.metadata.date_time_original).local().format('DD-MMM-YYYY h:mm A') listImage.push media # 额外优化:给null的metadata赋值空对象,避免后续视图访问报错 else if not media.metadata media.metadata = {} listImage
这里的?.是CoffeeScript的安全导航操作符,会自动判断media.metadata是否存在,不存在则直接返回undefined,不会触发报错。同时给null的metadata赋值空对象,后续视图访问属性时就不会因为null抛出异常。
2. 在HAML视图中添加多层存在性判断
即使后台处理了数据,视图层也要做兜底校验,避免API返回异常数据的情况:
修改HAML中两处日期相关的代码:
# 针对图片数量<=2的场景,修改ng-if判断条件 .photo-date{ng_if: "img.metadata && img.metadata.date_time_original" } %p {{ img.metadata.date_time_original}} # 针对图片数量>2的场景,添加判断后再渲染日期 %p.photo-date{ ng_if: "img.metadata && img.metadata.date_time_original" } {{ img.metadata.date_time_original }}
这里的img.metadata && img.metadata.date_time_original会先判断img.metadata是否有效(不是null/undefined),再判断date_time_original是否有值,只有两者都满足时才会渲染日期元素。
效果验证
经过以上修改后:
- 当
media.metadata为null时,代码不会尝试访问它的属性,彻底避免报错 - 只有当
date_time_original存在且有效时,才会在视图中显示日期 - 完全实现了“存在则显示,不存在则不显示”的预期逻辑
内容的提问来源于stack exchange,提问作者user9569059

