suchen

Heim  >  Fragen und Antworten  >  Hauptteil

Angular – So aktualisieren Sie eine untergeordnete Komponente, die einen Eingabeparameter übernimmt und ihn beim ersten Mal korrekt rendert

Meine Bildungserfahrung ist wie folgt:

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

und sind die folgenden Komponenten

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

Verfügt über die folgende Logik zum Anzeigen von aus Parametern erhaltenen Daten:

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;
    }
}

Ich verwende benutzerdefinierte Ereignisse, um Updates zu verarbeiten

@Output() updatedValue: EventEmitter<any> = new EventEmitter<string>();

  constructor() {}

  ngOnInit(): void {}

  fieldChanged(changes: SimpleChanges) {
    this.updatedValue.emit(changes);
  }

Dann habe ich das folgende HTML zum Bearbeiten der Daten:

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

Die aktualisierten Daten im Feld [value]="loadedEducation.school" (updatedValue)="loadedEducation.school = $event" werden jedoch nicht an die untergeordnete Komponente gebunden, sodass nichts angezeigt wird, bis sie aktualisiert wird und die Daten aus der Datenbank abruft.

Welche Möglichkeiten kann ich versuchen umzusetzen?

Ich habe versucht, ngOnChanges zu implementieren, aber ohne Erfolg.

P粉463418483P粉463418483253 Tage vor451

Antworte allen(2)Ich werde antworten

  • P粉658954914

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

    当您更改列表中项目的属性时,loadedEducations 列表不会更改。尝试刷新列表(this.loadedEducations = returnedEducations)或在项目中使用状态管理

    Antwort
    0
  • P粉022723606

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

    问题的根本原因是 @Input() 无法检测到对象和数组内部的更改,因为它们都是 引用类型。您的 education 属性是一个对象,因此在父组件中进行的直接改变属性的更改(例如 education.school = 'newValue' )不会触发子组件的属性 @Input() education 的任何更改

    有几种方法可以解决这个问题,每种方法都有其优点和缺点:


    仅传递您需要的属性作为基元

    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
      }
    }

    优点:

    • 使用简单直观,“正常”工作
    • 无需额外的样板即可将更改发送到子组件

    缺点:

    • 需要额外的样板来接收对子组件的更改。随着 @Input 数量的增长,变得笨重
    • 您失去了父组件和子组件之间的语义耦合,它们实际上由共享接口(即 Education 接口)绑定
    • 如果属性也是引用类型,则无法很好地扩展,在这种情况下,这些属性也需要解压并作为基元传递

    更改时在父级中重建对象

    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
      }
    }

    深度克隆< /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
      }
    }

    优点:

    缺点:

    • 需要额外的样板来发送更改到子组件,即在父组件中创建多余的 updateEducation() 函数

    将反应性元素传递到您的子组件中,例如 BehaviorSubject,并直接订阅更改

    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 }}

    优点:

    • 完全控制事件发送/订阅。这对于您希望触发的任何其他副作用都是有益的
    • 可以轻松扩展以使用许多组件,例如将 educationSubject 放入服务中,并将相同的服务注入到任何需要它的组件中
    • 还提倡使用不可变对象< /里>
    • 无需额外的样板即可接收子组件的更改

    缺点:

    • 需要额外的样板来发送更改到子组件,即在父组件中创建多余的 updateEducation() 函数
    • 使用反应式代码的典型限制,例如仅通过流进行变异、需要避免取消订阅(如果不使用 | async)等

    Antwort
    0
  • StornierenAntwort