ngOnChange() 在 angular2 中第二次不工作

ngOnChange() is not working secondtime in angular2

我在 angular2 工作。我正在将数据从一个父组件传递到另一个子组件。

<app-datatable-repr [myFilterData]="filterData"></app-datatable-repr> 

filterData 是一个对象。

第一次 OnChanges 检测到 "filterData" 的变化,但第二次 ngChange 没有检测到 "filterData" 的变化。

如何解决这个问题?

har-文件​​-upload.component.ts

import { Component, OnInit } from '@angular/core';
import { HarFileServiceService } from '../har-file-service.service';

@Component({
  selector: 'app-har-file-upload',
  templateUrl: './har-file-upload.component.html',
  styleUrls: ['./har-file-upload.component.css']
})

export class HarFileUploadComponent implements OnInit {

  constructor(private harFileServiceService:HarFileServiceService) { }

  ngOnInit() {
  }
  filterData:Object = {};
  changeListener(event:any){
    var that = this;
    var file = event.target.files[0];
    var myReader = new FileReader();
    var harFile = this.harFileServiceService;
    myReader.onload = function(e:any){
      var jsonData = JSON.parse(e.target.result);
      harFile.render(jsonData);
      that.filterData = harFile.responseFileData;
      // console.log(that.filterData)
    }
    // console.log(file);
    myReader.readAsText(file);
  }
}

har-文件​​-service.service.ts

import { Injectable } from '@angular/core';
import * as $ from 'jquery';

@Injectable()
export class HarFileServiceService {
    constructor() { }
    log:Object = {  entries: {} };
    totals:Object = {};
    pads:Object = {};
    left;
    right;
    idctr:number = 0;
    reqCount:number = 0;
    totalReqSize:number = 0;
    totalRespSize:number = 0;
    requestObj:Object = {'resources':[]};
    responseFileData:any = {};
    render(har: any) {
        var pageref;
        var that = this;
        $.each(har.log.entries, function (index, entries) {
            console.log(index, entries);
            var singleReqOb = {};
            that.requestObj['resources'].push(singleReqOb);
            pageref = pageref || entries.pageref;
            if(entries.pageref === pageref) {
                that.entry(index, entries);
            }
        });
        this.responseFileData = this.requestObj;
        console.log(this.responseFileData);
    }
    entry(id:any, entry:any) {
        id = id || this.idctr++;
        this.log['entries'][id] = entry;
        var t = new Date(entry.startedDateTime).getTime();
        if(this.left && this.right) {
            this.left = (this.left < t) ? this.left : t;
            this.right = (this.right > t) ? this.right : t;
        }
        else {
            this.left = this.right = t;
        }
        if(entry.request) {
            this.request(id, entry.request);
        }
        if(entry.response) {
            this.response(id, entry.response);
        }
    }
    request(id:any, request:any) {
        if(this.log['entries'][id]) {
            this.log['entries'][id].request = request;
        }
        else {
            this.log['entries'][id] = {
                id: id,
                request: request
            };
        }
        this._updateRequest(id, request);
        this.reqCount = this.reqCount + 1;
        if(request.headersSize && request.headersSize > 0) {
            this.totalReqSize = this.totalReqSize + request.headersSize;
        }
        if(request.bodySize && request.bodySize > 0) {
            this.totalReqSize = this.totalReqSize + request.bodySize;
        }
    }
    response(id:any, response:any) {
        if(this.log['entries'][id]) {
            this.log['entries'][id].response = response;
            this._updateResponse(id, response);

            if(response.headersSize && response.headersSize > 0) {
                this.totalRespSize = this.totalRespSize + response.headersSize;
            }
            if(response.bodySize && response.bodySize > 0) {
                this.totalRespSize = this.totalRespSize + response.bodySize;
            } 
        }
        else {
        }
    }
     _updateRequest(id:any, request:any) {
        var reqObj = this.requestObj['resources'][id]; 
        if(request.url) {
            reqObj['filePath'] = request.url;
        }
    };
    _updateResponse(id:any, response:any) {
        var reqObj = this.requestObj['resources'][id];
        var type =  response.content.mimeType;
        var type_0 = type.split("/")[0];
        var type_1 = type.split("/")[1];
        switch (type_1) {
            case "javascript":
            case "x-javascript":
                reqObj['type'] = 'script';
                break;
            case "css":
            case "json":
            case "html":    
                reqObj['type'] = type_1;
                break;
            case "x-shockwave-flash":
                reqObj['type'] = 'flash';
                break;
            default:
                reqObj['type'] = type;
                break;
        }
        if(type_0 == 'image' || type_0 == 'video'){
            reqObj['type'] = type_0;
            reqObj['type'] = (reqObj['type'] == 'image') ? 'image' : reqObj['type'];
        }
        if(response.content && response.content.text) {   
            reqObj['size'] = response.bodySize;
        }else{
            reqObj['size'] = '';
        }
    }
}

ngOnChange 这里

import { Component, OnInit , OnChanges, SimpleChanges, Input} from '@angular/core';
import * as $ from 'jquery';
import 'datatables.net'
import { HarFileServiceService } from '../har-file-service.service';

@Component({
  selector: 'app-datatable-repr',
  templateUrl: './datatable-repr.component.html',
  styleUrls: ['./datatable-repr.component.css']
})
export class DatatableReprComponent implements OnInit, OnChanges {
  @Input() myFilterData;
  constructor(private harFileServiceService:HarFileServiceService) { }
  public tableWidget: any;
  ngOnInit() {
    this.initDatatable();
  }

  ngOnChanges(changes:SimpleChanges){
    if(changes.myFilterData.currentValue.hasOwnProperty('resources')){
      this.tableWidget.clear().draw();
      this.tableWidget.rows.add(changes.myFilterData.currentValue.resources); // Add new data
      this.tableWidget.columns.adjust().draw(); // Redraw the DataTable
    }
  }
  private truncate(string:any, len:any){
    if (string.length > len)
      return string.substring(0,len)+'...';
    else
      return string;
  };
  parseURL(url:any) {
        var parsed_url:any = {}
        if (url == null || url.length == 0) return parsed_url;
    var protocol_i = url.indexOf('://');
    parsed_url.protocol = url.substr(0, protocol_i);
        var remaining_url = url.substr(protocol_i + 3, url.length);
        var domain_i = remaining_url.indexOf('/');
        domain_i = domain_i == -1 ? remaining_url.length - 1 : domain_i;
        parsed_url.domain = remaining_url.substr(0, domain_i);
        parsed_url.path = domain_i == -1 || domain_i + 1 == remaining_url.length ?
            null : remaining_url.substr(domain_i + 1, remaining_url.length);
        var domain_parts = parsed_url.domain.split('.');
        switch (domain_parts.length) {
            case 2:
                parsed_url.subdomain = null;
                parsed_url.host = domain_parts[0];
                parsed_url.tld = domain_parts[1];
                break;
            case 3:
                parsed_url.subdomain = domain_parts[0];
                parsed_url.host = domain_parts[1];
                parsed_url.tld = domain_parts[2];
                break;
            case 4:
                parsed_url.subdomain = domain_parts[0];
                parsed_url.host = domain_parts[1];
                parsed_url.tld = domain_parts[2] + '.' + domain_parts[3];
                break;
        }
        parsed_url.parent_domain = parsed_url.host + '.' + parsed_url.tld;
        return parsed_url;
  }
  imgExt:any = ["png", "gif", "jpeg", "jpg"]
    vidExt:any = ["mov", "flv", "mpg", "mpeg", "mp4", "ogv", "webm"]
  private initDatatable(): void {
    var myData =  this.myFilterData.hasOwnProperty('responseFileData') ? this.myFilterData.hasOwnProperty('responseFileData') : {};
    var that = this;
    let exampleId: any = $('#resourcesListing');
    this.tableWidget = exampleId.DataTable({
      aLengthMenu : [],
            aaData: myData,
            bPaginate: false,
            bAutoWidth: false,
            order: [],
            language: {
                search: "Search Resources : ",
                lengthMenu: "Display _MENU_ Resources",
                infoFiltered: "(filtered from _MAX_ Resources)",
                info: "Showing _START_ to _END_ of _TOTAL_ Resources",
                infoEmpty: "",
                zeroRecords: "<div style='padding: 10px;'>No resources match your search criteria.</div>",
                emptyTable: "<div style='padding: 10px;'>No resources available.</div>",
                paginate: {
                    first: " <i class='fa fa-fast-backward'></i> ",
                    previous: " <i class='fa fa-backward'></i> ",
                    next: " <i class='fa fa-forward'></i> ",
                    last: " <i class='fa fa-fast-forward'></i> "
                }
            }, 
      aoColumns: [
                {
                    mDataProp: 'filePath',
                    mRender: function (data, type, full) {
            var urlinfo = (that.parseURL(data));;
                        return that.truncate(urlinfo.domain, 50);
                    },
                    sWidth: "200px"
                },
                {
                    mDataProp: 'filePath',
                    mRender: function (data, type, full) {
            var urlinfo = (that.parseURL(data));
                        return "<a target='_blank' href='"+data+"'/>" + that.truncate(urlinfo.path ? urlinfo.path.split("?")[0] : "", 60) + "</a>";
          },
          sWidth: "400px"
                },
                // {
                //  mData: "filePath",
                //  mRender: function (data, type, full) {
                //      return '<a href="#" class="info"><i class="fa fa-info" aria-hidden="true"></i></a>';
                //  },
                //  sWidth: "60px",
                //  sClass: "center"
                // },
                {
                    mData: "type",
                    sWidth: "100px",
                    mRender: function (data, type, full) {
                        var resType = data,
                            resPath = full['filePath'];
                        if(resType == "css"){
                            // background-url will have type css, change to bg-img
                            var ext = resPath.split('.').pop();
                            if(that.imgExt.indexOf(ext) >= 0){
                                // showResType = "bg-img";
                                resType = "bg-image";
                            }
                        }else if(resType == "other" || resType == ""){
                            // video comes as type 'other' in firefox and empty in chrome
                            var ext = resPath.split('.').pop();
                            if(that.vidExt.indexOf(ext) >= 0){
                                // showResType = "video";
                                resType = "video";
                            }
                        }else if(resType == "img"){
                            resType = "image";
                        }
                        return resType;
                    }
                },
                {
                    mDataProp: 'filePath',
                    mRender: function (data, type, full) {
                        return (full.type == "image" || full.type == "img") ? '<div class="imageBackgroundParent"><div class="imageBackground" style="background-image: url('+ data +');"></div></div>' : "";
                    },
                    sWidth: "120px",
                    sClass: "center"
                },
                {
                    mData: "size",
                    sWidth: "80px"
                }
            ],
    });
  }
}

样本数据

"resources":[
  {
    "filePath": "http://www.cricbuzz.com/live-cricket-scores/18460/sl-vs-ind-2nd-test-india-tour-of-sri-lanka-2017",
    "type": "html",
    "size": 119362
  },
  {
    "filePath": "http://gc.kis.v2.scr.kaspersky-labs.com/EAA2612E-9291-A04E-A659-D0B272EEC835/main.js",
    "type": "script",
    "size": 104685
  },
  {
    "filePath": "http://i.cricketcb.com/statics/site/images/cbz-logo.png",
    "type": "image",
    "size": 0
  }
]

因为对象是可变的,所以 ngOnChange() 没有被调用。 发生这种情况是因为 ngOnChange() 它仅在参数实例更改时触发(而不是其中一个属性)。

您可以阅读更多相关信息 here

您可以利用不可变对象。这意味着该对象无法更改。有一个名为 immutable.js by facebook.

的很棒的图书馆

您也可以使用 Object.assign()。当您使用它时,您正在创建对象的新实例(而不是更改引用)。

长话短说,

  constructor(private harFileServiceService:HarFileServiceService) { }

  ngOnInit() {
  }
  filterData:Object = {};
  changeListener(event:any){
    var file = event.target.files[0];
    var myReader = new FileReader();
    var harFile = this.harFileServiceService;
    myReader.onload = (e:any)=>{
      var jsonData = JSON.parse(e.target.result);
      harFile.render(jsonData);
      this.filterData = Object.assign({},harFile.responseFileData);
    }
    // console.log(file);
    myReader.readAsText(file);
  }
}

在上面的示例中,我使用了 Object.assign()。此外,我稍微更改了语法并使用了 ecmascript arrow function

或者使用lodash cloneDeep改变参考

this.filterData = _.cloneDeep(harFile.responseFileData);