Maison  >  Questions et réponses  >  le corps du texte

Angular - Comment mettre à jour un composant enfant qui prend un paramètre d'entrée et le restitue correctement du premier coup

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粉463418483P粉463418483211 Il y a quelques jours410

répondre à tous(2)je répondrai

  • P粉658954914

    P粉6589549142024-03-22 14:12:38

    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

    répondre
    0
  • P粉022723606

    P粉0227236062024-03-22 13:08:51

    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< /a>

    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 :

    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.

    répondre
    0
  • Annulerrépondre