typescript Angular 6+ TypeError:无法读取未定义的属性“firstName”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/51904325/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Angular 6+ TypeError: Cannot read property 'firstName' of undefined
提问by Ben Racicot
My (Angular 6.1.2) view is loading in before my observable does thus creating the undefined error. The data ends up there properly after the console error.
我的(Angular 6.1.2)视图在我的 observable 之前加载,因此创建了未定义的错误。数据在控制台错误后正确结束。
COMPONENT
零件
ngOnInit() {
this.route.params.subscribe(params => {
this.UserId = params['id'];
this.objectService.get(this.UserId).subscribe((ret: user) => {
this.User = user;
});
});
}
SERVICE
服务
public get(id: string): Observable<User> {
return this.http.get<User>(`${this.api}/${id}`);
}
HTML
HTML
<h1>{{User.firstName}}</h1>
<h1>{{User.firstName}}</h1>
Checking it first suppresses the error.
首先检查它会抑制错误。
<h1 *ngIf="User">{{User.firstName}}</h1>
<h1 *ngIf="User">{{User.firstName}}</h1>
but I'd like to know how to do this correctly from the controller and or service so that my view works without checking for the data. Using the in-memory-api btw.
但我想知道如何从控制器和/或服务正确执行此操作,以便我的视图无需检查数据即可工作。顺便说一句,使用内存中的api。
UPDATE 2019:I've switched to resolving data with the router where I can then this issue is easy to handle with async pipe in the template. This method has saved me many headaches.
2019 年更新:我已切换到使用路由器解析数据,然后我可以在模板中使用异步管道轻松处理此问题。这个方法让我省了很多头痛。
UPDATE:It seems unanimous that we shouldn't be checking in the view. Properly setting the variables before they are used seems to be the best way. I've chosen to leverage the exported class when I set the variable like this:
更新:似乎一致认为我们不应该检查视图。在使用之前正确设置变量似乎是最好的方法。当我像这样设置变量时,我选择利用导出的类:
public user: User = new User();
which stops the undefined error.
public user: User = new User();
这会停止未定义的错误。
回答by Bruno Jo?o
You have three ways of solving this:
您可以通过三种方法解决此问题:
1 - Check the variable before binding it with ?
like <h1>{{User?.firstName}}</h1>
1 - 在使用?
like绑定之前检查变量<h1>{{User?.firstName}}</h1>
2 - Starting your variable with an empt object User = {}
;
2 - 用一个空对象启动你的变量User = {}
;
3 - Starting your variable with an empt User instance
3 - 用一个空的 User 实例启动你的变量
class User {
name: string;
...
}
class UserGrid {
user: User = new User();
}
As the error says cannot read property of undefined
正如错误所说 cannot read property of undefined
Tip: do not use first letter Upper for variable names. This is for classes and Types like user: User = new User();
提示:变量名不要使用首字母Upper。这适用于类和类型,例如user: User = new User();
回答by Jian Li
You are right, ideally we shouldn't put the checking logic in the view. You can do something like this:
你是对的,理想情况下我们不应该把检查逻辑放在视图中。你可以这样做:
In your component:
在您的组件中:
public firstName: string;
ngOnInit() {
this.route.params.subscribe(params => {
this.UserId = params['id'];
this.objectService.get(this.UserId).subscribe((ret: user) => {
if (user) {
this.firstName = user.firstName;
}
});
});
}
Then in your view html:
然后在您的视图 html 中:
<h1>{{firstName}}</h1>
Also, as a best practice for subscriptions and for better performance, you should subscribe in ngOnInit, then unsubscribe in ngOnDestroy, something like this:
此外,作为订阅和更好性能的最佳实践,您应该在 ngOnInit 中订阅,然后在 ngOnDestroy 中取消订阅,如下所示:
import { Subscription } from "rxjs";
public firstName: string;
private userSub: Subscription;
ngOnInit() {
this.route.params.subscribe(params => {
this.UserId = params['id'];
this.userSub = this.objectService.get(this.UserId).subscribe((ret: user) => {
if (user) {
this.firstName = user.firstName;
}
});
});
}
public ngOnDestroy() {
this.userSub.unsubscribe();
}
回答by Chybie
First of all, the way you did now is the one of the right way. The other better way would be the solution 1 suggested by @vinagreti.
首先,你现在的做法是正确的做法。另一种更好的方法是@vinagreti 建议的解决方案 1。
This happen because when your component initialised, the template is loaded but your User
object is undefined
because this.User = user;
is sit inside an async rxjs call.
发生这种情况是因为当您的组件初始化时,模板已加载,但您的User
对象是undefined
因为this.User = user;
位于异步 rxjs 调用中。
That's why in the template {{User.firstName}}
return error because you are reading firstName
from undefined.
这就是为什么在模板中{{User.firstName}}
返回错误的原因,因为您正在firstName
从 undefined中读取。
The proposed solutions by @vinagreti are the best solution already. Personally I preferred using <h1>{{User?.firstName}}</h1>
in most cases.
@vinagreti 提出的解决方案已经是最好的解决方案。我个人更喜欢<h1>{{User?.firstName}}</h1>
在大多数情况下使用。
回答by Chellappan ?
Rxjs switchmap is elegant way to subscribe inside another subscribe
Rxjs switchmap 是在另一个订阅中订阅的优雅方式
User={}
ngOnInit() {
this.route.params.switchMap(params=>{
this.objectService.get(params['id'])
}).subscribe((ret: user) => {
this.User = ret;
});
});
}
回答by Raj Sappidi
One way to deal with it is to initialize User in the component with an empty firstName
处理它的一种方法是使用空的 firstName 初始化组件中的 User