我的教育经历如下:
<cdk-virtual-scroll-viewport itemSize="5" class="list-scroll"> <app-education-item *ngFor="let education of loadedEducations" (isSelected)="changeSelected(education)" [ngClass]="{ selected: education == loadedEducation }" [education]="education" (isRemoved)="removeEducation(education)" ></app-education-item> </cdk-virtual-scroll-viewport>
并且是以下组件
<div [ngClass]="{ 'list-item-container-collapsed' : isCollapsed, 'list-item-container': !isCollapsed, 'unselected': !isActive, 'selected': isActive}" (click)="selectEducation()"> <div class="top-items-container" style="display: flex;"> <div class="item-text"> <span class="txt-header">{{educationHeader}}</span> <p class="txt-date"> <span>{{startDate}}</span> - <span>{{endDate}}</span> </p> </div> </div>
具有以下逻辑,用于显示从参数中获取的数据:
export class EducationItemComponent implements OnInit { @Input() education: Education; isCollapsed = false; isActive = false; startDate: string; endDate: string; educationHeader: string; educationDescription: string; constructor() { } ngOnInit(): void { console.log(this.education); this.startDate = this.education.startDate != '' ? formatDate(this.education.startDate, 'MMM yyyy', 'en-US') : formatDate(new Date(), 'MM YYYY', 'en-US') ; this.endDate = this.education.endDate != 'present' ? this.endDate = formatDate(this.education.endDate, 'MMM yyyy', 'en-US') : this.education.endDate; this.educationHeader = this.education.degree == undefined || this.education.description == undefined ? '' : this.education.degree + ' at ' + this.education.school; if (!this.education.description.enUS && this.education.description.nlNL) { this.educationDescription = this.education.description.nlNL; } else if (this.education.description.enUS) { this.educationDescription = this.education.description.enUS; } }
我使用自定义事件来处理更新
@Output() updatedValue: EventEmitter<any> = new EventEmitter<string>(); constructor() {} ngOnInit(): void {} fieldChanged(changes: SimpleChanges) { this.updatedValue.emit(changes); }
然后我有以下 html 用于操作数据:
<div class="update-wrap"> <div class="list-header">Update education</div> <div> <div class="col-sm-6 input-wrapper"> <app-input-field label="Institution" [value]="loadedEducation.school" (updatedValue)="loadedEducation.school = $event" ></app-input-field> </div> <div class="col-sm-6 input-wrapper date-picker-input"> <app-input-field label="Degree" [value]="loadedEducation.degree" (updatedValue)="loadedEducation.degree = $event" ></app-input-field> </div> </div> </div>
但是,字段 [value]="loadedEducation.school" (updatedValue)="loadedEducation.school = $event"
中的更新数据不会与子组件绑定,因此在刷新并获取之前不会显示任何内容来自数据库的数据。
我可以尝试实现哪些可能性?
我尝试实现 ngOnChanges,但没有成功。
当您更改列表中项目的属性时,loadedEducations 列表不会更改。尝试刷新列表(
this.loadedEducations = returnedEducations
)或在项目中使用状态管理问题的根本原因是
@Input()
无法检测到对象和数组内部的更改,因为它们都是 引用类型。您的education
属性是一个对象,因此在父组件中进行的直接改变属性的更改(例如education.school = 'newValue'
)不会触发子组件的属性@Input() education
的任何更改有几种方法可以解决这个问题,每种方法都有其优点和缺点:
仅传递您需要的属性作为基元
parent.component.ts
parent.component.html
child.component.ts
优点:
缺点:
@Input
数量的增长,变得笨重Education
接口)绑定更改时在父级中重建对象
parent.component.ts
深度克隆
parent.component.html
child.component.ts
优点:
Education
接口,保持父组件和子组件之间的语义耦合缺点:
updateEducation()
函数将反应性元素传递到您的子组件中,例如
BehaviorSubject
,并直接订阅更改parent.component.ts
parent.component.html
child.component.ts
child.component.html
优点:
educationSubject
放入服务中,并将相同的服务注入到任何需要它的组件中缺点:
updateEducation()
函数| async
)等