Angular Universal - timeout should not be used

痴心易碎 提交于 2020-12-13 04:47:05

问题


so I have been trying to convert my application into angular universal, and for the most part it has been fine. But I read some "gotchas" earlier: https://github.com/onespeed-articles/angular-universal-gotchas

It suggests that I should not be using timeout which is annoying, because in angularjs you used it to make things fire after a view was rendered so you could be sure that dimensions of elements were correct, etc.

I have also read that it still persists in angular 6 so I have this directive:

import { Directive, ElementRef, AfterViewInit, Input, HostListener } from '@angular/core';

@Directive({
  selector: '[pyb-button-group]'
})
export class ButtonGroupDirective implements AfterViewInit {
  @Input() className: string;

  @HostListener('window:resize', ['$event'])
  onResize() {
    let resize = this.resize;
    let element = this.element;
    let className = this.className;

    setTimeout(function () {
      resize(element, className);
    }, 500);
  }

  constructor(private element: ElementRef) {
  }

  ngAfterViewInit() {
    this.resize(this.element, this.className);
  }

  resize(nativeElement, className) {
    let elements = nativeElement.nativeElement.getElementsByClassName(className || 'btn-choice');
    let headerHeight = 0;

    for (var i = 0; i < elements.length; i++) {
      let element = elements[i];
      let header = element.getElementsByClassName('header');

      if (!header.length) return;

      header = header[0];
      header.style.height = 'auto'; // Reset when resizing the window

      let height = header.offsetHeight;
      if (height > headerHeight) headerHeight = height;
    }

    for (var i = 0; i < elements.length; i++) {
      let element = elements[i];
      let header = element.getElementsByClassName('header');

      if (!header.length) return;

      header = header[0];
      header.style.height = headerHeight + 'px';
    }
  }
}

When the browser resizes, it waits for .5 of a second before it tries to resize the button group. If this is bad practice, what should I use instead?


回答1:


When the browser resizes, it waits for .5 of a second before it tries to resize the button group. If this is bad practice, what should I use instead?

You are delaying every resize event. Generally, you want to debounce and handle only one event every 500ms. This can be done using an observable, but make sure to unsubscribe when the component is destroyed.

observableFromEvent(window, 'resize')
  .pipe(debounceTime(500))
  .subscribe(() => this.resize(this.element, this.className))

Also @HostListener() never fires events during server-side rendering. There is no DOM on the server to trigger window resize events.

  setTimeout(function () {
      resize(element, className);
  }, 500);

The setTimeout global function that you are using here has a different function signature in NodeJS. When you run the application in Angular Universe it runs inside NodeJS to generate the HTML before it goes to the web browser. setTimeout returns a number on web browsers but returns a resource handle in NodeJS.

If you're going to run your application in Angular Universal then it means you're writing source code that is decoupled from the web browser. That means no direct manipulation of the DOM, no global variables and no global window variable.




回答2:


You want that code to run in browser not in server. The link you provided gives you the solution:

 if (isPlatformBrowser(this.platformId)) {
      //your setTimeout here
  }


来源:https://stackoverflow.com/questions/53787940/angular-universal-timeout-should-not-be-used

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!