Ideally I would need to reload / rerender my component\'s template but if there is a better way to do this I will gladly implement it.
Desired behavior:
I finally got it working!
So, my problem was:
When the new HTML elements are generated (with *ngIf) they don't get displayed because they don't get processed the same way as the other menu elements do.
So I asked how to reload or re-render the template with all the 'new' elements... But I did not find where to reload a component or a component's template. As instead, I applied the logic that process the menu to my updated template.
(If you want the short story version, go at the bottom and read the Summary)
So, I dived into my template's deepest logic and created a directive to render the menu:
MenuDirective (directive)
@Directive({
selector: '[menuDirective]'
})
export class MenuDirective implements OnInit, AfterContentInit {
constructor(private menu: ElementRef,
private router: Router,
public layoutService: LayoutService) {
this.$menu = $(this.menu.nativeElement);
}
// A lot of boring rendering of layout
ngAfterContentInit() {
this.renderSubMenus(this.$menu);
}
renderSubMenus(menuElement) {
menuElement.find('li:has(> ul)').each((i, li) => {
let $menuItem = $(li);
let $a = $menuItem.find('>a');
let sign = $('');
$a.on('click', (e) => {
this.toggle($menuItem);
e.stopPropagation();
return false;
}).append(sign);
});
}
}
So here I create the menu directive that renders the layout of the menu according to the existing html elements. And, as you can see, I isolated the behavior that processes the menu elements adding the + icon, creating the submenu feature, etc...: renderSubMenus().
How does renderSubMenus() behave:
It loops through the DOM elements of the nativeElement passed as parameter and applies the logic to display the menu in the correct way.
menu.html
And that would be how I build the menu.
Now let's see the IBOsNavigationElement component, that is included in the menu with the attribute [ibos-navigation-element].
IBOsNavigationElement (component)
@Component({
selector: '[ibos-navigation-element]',
template: `
`
})
export class IBOsNavigationElement implements OnInit, DoCheck {
private $menuElement: any;
private navigationList = [];
private menuRendered: boolean = false;
constructor(private navigationService: NavigationElementsService, private menuDirective: MenuDirective, private menuElement: ElementRef) {
this.$menuElement = $(this.menuElement.nativeElement);
this.navigationService.updateIBOsNavigation$.subscribe((navigationData) => {
this.navigationList.push(navigationData);
log.d('I received this Navigation Data:', JSON.stringify(this.navigationList));
}
);
}
ngOnInit() {
}
ngDoCheck() {
if (this.navigationList.length > 0 && !this.menuRendered) {
log.er('calling renderSubMenus()');
this.menuDirective.renderSubMenus(this.$menuElement.find('ul.renderMe'));
this.menuRendered = true;
}
}
}
Ok, so what have I done different here? Several things...
MenuDirective so I can call its renderSubMenus() method.ElementRef and find() to select the block of code that I want to send to this.menuDirective.renderSubMenus(). I find it through its class, see: this.$menuElement.find('ul.renderMe').ngDoCheck() method where I check if the list navigationList is populated and if I have already rendered this block of code (I had issues because was rendering too many times and I had like 6 + buttons: disaster).Summary:
To 'reload' the template:
ElementRef I get the portion of template that I want to 'reload'.ngDoCheck(). You can call that method whenever you want.*ngIf.So, technically, I did not reload the component. I applied to the component's template the same logic that would have been applied if I reloaded it.