• [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.

  • 相关阅读:
    web服务之NginX介绍
    LVS介绍以及工作模式案例
    sersync 实现实时数据同步
    Java高并发20-并发包中锁原理解析(二)
    Java高并发19-并发包中锁原理解析(一)
    从零开始学VUE之VueRouter(导航守卫)
    从零开始学VUE之VueRouter(传递参数)
    从零开始学VUE之VueRouter(嵌套路由)
    从零开始学VUE之VueRouter(路由懒加载)
    从零开始学VUE之VueRouter(动态路由)
  • 原文地址:https://www.cnblogs.com/Answer1215/p/6298063.html
Copyright © 2020-2023  润新知