Primero, tenga en cuenta que esta excepción solo se lanzará cuando esté ejecutando su aplicación en modo de desarrollo (que es el caso de forma predeterminada a partir de beta-0): si llama enableProdMode()
al arrancar la aplicación, no se lanzará ( consulte plunk actualizado ).
En segundo lugar, no haga eso porque esta excepción se está lanzando por una buena razón: en resumen, cuando está en modo dev, cada ronda de detección de cambio es seguida inmediatamente por una segunda ronda que verifica que no hayan cambiado los enlaces desde el final de la primera, ya que esto indicaría que los cambios están siendo causados por la detección de cambios en sí.
En su plunk, el enlace {{message}}
se cambia por su llamada a setMessage()
, que ocurre en el ngAfterViewInit
gancho, que ocurre como parte del turno de detección de cambio inicial. Sin embargo, eso en sí mismo no es problemático: el problema es que setMessage()
cambia el enlace pero no desencadena una nueva ronda de detección de cambios, lo que significa que este cambio no se detectará hasta que se desencadene una futura ronda de detección de cambios en otro lugar.
La conclusión: todo lo que cambie un enlace debe activar una ronda de detección de cambio cuando lo haga.
Actualice en respuesta a todas las solicitudes de un ejemplo de cómo hacerlo : la solución de @ Tycho funciona, al igual que los tres métodos en la respuesta que señaló @MarkRajcok. Pero, francamente, todos se sienten feos y equivocados para mí, como el tipo de trucos a los que nos acostumbramos en ng1.
Para estar seguro, hay ocasionales circunstancias en las que estos cortes son apropiadas, pero si usted está utilizando en cualquier cosa más que una muy forma ocasional, es una señal de que estás luchando contra el marco en lugar de abrazar plenamente su naturaleza reactiva.
En mi humilde opinión, una manera más idiomática, "Angular2" de abordar esto es algo así como: ( plunk )
@Component({
selector: 'my-app',
template: `<div>I'm {{message | async}} </div>`
})
export class App {
message:Subject<string> = new BehaviorSubject('loading :(');
ngAfterViewInit() {
this.message.next('all done loading :)')
}
}
ExpressionChangedAfterItHasBeenCheckedError
error explica el comportamiento con gran detalle.