По-перше, зауважте, що цей виняток буде викинуто лише тоді, коли ви запускаєте додаток у режимі розробки (що за замовчуванням є випадком бета-0). Якщо ви зателефонуєте enableProdMode()
під час завантаження програми, він не буде кинутий ( див. оновлений планк ).
По-друге, не робіть цього, тому що цей виняток кидається з поважних причин: Якщо коротко, коли в режимі розробки кожен раунд виявлення змін супроводжується негайно другим раундом, який підтверджує, що прив'язки не змінилися з кінця першого, оскільки це вказувало б на те, що зміни викликаються самим виявленням змін.
У вашому планку прив'язка {{message}}
змінюється вашим викликом до setMessage()
, що відбувається в ngAfterViewInit
гачку, що відбувається як частина початкової черги виявлення змін. Це саме по собі не є проблематичним - проблема полягає в тому, що setMessage()
змінюється прив'язка, але не викликає новий раунд виявлення змін, що означає, що ця зміна не буде виявлена, поки якийсь майбутній раунд виявлення змін не буде запущений десь в іншому місці.
Винос: все, що змінює прив'язку, потрібно викликати раунд виявлення змін, коли це відбувається.
Оновіть у відповідь на всі запити приклад того, як це зробити : @ рішення Tycho працює, як це вказували три методи у відповіді @MarkRajcok. Але, чесно кажучи, всі вони відчувають мене некрасиво і не так, як той тип хакків, до яких ми звикли спиратися в ng1.
Безумовно, бувають випадкові коли ці хаки доречні, але якщо ви використовуєте їх що-небудь більше, ніж дуже періодично, це знак того, що ви боретеся з рамками, а не повністю сприймаєте її реакційну природу.
ІМХО, більш ідіоматичний, "кутовий шлях2" для підходу до цього - це щось за напрямками: ( планк )
@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
помилку, пояснює поведінку дуже детально.