In Angular 1 I have written a custom directive ("repeater-ready") to use with ng-repeat
to invoke a callback method when the iteration has been completed:
if ($scope.$last === true)
{
$timeout(() =>
{
$scope.$parent.$parent.$eval(someCallbackMethod);
});
}
Usage in markup:
<li ng-repeat="item in vm.Items track by item.Identifier"
repeater-ready="vm.CallThisWhenNgRepeatHasFinished()">
How can I achieve a similar functionality with ngFor
in Angular 2?
You can use @ViewChildren for that purpose
@Component({
selector: 'my-app',
template: `
<ul *ngIf="!isHidden">
<li #allTheseThings *ngFor="let i of items; let last = last">{{i}}</li>
</ul>
<br>
<button (click)="items.push('another')">Add Another</button>
<button (click)="isHidden = !isHidden">{{isHidden ? 'Show' : 'Hide'}}</button>
`,
})
export class App {
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
@ViewChildren('allTheseThings') things: QueryList<any>;
ngAfterViewInit() {
this.things.changes.subscribe(t => {
this.ngForRendred();
})
}
ngForRendred() {
console.log('NgFor is Rendered');
}
}
origional Answer is here https://stackoverflow.com/a/37088348/5700401
You can use something like this (ngFor local variables):
<li *ngFor="#item in Items; #last = last" [ready]="last ? false : true">
Then you can Intercept input property changes with a setter
@Input()
set ready(isReady: boolean) {
if (isReady) someCallbackMethod();
}
For me works in Angular2 using Typescript.
<li *ngFor="let item in Items; let last = last">
...
<span *ngIf="last">{{ngForCallback()}}</span>
</li>
Then you can handle using this function
public ngForCallback() {
...
}
The solution is quite trivial. If you need to know when ngFor
completes printing all the DOM elements to the browser window, do the following:
Add a placeholder for the content being printed:
<div *ngIf="!contentPrinted">Rendering content...</div>
Create a container with display: none
for the content. When all items are printed, do display: block
. contentPrinted
is a component flag property, which defaults to false
:
<ul [class.visible]="contentPrinted">
...items
</ul>
Add onContentPrinted()
to the component, which disables itself after ngFor
completes:
onContentPrinted() {
this.contentPrinted = true;
this.changeDetector.detectChanges();
}
And don't forget to use ChangeDetectorRef
to avoid ExpressionChangedAfterItHasBeenCheckedError
.
last
valueDeclare last
variable on ngFor
. Use it inside li
to run a method when this item is the last one:
<li *ngFor="let item of items; let last = last">
...
<ng-container *ngIf="last && !contentPrinted">
{{ onContentPrinted() }}
</ng-container>
<li>
contentPrinted
component flag property to run onContentPrinted()
only once.ng-container
to make no impact on the layout.Instead of [ready], use [attr.ready] like below
<li *ngFor="#item in Items; #last = last" [attr.ready]="last ? false : true">
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With