Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TemplateRef and change detection

Recently I started to actively use templates to customize my UI components. I also use OnPush change detection strategy to optimize performance. It all goes well if I pass template onto the nested component. User actions trigger change detection in the nested component and it travels up to the original component where template is defined and change detection triggers there as well, updating the template and whatever other logic I have in there.

However if I try to make, say popup/alert/tooltip functionality with template — I start to pass TemplateRef up the tree into popup host component. Therefore if I perform any action on it — change detection will not reach the origin of the template. So lets asume I have this component in pseudo code:

<p>Your balance: {{balance}}</p>

<ng-template #popup>
  Your balance: {{balance}}
  <button (click)="balance -= 100">Withdraw</button>
</ng-template>

If I pass this template to the popup host component, which is located up in the DOM tree:

<main-component>
   <balance></balance>
</main-component>
<popup-host></popup-host>

Then clicking "Withdraw" will not trigger change detection in the origin component. {{balance}} inside the template in the popup will get updated, but although it is the same variable as in the origin balance component — balance will not know about this change untill something has triggered its change detection.

Can anybody share an idea of how they would approach this issue? OnPush and templates are very powerful tools but I cannot figure out the way to combine them together in such case, since TemplateRef does not have any reference to its origin component, only its DOM comment node.

I could force passing ChangeDetectorRef of the original component to the popup service but I would want to come up with a solution to the arbitrary case like that. Any suggestions will be greatly appreciated!

like image 732
waterplea Avatar asked Oct 17 '22 19:10

waterplea


1 Answers

Well, what I ended up doing is create a directive:

<ng-template myDirective>
  Content
</ng-template>

And in that directive I inject TemplateRef and ChangeDetectorRef. This way instead of giving TemplateRef to where I needed that template, I give ViewChild(MyDirective) and use myDirective.template as template and call markForCheck() on that change detector on ngAfterViewChecked() of that component.

like image 152
waterplea Avatar answered Nov 04 '22 19:11

waterplea