I have a parent component like this. So number of items in menu depends on model. And model changes.
<parent>
<menu>
<item *ngIf="model.info">
... some data
<item *ngIf="model.comments">
.... some data
<item *ngIf="model.attachments">
... some data
<item *ngIf="model.orders">
.... some data
</menu>
</parent>
Parent component:
export class Parent {
@Input() public model: any;
}
Where menu is a component itself using ng-content like this, I am creating menu based on menuItems count.
selector: 'menu',
template: ` <ul class="nav"
<li *ngFor="let item of items" [class.active]="item.active"
<a class="btn" (click)="menuItemClicked(item)"> </a>
</li>
</ul>
<div class="content">
<ng-content></ng-content>
</div>
`
export class MenuComponent {
@ContentChildren(MenuItem) items;
ngAfterContentInit() {
this.setActiveMenuItem();
}
public menuItemClicked(item) {
this.changeActiveItem(item)
}
private setActiveItem() {
const items = this.items.toArray();
const actives = this.items.filter(i => i.active);
if (!actives.length && items.length) {
items[0].active = true;
}
}
private changeActiveItem(item) {
const items = this.items.toArray();
items.forEach(i => i.active = false);
item.active = true;
}
}
Where a single menuItem itself is a component, that uses ng-content:
@Component({
selector: 'item',
template: `
<ng-content *ngIf="active"></ng-content>
`
})
export class MenuItemComponent {
@Input() active = false;
public setActive() {
this.active = true;
}
public setNotActive() {
this.active = false;
}
}
Parent component is used like this:
<app>
<parent *ngIf="model.displayMenu" [model]="model"></parent>
</app>
So it is created only once, and then model changes based on user actions (clicks. etc.)
Now what is the problem ? The problem is that suppose I have created a parent component. And in my usecase model changes. I know exactly when model changes, but the thing is that on that change I want always the first menu item to be active on that change.
My problem is that I am not able to use ngAfterViewInit hook, because the items are not already there. It takes some time for angular change detection to change that content. If I used ngAfterViewInit, the menu items are not updated in that hook yet. I do not want to use ngAfterViewChecked, because it constantly triggers change detection and causes performance issues (behind there is a constant stream change in model info).
Example: I have active 4th menu item and model changes. The next model has only 2 menu items, and I want the menu item smoothly to switch to 1st menu item. If I do not do this, then I get empty content.
How could this be solved?