Mon expérience éducative est la suivante :
<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>
et sont les composants suivants
<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>
Possède la logique suivante pour afficher les données obtenues à partir des paramètres :
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; } }
J'utilise des événements personnalisés pour gérer les mises à jour
@Output() updatedValue: EventEmitter<any> = new EventEmitter<string>(); constructor() {} ngOnInit(): void {} fieldChanged(changes: SimpleChanges) { this.updatedValue.emit(changes); }
Ensuite, j'ai le html suivant pour manipuler les données :
<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>
Cependant, les données mises à jour dans le champ [value]="loadedEducation.school" (updatedValue)="loadedEducation.school = $event"
ne seront pas liées au composant enfant, donc rien ne sera affiché jusqu'à ce qu'il actualise et récupère les données de la base de données.
Quelles possibilités puis-je essayer de mettre en œuvre ?
J'ai essayé d'implémenter ngOnChanges mais sans succès.
La liste chargéeEducations ne change pas lorsque vous modifiez les propriétés des éléments de la liste. Essayez d'actualiser la liste (
this.loadedEducations = returnedEducations
) ou utilisez la gestion d'état dans votre projetLa cause première du problème est tout changement dans
@Input()
无法检测到对象和数组内部的更改,因为它们都是 引用类型。您的education
属性是一个对象,因此在父组件中进行的直接改变属性的更改(例如education.school = 'newValue'
)不会触发子组件的属性@Input() education
Il existe plusieurs façons de résoudre ce problème, chacune avec ses avantages et ses inconvénients :
Passez uniquement les propriétés dont vous avez besoin en tant que primitives
parent.component.ts
parent.component.html
child.component.ts
Avantages :
Inconvénients :
Un passe-partout supplémentaire est nécessaire pour- recevoir les modifications apportées aux composants enfants. À mesure que le nombre de augmente, cela devient lourd
Vous perdez le couplage sémantique entre les composants parent et enfant, ils sont en fait liés par une interface partagée (c'est-à-dire - interface)
Ne s'adapte pas bien si les propriétés sont également des types de référence, auquel cas ces propriétés doivent également être décompressées et transmises en tant que primitives-
@Input
Education
Reconstruire l'objet dans le parent une fois modifié
parent.component.ts
Clonage profond
parent.component.html
child.component.ts
Avantages :
Conserver l'utilisation de l'interface- pour maintenir le couplage sémantique entre les composants parent et enfant
Promouvoir l'utilisation d'- objets immuablesC'est généralement une bonne pratique pour les objets
Pas besoin de passe-partout supplémentaire pour - recevoir les modifications apportées aux sous-composants.
Education
Inconvénients :
Nécessite un passe-partout supplémentaire pour- envoyer les modifications au composant enfant, c'est-à-dire créer des fonctions
updateEducation()
redondantes dans le composant parentTransmettez des éléments réactifs dans les composants de votre enfant comme
et abonnez-vous directement aux modifications
BehaviorSubject
parent.component.ts
parent.component.html
child.component.ts
child.component.html
Avantages :
educationSubject
dans un service et injecter le même service dans n'importe quel composant qui en a besoinInconvénients :
updateEducation()
fonctions| async
), etc.