Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 : Avoid DOM render on ngIf second time

Tags:

angular

I have one Tab control and there are two tabs in it. I have placed two Kendo Grid/Any component in that different tabs.

When I open/select the tab first time it render the related component/html in the DOM. To boost the performance I have placed ngIf on tabs to show only active tab html. So now Dom show only active tab html but now when I traverse to other tab and revisit previous tab it's component/content seems render again. I wants to stop this second time rendering.

Note: If I replace ngIf with hidden then it works as accepted but it cost to performance as so many watches and DOM connected with it.

Actually my main problem is that due to above issue when I navigate to tabs my grid scroll position set to top every time instead it should remain at same state

Below is the some part of the code which I have did.

If condition in tab content html(render only selected tab in DOM)

<div class="tab-heading-outer">
    <div class="tab-heading">
        <ul id="ulOpenedTabs" class="nav nav-tabs main-tabs" role="tablist">
            <li>                 
                <span class="ellipsis"> {{tab.Header}} </span>
            </li>
        </ul>
    </div>
</div>

<div class="tab-content" *ngIf="tab.IsSelected">
    <ng-content>
    <!--Html goes here-->
    </ng-content>
</div>
like image 247
Sandip - Frontend Developer Avatar asked Feb 12 '18 10:02

Sandip - Frontend Developer


2 Answers

If you really don't want to remove the component from DOM and re-render it when you open the tab, another solution could be this:

  • Hide the component with [hidden].
  • Remove the component from the change detection tree with ChangeDetectorRef.detach() when the tab is closed.
  • Add change detection back to the component with ChangeDetectorRef.reattach() when the tab is opened to get the newest data.

Depending on how your component is implemented, this could solve your performance issues. Especially if you rely heavily on Observables and the async Pipe (as you should), there should be no computation if the template is not checked for changes.

To quote the documentation for detach():

Imagine the data changes constantly, many times per second. For performance reasons, we want to check and update the list every five seconds. We can do that by detaching the component's change detector and doing a local check every five seconds.

You would do the same, only not time-based but based on whether the tab is open or not.

All you have to do is inject the ChangeDetectorRef in the component constructor and hook the change detection up to an @Input() property:

constructor(private changeDetector: ChangeDetectorRef) {}

@Input() set visible(visible: boolean) {
  if(!visible) {
    changeDetector.detach();
  } else {
    changeDetector.reattach();
  }
}

Now you can control whether the component gets new data or not by simply setting [visible]="false" or [visible]="true".

You can find another full example in the official documentation for the ChangeDetectorRef.

like image 54
magnattic Avatar answered Oct 17 '22 08:10

magnattic


Can you use [hidden]="condition" instead of *ngIf="condition"?

*ngIf when false will remove the element it's on and all of its children elements from the DOM.

Whereas when [hidden] is true the html is still in the DOM, but it is not visible on the screen to the user at the time until [hidden]="false";

like image 22
Chris Avatar answered Oct 17 '22 10:10

Chris