I am a beginner with Angular, and i can't find proper solution for my problem.
I have a component containing table filled with list of items (each item in list is in another component), and there is third component containing filter. Filter contains multiple checkboxes and a filter button.
I send boolean array of checkboxes states from filterComponent through itemsListComponent to singleItemComponent and it works fine. My problem is changes detection. When I used NgDoCheck with differs it works always when I click at checkbox and filter button instead only filter button.
I tried NgOnChanges but it worked only once and then it didn't see any changes of values into array.
This is my SingleItemsComponent (I think you don't need others to help me solve this). Look at this and show me any example of solving this problem please.
import { Component, OnInit, OnChanges,ViewChild, AfterViewInit, Inject, Input, DoCheck, KeyValueDiffer, KeyValueDiffers, SimpleChanges, SimpleChange, ChangeDetectionStrategy, ChangeDetectorRef, IterableDiffers } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { MatTableDataSource, MatPaginator, MatSort, throwToolbarMixedModesError } from '@angular/material';
import { IPOLine } from 'src/app/models/po-line';
import { POLineService } from 'src/app/services/po-line.service';
@Component({
selector: 'app-po-lines-list',
templateUrl: './po-lines-list.component.html',
styleUrls: ['./po-lines-list.component.css'],
animations: [
trigger('detailExpand', [
state('collapsed', style({ height: '0px', minHeight: '0', display: 'none' })),
state('expanded', style({ height: '*' })),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
]),
],
})
export class POLinesListComponent implements OnInit, DoCheck{
isLogged = false;
login: string;
dataSource = new MatTableDataSource<IPOLine>();
expandedElement: IPOLine;
errorMessage: string;
response: any;
today = new Date(); // (1990, 0, 1);
isLoadingList = true;
differ: any;
@Input() sentData: boolean[];
_sentData = this.sentData;
ngDoCheck(){
var changes = this.differ.diff(this._sentData);
if (changes){
console.log('changes detected changes detected changes detected changes detected changes detected ');
}
else
console.log('changes not detected changes not detected changes not detected changes not detected ');
}
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
constructor(
//private cd: ChangeDetectorRef,
private differs: KeyValueDiffers,
private _POLineService: POLineService,
private activatedRoute: ActivatedRoute) {
this.differ = differs.find({}).create();
}
ngOnInit() {
// Assign the data to the data source for the table to render
this.login = this.activatedRoute.snapshot.paramMap.get('login');
this._POLineService.getUserPOLines(this.login)
.subscribe(data => {
this.dataSource.data = data;
},
error => {
this.errorMessage = <any>error;
this.isLoadingList = false;
}
,
() => {
// console.log('eee' + this.dataSource.data);
this.isLoadingList = false;
this.dataSource.data.forEach(x => x.isExpired = new Date(x.PromisedDate) < new Date() ? true : false);
}
);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
}
I'm sorry for the mess in a code but I tried so many things i don't even remember what was what. Thanks for any help.
FilterComponent.ts:
import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
@Component({
selector: 'app-filters',
templateUrl: './filters.component.html',
styleUrls: ['./filters.component.css']
})
export class FiltersComponent implements OnInit {
@Output() filterByClass = new EventEmitter();
filterByTTR = false;
filterByTBR = false;
filters:boolean[] = [];
constructor() { }
ngOnInit() {
}
log() {
if(!this.filterByTTR)
console.log('TTR not checked');
else
console.log('TTR checked');
if (!this.filterByTBR)
console.log('TBR not checked');
else
console.log('TBR checked');
this.filters[0] = this.filterByTTR;
this.filters[1] = this.filterByTBR;
this.filterByClass.emit(this.filters);
}
Part of FilterComponent.html:
<mat-card-content class="col">
<mat-checkbox [checked]="filterByTTR" (change)="filterByTTR = !filterByTTR">TTR</mat-checkbox>
<mat-checkbox [checked]="filterByTBR" (change)="filterByTBR = !filterByTBR">TBR</mat-checkbox>
<!-- <mat-checkbox [(ngModel)]="filterByTBR"ref-TBR>TBR</mat-checkbox> -->
<div class="d-flex justify-content-between">
<button mat-raised-button color="primary">Clear</button>
<button mat-raised-button (click)="log()" color="primary">Apply</button>
</div>
PoLinesCompoenent.ts:
import { Component, OnInit, NgModule, ViewChild, Input } from
'@angular/core';
@Component({
selector: 'app-po-lines',
templateUrl: './po-lines.component.html',
styleUrls: ['./po-lines.component.css']
})
export class POLinesComponent implements OnInit {
count: boolean[];
constructor() { }
ngOnInit(){}
displayCounter(count) {
console.log('first value is: ' + count[0] + ' second value is: ' + count[1]);
this.count = count;
}
PoLinesComponent.html:
<div class="container">
<div class="row">
<div class="side-bar col">
<app-filters (data)='displayCounter($event)'></app-filters>
</div>
<div class="content col">
<app-po-lines-list [sentData]="count"></app-po-lines-list>
</div>
</div>
</div>
You can use the setter with input to detect the changes if 'sentData` input is changed by the parent. The setter function will be called everytime the input changes from outside. For example you can do something like:
See this link for more details about input change detection : Intercept @Input property change in Angular Hope this helps.
If the value passed in input via parent is not a primitive type then angular wont detect the changes in that object and the setter wont be called in the child i.e.
POLinesListComponent
. For fixing this issue and getting your change detected, you can useObject.assign
function of javascript which will change the reference ofthis.count
thus triggering angular change detection. You can do something like the following in yourdisplayCounter
function:I have even created a stackblitz similar to your implementation in which the change is being detected properly and the value of new count is being logged to the console everytime filter is applied. Here Input Change Detection for Object