Angular 如何在角坐标系中使用计算/计算特性?

Angular 如何在角坐标系中使用计算/计算特性?,angular,binding,calculated-field,computed-properties,computed-field,Angular,Binding,Calculated Field,Computed Properties,Computed Field,我被这样一个问题折磨着:在角投影中,我应该在哪里找到我的计算属性 例如: 我有模型、获取模型的服务和显示模型的组件 person.model.ts: 导出类人员{ 名字:字符串; lastName:string; } person.service.ts: 导出类PersonService{ //注入http:HttpClient 获取(id){ 返回这个.http.get(`api endpoint/person/${id}`); } } person.component.ts @组件({

我被这样一个问题折磨着:在角投影中,我应该在哪里找到我的计算属性

例如: 我有模型、获取模型的服务和显示模型的组件

person.model.ts:

导出类人员{
名字:字符串;
lastName:string;
}
person.service.ts:

导出类PersonService{
//注入http:HttpClient
获取(id){
返回这个.http.get(`api endpoint/person/${id}`);
}
}
person.component.ts

@组件({
选择器:“应用程序”,
模板:`
`,
提供者:[个人服务]
})
导出类AppComponent{
人:人,;
//注入personService:personService
恩戈尼尼特(){
personService.get(1.subscribe)(p=>this.person=p);
}
}
现在我需要
fullName
将其显示在输入字段下的模板中

选项1。如果你在谷歌上搜索“计算属性”,你很可能会在组件中找到计算属性的示例

@组件({
选择器:“应用程序”,
模板:`
{{fullName}}
`,
提供者:[个人服务]
})
导出类AppComponent{
人:人,;
获取全名(){
返回`${this.person.firstName}${this.person.lastName}`
}
//注入personService:personService
恩戈尼尼特(){
personService.get(1.subscribe)(p=>this.person=p);
}
}
但这是这种代码的正确位置吗? 如果我们想在其他组件、服务等中重用此属性,该怎么办

选项2。我个人想扩展
person.model.ts

导出类人员{
名字:字符串;
lastName:string;
获取全名():字符串{
返回`${this.firstName}${this.lastName}`
}
}
@组件({
选择器:“应用程序”,
模板:`
{{person.fullName}
`,
提供者:[个人服务]
})
导出类AppComponent{
人:人,;
//注入personService:personService
恩戈尼尼特(){
personService.get(1.subscribe)(p=>this.person=p);
}
}
但我们面临另一个问题。我们的
personService
返回的对象根本没有这个getter

那我该怎么办?我需要创建
person.model.ts
的新实例,然后将我们的响应分配给它吗?或者我需要另一个模型,比如
person.view model.ts


感谢您的时间:D

我将添加一个我觉得非常有用的模式。我个人喜欢将关注点分开,即在
PersonService
中保留所有
Person
相关的计算属性,并直接从服务中使用这些属性。特别是如果你在其他地方使用它们。 在您的
PersonService
中,我将添加一个
行为主题
,您可以在其他地方的模板中绑定到该主题:

// person.serice.ts

private readonly _fullName: BehaviorSubject<string> = new BehaviorSubject('');
public readonly fullName$ = this._fullName.asObservable();

public get fullName(): string {
    return this._fullName.getValue();
}

public set fullName(p: Person): string {
    this._fullName.next(p.firstName + p.lastName);
}

// inject http: HttpClient

get(id) {
   return this.http.get<Person>(`api-endpoint/person/${id}`)
       .pipe(tap((p: Person) => this.fullName = p);
}
//person.serice.ts
private readonly_全名:BehaviorSubject=new BehaviorSubject(“”);
public readonly fullName$=this.\u fullName.asObservable();
public get fullName():字符串{
返回此值。_fullName.getValue();
}
公共集全名(p:Person):字符串{
this.\u fullName.next(p.firstName+p.lastName);
}
//注入http:HttpClient
获取(id){
返回此.http.get(`api endpoint/person/${id}`)
.pipe(tap((p:Person)=>this.fullName=p);
}
在您的组件中:

// person.component.ts

@Component({
  selector: 'app',
  template: `
   <div>
    <input [value]='person.firstName'>
    <input [value]='person.lastName'>
    <span>{{ fullName$ | async }}</span>
   </div>
`,
  providers:  [ PersonService ]
})
export class AppComponent {
  person: Person;
  fullName$: Observable<string>;

  // inject personService: PersonService

  ngOnInit() {
   this.fullName$ = this.personService.fullName$;
   this.personService.get(1).subscribe(p => this.person = p);
  }
}


//person.component.ts
@组成部分({
选择器:“应用程序”,
模板:`
{{fullName$| async}}
`,
提供者:[个人服务]
})
导出类AppComponent{
人:人,;
全名$:可见;
//注入personService:personService
恩戈尼尼特(){
this.fullName$=this.personService.fullName$;
this.personService.get(1.subscribe)(p=>this.person=p);
}
}
基本解决方案 因此,对于选项2,您需要将来自服务器的数据封装到模型中

person.model.ts

导出类人员{
名字:字符串;
lastName:string;
建造师(obj){
分配(本,obj);
}
获取全名():字符串{
返回this.firstName+this.lastName;
}
}
当您实现此功能或使用一些额外的保护逻辑(检查扩展解决方案)时,您可以在您的服务中执行此功能:

person.service.ts

导出类PersonService{
...
get(id):可观察的{
返回此.http.get(`api端点/person/${id}`).pipe(
map((响应:部分)=>新人(响应)),
);
}
}
Partial
类型,因为它不具有某些动态属性

扩展解 尽管此基本解决方案易受运行时错误的影响。例如,如果初始化对象的某些字段与类定义冲突,并且它也不关心obj是否有其他字段,则您可能需要添加更多逻辑,例如:

已过滤的-object.helper.ts

import{keys}from'ts transformer keys';//允许从接口取出密钥
导出函数过滤器DERBEJEC(obj){
const allowed=keys();
返回Object.keys(obj)
.filter(键=>允许。包括(键))
.reduce((对象,键)=>{
obj[key]=原始[key];
返回obj;
}, {});
}
请记住,这需要安装
ts变压器钥匙

person.model.ts

从'path/to/filteredobject.helper'导入{filteredObjec};
...
建造师(obj){
赋值(this,filteredObjec(obj));
}

或者,您可以创建自己的装饰器来描述字段。我在这里不提供示例,因为这太过分了。

我已经成功地使用这个npm模块很长一段时间了:

如果您同意为您的模型创建类,那么它是一个救命稻草,可以处理类的深度嵌套和许多其他非t类