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

Angular报错TypeError: Cannot read 'email' of undefined

问题根因

控制台报错TypeError: Cannot set properties of undefined (setting 'email')翻译:类型错误:无法为undefined对象设置属性(正在赋值'email'字段),触发原因以及后端接参为null的核心问题有3个:

  • 模板中双向绑定[(ngModel)]使用了仅支持读操作的安全导航符?,且实例化CreateUser时没有初始化嵌套的loginDO属性,loginDO初始为undefined,表单输入时Angular尝试给不存在的对象赋值直接抛错,输入的邮箱、密码根本没有绑定到userDO实例上,最终发请求时loginDO字段为空,后端自然接不到有效值。
  • LoginService中的HTTP POST是异步请求,原代码在接口还没返回响应时就同步return了初始空对象,组件层永远拿不到后端真实返回的用户数据。
  • 若后端Spring Boot接口的参数未加@RequestBody注解,即使前端传了正确JSON,Spring也无法将请求体解析为Java对象,同样会出现参数全为null的情况。
修复步骤

1. 修复数据模型初始化,移除ngModel中的安全导航符

首先修改CreateUser类,实例化时直接初始化嵌套的loginDO属性,避免出现undefined:

// CreateUser.ts
import { LoginUser } from "./LoginUser";

export class CreateUser {
    firstName: string = '';
    lastName: string = '';
    birthdayDate: string = '';
    gender: string = '';
    country: string = '';
    phoneNumber: string = '';
    loginDO: LoginUser = new LoginUser();
}

再修改LoginUser类,给字段设置初始空值:

// LoginUser.ts
export class LoginUser {
    email: string = '';
    password: string = '';
}

最后修改模板中两个输入框的ngModel绑定,去掉?安全导航符(此时loginDO已经确定初始化,不存在undefined问题):

<!-- 邮箱输入框 -->
<input
  type="email"
  class="form-control"
  id="exampleInputEmail1"
  aria-describedby="emailHelp"
  placeholder="Enter email"
  name="email"
  [(ngModel)]="userDO.loginDO.email"
/>

<!-- 密码输入框 -->
<input
  type="password"
  class="form-control"
  id="exampleInputPassword1"
  placeholder="Password"
  name="password"
  [(ngModel)]="userDO.loginDO.password"
/>

2. 修复异步请求逻辑,禁止同步返回异步结果

将LoginService中的方法改为直接返回HTTP请求的Observable对象,不要在Service中提前订阅、同步return空值:

// login.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { CreateUser } from '../CreateUser';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class LoginService {
  private baseUrl:string = "http://localhost:8080";
  constructor(private http:HttpClient) {}

  fetchUser(userData: CreateUser): Observable<CreateUser> {
    return this.http.post<CreateUser>(`${this.baseUrl}/login`, userData);
  }
}

对应修改组件中的调用逻辑,订阅Observable获取后端返回值:

// login.component.ts
import { Component, OnInit } from '@angular/core';
import { CreateUser } from 'src/app/CreateUser';
import { LoginService } from 'src/app/service/login.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  userDO: CreateUser = new CreateUser();
  constructor(private postRequest : LoginService) {}

  loginUser() {
    console.log("提交的表单数据:", this.userDO);
    this.postRequest.fetchUser(this.userDO).subscribe({
      next: (res) => {
        console.log("后端返回用户数据:", res);
        this.userDO = res;
        // 此处写登录成功后的路由跳转、本地存储等逻辑
      },
      error: (err) => {
        console.error("登录请求失败:", err);
      }
    })
  }

  ngOnInit(): void {}
}

3. 校验后端接口配置

确认Spring Boot的登录接口方法给入参加了@RequestBody注解,参考示例:

@PostMapping("/login")
// 必须加@RequestBody才能解析前端传的JSON请求体
public CreateUser login(@RequestBody CreateUser userDO) {
    // 此处编写账号密码校验逻辑
    // 此时userDO里的loginDO.email、loginDO.password可以正常获取到前端传值
}

如果Angular(默认4200端口)和Spring Boot(默认8080端口)端口不一致出现跨域报错,在Controller类上添加@CrossOrigin(origins = "http://localhost:4200")注解,或配置全局跨域规则即可。

内容的提问来源于stack exchange,提问作者Jay Mistry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 06:19:29