Angular - Comment mettre à jour un composant enfant qui prend un paramètre d'entrée et le restitue correctement du premier coup
P粉463418483
P粉463418483 2024-03-21 21:06:55
0
2
443

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.

P粉463418483
P粉463418483

répondre à tous(2)
P粉658954914

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 projet

P粉022723606

La 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

education: Education = 

parent.component.html





child.component.ts

export class EducationItemComponent implements OnChanges {
  @Input() school: string;
  @Input() degree: string;

  ngOnChanges(changes: SimpleChanges): void {
    // will emit whenever .school or .degree is changed in the parent
  }
}

Avantages :

  • Simple et intuitif à utiliser, fonctionne « juste »
  • Envoyer les modifications aux composants enfants sans passe-partout supplémentaire

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@Input
  • 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) Education
  • 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

Reconstruire l'objet dans le parent une fois modifié

parent.component.ts

education: Education = 

updateEducation(educationProps: Partial): Education {
  this.education = {
    ...this.education, // Note: You may want to 'deep clone' your object depending on how nested it is
    ...educationProps
  }
}

Clonage profond

parent.component.html





child.component.ts

export class EducationItemComponent implements OnChanges {
  @Input() education: Education;

  ngOnChanges(changes: SimpleChanges): void {
    // will emit whenever updateEducation() is called in the parent
  }
}

Avantages :

    Conserver l'utilisation de l'interface
  • pour maintenir le couplage sémantique entre les composants parent et enfantEducation
  • 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.

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 parent

Transmettez des éléments réactifs dans les composants de votre enfant comme

et abonnez-vous directement aux modificationsBehaviorSubject

parent.component.ts

educationSubject: BehaviorSubject = new BehaviorSubject(  )

updateEducation(educationProps: Partial): Education {
  const updatedEducation: Education = {
    ...this.education, // Note: You may want to 'deep clone' your object depending on how nested it is
    ...educationProps
  }
  this.educationSubject.next(updatedEducation}
}

parent.component.html





  
  

child.component.ts

export class EducationItemComponent implements OnChanges {
  @Input() educationSubject: BehaviorSubject;
}

child.component.html


  

{{ education.school }}

Avantages :

  • Contrôle total sur l'envoi/l'abonnement aux événements. C'est bon pour tout autre effet secondaire que vous souhaitez déclencher
  • Peut être facilement étendu pour utiliser de nombreux composants, par exemple mettre educationSubject dans un service et injecter le même service dans n'importe quel composant qui en a besoin
  • Prône également l'utilisation d'objets immuables
  • Aucun passe-partout supplémentaire n'est requis pour recevoir les modifications apportées aux sous-composants

Inconvénients :

  • Nécessite un passe-partout supplémentaire pour envoyer les modifications au composant enfant, c'est-à-dire créer des updateEducation() fonctions
  • redondantes dans le composant parent
  • Limites typiques de l'utilisation de code réactif, comme la mutation uniquement via des flux, la nécessité d'éviter de se désinscrire (si vous n'utilisez pas | async), etc.
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal