strategy onpush force detector detectchanges change typescript angular angular2-changedetection

typescript - onpush - detectchanges() angular



¿Cómo desencadenar la detección de cambios en Angular2? (3)

No estoy seguro de si es mejor. Hay un par de otras formas en que puedo pensar.

Usando NgZone

Puede inyectar NgZone y ejecutar el método de ejecución con una devolución de llamada:

NgZone.run(()=>this.currentUser.next(user));

Usando setTimeout

setTimeout activará la detección de cambios de forma automática:

setTimeout(()=>this.currentUser.next(user));

Esta pregunta ya tiene una respuesta aquí:

Estoy creando un servicio de Facebook que llama a la API de JavaScript de Facebook y me pregunto cómo implementar mejor la detección de cambios cuando mis valores se actualicen.

Tengo un UserService que tiene una propiedad currentUser que es un BehaviorSubject:

currentUser: Subject<User> = new BehaviorSubject<User>(new User(null));

Y cuando quiero actualizar al usuario en respuesta a la javascript SDK de Facebook que me dice que el usuario ha iniciado o cerrado sesión, lo actualizo y necesito llamar a tick() en un ApplicationRef :

updateUser(user: User) { console.log(''UserService.updateUser:'', user); this.currentUser.next(user); this.appRef.tick(); // UI does not update without this } constructor(facebook: Facebook) { this.facebook.facebookEvents.filter(x => x != null && x.eventName == ''auth.authResponseChange'') .subscribe((event) => { this.updateUser(new User(event.data)); } }

En mi componente, almaceno el ''usuario actual'' del servicio del usuario en el constructor y me uno a la propiedad del valor:

<h2>Logged into Facebook as {{currentUser.value.name}}</h2> <p>Is this you? &nbsp; <img src="{{currentUser.value.profilePicUrl}}"></p>

¿Estoy haciendo algo mal? ¿Hay una manera mejor que tener que llamar a ApplicationRef.tick () después de un cambio desencadenado desde una biblioteca externa?

Editar

Intenté usar NgZone y eso no funciona, usando un evento diferente que devuelve publicaciones en un feed a medida que el servicio las publica a través de ellas:

constructor(userService: UserService, private ref: ApplicationRef, private zone: NgZone) ... this.postsSubject.subscribe((post) => { this.zone.runOutsideAngular(() => { // doesn''t do anything this.posts.push(post); console.log(''postsSubject POST, count is '', this.posts.length); ref.tick(); // required to update bindings }); }

La consola muestra el incremento de recuento, pero el enlace html {{posts.length}} solo se actualiza si agrego la llamada ref.tick() ...

Creo que vi en algún lugar que puedes hacer ''entradas'' disponibles para cualquier componente del componente de la aplicación de nivel superior, que podría ser el camino a seguir para el usuario que ha iniciado sesión, pero no para otras llamadas como obtener publicaciones en un feed ...


¿Estoy haciendo algo mal? ¿Hay una manera mejor que tener que llamar a ApplicationRef.tick() después de un cambio desencadenado desde una biblioteca externa?

Depende. Si llamas a las API de Facebook fuera de Angular (es decir, registras controladores de eventos asincrónicos fuera de Angular), entonces necesitarás ejecutar manualmente la detección de cambios como parte del manejo de cualquier evento. Tu también puedes

  • NgZone y luego run() en ese objeto, que ejecutará la función pasada (devolución de llamada) dentro de la zona angular y luego llamará automáticamente a ApplicationRef().tick() , que ejecutará la detección de cambios para toda la aplicación, o
  • inyecte ApplicationRef y llame a tick() usted mismo, o
  • ChangeDetectorRef y llame a detectChanges() usted mismo: esto solo ejecutará la detección de cambios en el componente uno y sus hijos.

Tenga en cuenta que si inyecta NgZone , no desea usar runOutsideAngular() . Eso ejecutará la función pasada (devolución de llamada) fuera de la zona angular, y no llamará a ApplicationRef().tick() , por lo que la detección de cambios no se ejecutará.

Si llama a las API de Facebook dentro de Angular, es posible que pueda evitar todo lo anterior, porque entonces Angular (mediante su uso de Zone.js) debe aplicar un parche monofónico a las llamadas a eventos asincrónicos. Luego, cuando se active su evento, se llamará automáticamente a ApplicationRef.tick() . Consulte https://.com/a/34593821/215945 para obtener más información sobre este enfoque.


¿Podría darnos la forma de inicializar el proveedor de Facebook y su servicio en su componente?

Opción 1

Su comportamiento me hace cambiar que el código de Facebook se está ejecutando fuera de una zona angular, por lo que la detección de cambio angular no se ejecuta cuando se activa un evento. Tú

También podría ejecutar manualmente la detección de cambios:

import { Component, ChangeDetectorRef } from ''angular2/core''; @Component({ (...) }) export class MyComponent { constructor(private cdr:ChangeDetectorRef) { } someMethod() { this.cdr.detectChanges(); } }

Vea estas preguntas:

Opcion 2

Quizás su evento se currentUser antes de que el componente registre una devolución de llamada en el sujeto currentUser . En este caso, podría desencadenar el evento más tarde ...