zoukankan      html  css  js  c++  java
  • [Angular] Using ngOnChanges lifeCycle hook to break object reference

    What could be the issue, for example we have two list:

    Parent component:

    @Component({
      selector: 'passenger-dashboard',
      styleUrls: ['passenger-dashboard.component.scss'],
      template: `
        <div>
          <passenger-count
            [items]="passengers">
          </passenger-count>
          <div *ngFor="let passenger of passengers;">
            {{ passenger.fullname }}
          </div>
          <passenger-detail
            *ngFor="let passenger of passengers;"
            [detail]="passenger"
            (edit)="handleEdit($event)"
            (remove)="handleRemove($event)">
          </passenger-detail>
        </div>
      `
    })
    export class PassengerDashboardComponent implements OnInit {
      passengers: Passenger[];
      constructor() {}
      ngOnInit() {
        this.passengers = [{
          id: 1,
          fullname: 'Stephen',
          checkedIn: true,
          checkInDate: 1490742000000,
          children: null
        }, {
          id: 2,
          fullname: 'Rose',
          checkedIn: false,
          checkInDate: null,
          children: [{ name: 'Ted', age: 12 },{ name: 'Chloe', age: 7 }]
        }, {
          id: 3,
          fullname: 'James',
          checkedIn: true,
          checkInDate: 1491606000000,
          children: null
        }, {
          id: 4,
          fullname: 'Louise',
          checkedIn: true,
          checkInDate: 1488412800000,
          children: [{ name: 'Jessica', age: 1 }]
        }, {
          id: 5,
          fullname: 'Tina',
          checkedIn: false,
          checkInDate: null,
          children: null
        }];
      }
      handleEdit(event: Passenger) {
        this.passengers = this.passengers.map((passenger: Passenger) => {
          if (passenger.id === event.id) {
            passenger = Object.assign({}, passenger, event);
          }
          return passenger;
        });
      }
      handleRemove(event: Passenger) {
        this.passengers = this.passengers.filter((passenger: Passenger) => {
          return passenger.id !== event.id;
        });
      }
    }

    Child component:

    @Component({
      selector: 'passenger-detail',
      styleUrls: ['passenger-detail.component.scss'],
      template: `
        <div>
          <span class="status" [class.checked-in]="detail.checkedIn"></span>
          <div *ngIf="editing">
            <input 
              type="text" 
              [value]="detail.fullname"
              (input)="onNameChange(name.value)"
              #name>
          </div>
          <div *ngIf="!editing">
            {{ detail.fullname }}
          </div>
          <div class="date">
            Check in date: 
            {{ detail.checkInDate ? (detail.checkInDate | date: 'yMMMMd' | uppercase) : 'Not checked in' }}
          </div>
          <div class="children">
            Children: {{ detail.children?.length || 0 }}
          </div>
          <button (click)="toggleEdit()">
            {{ editing ? 'Done' : 'Edit' }}
          </button>
          <button (click)="onRemove()">
            Remove
          </button>
        </div>
      `
    })
    export class PassengerDetailComponent implements OnInit {
    
      @Input()
      detail: Passenger;
    
      @Output()
      edit: EventEmitter<any> = new EventEmitter();
    
      @Output()
      remove: EventEmitter<any> = new EventEmitter();
    
      editing: boolean = false;
      
      constructor() {}
    
      ngOnInit() {
        console.log('ngOnInit');
      }
      
      onNameChange(value: string) {
        this.detail.fullname = value;
      }
      
      toggleEdit() {
        if (this.editing) {
          this.edit.emit(this.detail);
        }
        this.editing = !this.editing;
      }
      onRemove() {
        this.remove.emit(this.detail);
      }
    }

    They both display list of "passengers".

    What will happens that when we change the "passenger" value in 'passenger-detail' component. It will using '(edit)' event to update parent component's 'passengers' variable.

    Both changes happens in the same time.

    But what we really want is, until child component click "Done" button then parent component get udpate.

    So what we can do is using 'ngOnChanges' in child component to break Javascript object reference (this.detail, which marked in yellow background).

    export class PassengerDetailComponent implements OnChanges, OnInit {
    
      constructor() {}
    
      ngOnChanges(changes) {
        if (changes.detail) {
          this.detail = Object.assign({}, changes.detail.currentValue);
        }
        console.log('ngOnChanges');
      }
      
      onNameChange(value: string) {
        this.detail.fullname = value;
      }
      
      ...
    }

    We use 'Object.assign' to create a new 'this.detail' object reference.

    And because of this new creation, it actually breaks the reference of 'this.detail'.

    And only when click "Done" button, the deatial will be sent to the parent component.

  • 相关阅读:
    CF1537C Challenging Cliffs
    CF1454E Number of Simple Paths
    六、链表
    AOP中的一些概念
    Autowired查找顺序
    webpack配置babel
    selenium处理iframe下 #document 标签
    Soul 网关 Nacos 数据同步源码解析
    安装ssl证书后,部分浏览器提示你的链接不安全,服务器应使用tls1.2或更高版本
    php 安装 imagick扩展失败 ,phpinfo一直不显示
  • 原文地址:https://www.cnblogs.com/Answer1215/p/6298063.html
Copyright © 2011-2022 走看看