ngOnChange() 在 angular2 中第二次不起作用



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

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

过滤器数据是一个对象。

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

如何解决这个问题?

har-file-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-file-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'] = '';
}
}
}

在这里更改

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()仅在参数实例更改时触发(而不是它的属性之一)。

您可以在此处阅读更多相关信息

您可以利用不可变的对象。这意味着对象无法更改。Facebook上有一个名为immutable.js的伟大库。

您也可以使用 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 箭头函数。

或者使用lodash克隆深度来更改引用

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

ngOnChanges在具有相同引用时不会检测到对象更改,解决方案是每次创建一个新的对象引用:

const object = Object.assign({}, oldObject)

最新更新