You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 12:25:56