【问题标题】:Angular cannot read property of undefined in component/formAngular 无法读取组件/表单中未定义的属性
【发布时间】:2018-05-08 05:34:54
【问题描述】:

我正在尝试让 UPDATE 从我的 CRUD API 中工作。我知道问题出在 UPDATE 的表单或组件中,但我不确定我缺少什么。

表单 HTML

<form #form="ngForm" (ngSubmit)="updateReminder(form.value)">
  <div class="form-group">
    <label for="nameField">Name:</label>
    <input name="nameField" class="form-control" [ngModel]="reminders.name">
    <br />
    <label for="occasionField">Occasion:</label>
    <input name="occasionField" class="form-control" 
[ngModel]="reminders.occasion">
 </div>
 <button type="submit">save</button>
</form>

表单组件

import { Component, OnInit, Input } from '@angular/core';
import { ReminderService } from '../providers/reminder.service';

@Component({
  selector: 'app-results',
  templateUrl: './results.component.html',
  styleUrls: ['./results.component.css'],
  providers: [ReminderService]

})
export class ResultsComponent implements OnInit {

constructor(private reminderService:ReminderService) {}

 reminderList = null;
 @Input() reminders; 


ngOnInit() {}   


updateReminder(obj:any):void {
 this.reminders.name = obj.nameField;
 this.reminders.occasion = obj.occasionField;
 this.reminderService.updateReminder(this.reminders._id, this.reminders)
  .subscribe((result) =>{
    location.reload();
 })
}

应用组件 HTML

<div class="container">
<app-intro title="{{title}}"></app-intro>
<app-form ></app-form>
<app-results *ngFor='let reminder of reminderList' [reminders]="reminder">
</app-results>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256- FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"> 

应用组件(没有路由器)

import { Component } from '@angular/core';
import { ReminderService } from './providers/reminder.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [ReminderService]
})
export class AppComponent {

 title = 'The Amazing Reminder App';

  constructor(private reminderService:ReminderService) {}

  reminderList = null;

 ngOnInit() {
    this.reminderService.listReminders().subscribe((reminders)=>{
        this.reminderList = reminders;
    });
 } 
}

错误在 HTML 中:

错误类型错误:无法读取未定义的属性“名称”

<input name="nameField" class="form-control" [ngModel]="reminders.name">

【问题讨论】:

  • 错误发生在哪一行?
  • 抱歉,在 HTML 中。 ERROR TypeError: Cannot read property 'name' of undefined

标签: angular


【解决方案1】:

问题在于,作为输入变量,reminders 对象最初是未定义的,直到 angular 完成对组件的初始化。请在此处查看此行。

@Input() reminders;

然而 html 部分并没有等待渲染,因此很早就尝试使用这个变量。

<input name="nameField" class="form-control" [ngModel]="reminders.name">

因此,当它在初始化过程中尝试在输入变量设置之前解析模型时,它会遇到一个未定义的变量并尝试在其中找到一个name 字段,这当然还不存在。

有多种方法可以解决这个问题。

  1. reminders 对象一个默认值,甚至可以是一个空对象。我个人认为这样你会牺牲内存使用来防止错误,这似乎有点不干净
  2. 在您的 html 中使用 elvis 运算符作为空检查:[ngModel]="reminders?.name"。您必须在每个尝试访问提醒对象字段的字段中执行此操作,根据您的表单,这可能是很多代码
  3. 仅在最终设置提醒对象时才呈现表单。这可以通过在周围 div 或表单上的简单 *ngIf 轻松完成:&lt;div class="form-group" *ngIf="reminders"&gt;

这可能是个人选择,但对我来说,最后一个选项似乎是最干净的。没有理由在需要的值存在之前渲染您的视图,然后在设置它们时重新渲染它。

关于这个主题还有更多问题,例如你可以在这里查看this 一个。

希望这会有所帮助。


编辑

所以我重新检查了您的代码,虽然您的 updateReminder 函数是表单提交,但我想这是一个纯粹的更新表单。在这种情况下,我会说选项 3 应该可以正常工作。 Angular 会进行一些巧妙的更改检测和重新渲染,因此您可能应该首先检查输入变量是否设置正确。如果是,Angular 应该完成剩下的工作,并在它意识到对象现在存在的那一刻重新渲染 *ngIf 部分。

在我们检查输入变量之前,了解 Angular 如何处理输入变量总是有帮助的,这最终归结为所谓的 生命周期挂钩。一种特殊的钩子是ngOnInit() 钩子。以下是 Angular 的 documentation 对钩子的评价:

在Angular首先显示数据绑定属性并设置指令/组件的输入属性后初始化指令/组件

这基本上意味着作为@Input 传输到组件的变量在创建组件(构造函数代码)时设置,但仅在初始化之后设置。这会导致一些执行延迟,并最终导致上述错误。

要检查输入变量是否设置正确,我们可以将其记录到ngOnInit() 内的控制台。

ngOnInit() {
  console.log(this.reminders);
}  

作为对比,如果你在构造函数中这样做,你会看到此时它仍然是空的。

constructor(private reminderService:ReminderService) {
  // should be undefined at this point
  console.log(this.reminders);
}

因此,如果从 ngOnInit 记录了提醒变量,则 *ngIf 方法应该可以正常工作。

【讨论】:

  • 感谢您提供如此深思熟虑的答案。这实际上对“为什么”有很大帮助。我选择了#3,但是当我输入 *ngIf 时,表格消失了。我猜我需要在 ngInit 中添加一些东西来实例化组件?
  • 我明白你的意思。这当然归结为您的提醒对象来自哪里。因为它用@Input 注明,所以我假设该对象作为完全创建的对象来自您的组件外部。如果不是这种情况,例如,如果表单只是用于创建一个全新的对象而不是更新现有的对象,我会在声明上用一个全新的空对象实例化该对象(解决方案 1)。当它用于处理现有对象的新创建和更新时,也建议这样做,因为当什么都不存在时它是一种回退。
  • 因为解决方案 1 似乎在这里起到了作用,我只是猜你根本没有输入提醒变量。只需检查您是否真的需要 @Input 表示法。请记住,当您输入一个变量时,它会覆盖现有的变量。因此,如果您使用空状态初始化对象但输入未定义的对象,我敢打赌错误仍然会发生,只是在以后的生命周期挂钩中。
  • 我已经更新了我的答案,以提供更多关于正在发生的事情以及如何找到可能的问题的详细信息
  • 我回去安慰 ngOnInit 并发现提醒对象未定义,这确实解释了很多。但是,我不确定如何在组件中设置它以便加载。提醒:提醒{} 不正确。抱歉,我还是新手。
猜你喜欢
  • 2017-11-09
  • 1970-01-01
  • 2021-11-24
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 2018-12-14
  • 2021-10-23
  • 1970-01-01
相关资源
最近更新 更多