Creé una aplicación Angular 2 que contiene un componente cuyo elemento HTML intento colocar en relación con el de otro componente. Para calcular las coordenadas exactas, necesito saber el ancho y la altura de mi propio elemento tal como lo muestra el navegador.
Estoy usando window.getComputedStyle(this.elementRef.nativeElement) para obtener esas propiedades. Noté que, a medida que se representa la página, las propiedades siguen cambiando hasta que finaliza la representación de la página. Para informarme sobre cualquier cambio y ajustar el posicionamiento, verifico los valores en un método ngAfterViewChecked de mi componente.
Sin embargo , parece que no se llama a ngAfterViewChecked cuando la representación conduce a nuevas propiedades de estilo calculadas, ya que descubrí que mi gancho ya no se llama, aunque las propiedades de estilo calculadas todavía están cambiando. Supongo que el marco Angular no está diseñado para detectar tal cambio.
Mi primer intento fue implementar el gancho ngDoCheck , pero parece que este tampoco se llama después de un tiempo y antes de que la propiedad de estilo calculado tenga su valor final. Supongo que todavía no entiendo completamente cuándo se pretende llamar exactamente a este gancho.
Finalmente descubrí que, si implemento una función setTimeout en ngAfterViewChecked , esto lleva a que se vuelva a llamar a este mismo enlace más tarde, incluso si paso solo una función ficticia como:
setTimeout(() => {}, 500); Pero, francamente, no entiendo por qué esto es así. ¿Puede alguien explicarme la conexión entre setTimeout y el ngAfterViewChecked ?
Y si bien esto parece ser una solución un tanto sucia: ¿Cuál es la forma 'Angular' adecuada para detectar y manejar un cambio en los atributos de estilo calculados?
Extracto del código:
export class MyComponent implements OnInit, AfterViewChecked { private cssWidth: number; private cssHeight: number; constructor(private elementRef: ElementRef, private renderer: Renderer2) { } ngAfterViewChecked() { console.log("ngAfterViewChecked"); this.updateView(); } public updateView() { const sizeX = parseFloat(window.getComputedStyle(this.elementRef.nativeElement).width) || 0; const sizeY = parseFloat(window.getComputedStyle(this.elementRef.nativeElement.height) || 0; if (sizeX === this.cssWidth && sizeY === this.cssHeight) { // no change return; } console.log("Change detected!"); // TODO Does not work without this dummy timeout function (else no more changes detected) - why so?? setTimeout(() => {}, 500); [.. doing the positioning here ..] }Consulte el diagrama superior aquí para ver el diagrama del ciclo de vida. Si su gancho en doCheck no funciona, AfterViewChecked tampoco funcionará ya que doCheck inicia AfterViewChecked.
Cada vez que se completa un proceso asíncrono, se produce otra ronda de doCheck. Eso llamaría a AfterViewChecked, y eso llamaría a su función updateView. SetTimout() es un proceso asíncrono. Sospecho que el código anterior se repetiría infinitamente como está.
Creo que lo que desea es que el componente principal de lo que ha mostrado aquí use ngAfterViewChecked() y que llame a updateView(). Ese tema se explora aquí .
La forma angular de hacer que dos componentes funcionen juntos es tener un componente principal que pueda comunicar los cambios entre los componentes secundarios, ya que el componente principal es el contexto que puede ver los eventos que ocurren en los elementos secundarios.
La solución que personalmente usaría sería un EventEmitter, en el componente que no se muestra, en la función ngOnInit(). Informaría al padre que está inicializado. Luego, en el componente principal, tenga una llamada de función que ocurra en el evento emitido que le dice al componente secundario que tiene aquí para actualizar la Vista.
En Vanilla JavaScript podrías usar:
y activa tu propia función cuando se realiza un cambio de DOM.
MutationObserver proporciona a los desarrolladores una forma de reaccionar a los cambios en un DOM. Está diseñado como reemplazo de los eventos de mutación definidos en la especificación de eventos DOM3.
¿Por qué no se llama a ngAfterViewChecked cuando la representación conduce a nuevas propiedades de estilo calculadas?
El framework Angular no detecta cambios en el estilo calculado de los elementos DOM, al menos no cuando son causados por el motor de renderizado del navegador. En consecuencia, el gancho ngAfterViewChecked no se llamará en tales casos.
¿Por qué funciona cuando se usa setTimeout?
Como se explica en la respuesta de Michael Palmer, setTimeout hace que Angular se dé cuenta de un proceso asíncrono que podría causar un cambio. Por lo tanto, se llama al ngAfterViewChecked después de que se haya realizado la función de tiempo de espera. Angular no intenta verificar qué se hace exactamente en la función setTimeout y si esto es algo que realmente afecta la vista. Obviamente, esto sería bastante difícil de implementar y probablemente no valga la pena el esfuerzo. En cambio, Angular llama al gancho ngAfterViewChecked en caso de que algo haya sucedido en el proceso asincrónico que afecte la vista.
¿Cuál es la forma angular de escuchar los cambios de estilo calculados?
Parece que no hay otra forma que usar setTimeout para observar los cambios en el estilo calculado de los elementos DOM.