Почему шаблон Angular 2 не обновляется при вызовах за пределами угловой зоны?
Я думал, что создам очень простую форму входа в систему с привязанными к компоненту свойствами имени пользователя и пароля, которая будет проходить через следующие шаги:
- Отправить учетные данные с вызовом fetch()
- ТОГДА получить содержимое JSON объекта результата Response
- ТОГДА проверьте этот контент для результата проверки на стороне сервера
Если учетные данные были неправильными, это изменило бы свойство компонента, которое сообщило бы Angular применить класс к входам имени пользователя и пароля, чтобы сделать их временно красными (используя setTimeout, чтобы изменить это обратно)
Проблема, с которой я столкнулся, состоит в том, что Angular не будет правильно применять класс, и я не был уверен, почему. Я решил создать упрощенный тестовый проект, чтобы сузить проблему, и в результате я добавил system-polyfills/when.js.
Этот код проходит через 1, 2, затем 3 и устанавливает его как в свойстве компонента, так и выводит его на консоль отладки. Angular корректно отображает свойство компонента, если не включен system-polyfill, в этом случае он остановится на 1 и никогда не изменит его на 2 или 3, даже если консоль показывает, что свойство фактически изменилось:
export class App {
private stateIndicator:string = "0";
public showState(state:string) {
console.log('State: ' + state);
this.stateIndicator = state;
}
public showFetchProblem() {
this.showState('1')
fetch('http://www.google.com/robots.txt',{mode:'no-cors'}).then((response:any) => {
this.showState('2')
response.text().then((value) => {
this.showState('3')
});
});
}
}
Я создал следующий Plunker, чтобы продемонстрировать это поведение: http://plnkr.co/edit/GR9U9fTctmkSGsPTySAI?p=preview
И да, очевидные решения:
- Не включайте system-polyfills или
- Вручную добавьте другой Polyfill Promise перед SystemJS, если вам это нужно
Но мне все еще любопытно, почему это происходит, и, надеюсь, кто-то может пролить свет на это (и, возможно, помочь решить основную проблему).
Изменить: оригинальное название этого было Why is Angular 2's template rendering misbehaving when using system-polyfills (when.js)
, Спасибо Тьерри и Гюнтеру за помощь и указание на то, что Angular 2 использует зоны здесь. Для тех, кто сталкивается с этим в будущем, вот две отличные статьи, которые объясняют зоны более подробно и улучшат ваше понимание этого сценария, если вы столкнетесь с ним:
2 ответа
Promise polyfill предоставляет пользовательскую реализацию Promise, которая, кажется, выполняется вне области Angular2 (то есть не в зоне).
Если вы выполняете свой код явно в зоне, управляемой Angular2 (с NgZone
класс), это работает, когда system-polyfill.js
файл включен.
Вот образец:
constructor(private zone:NgZone) {}
public showFetchProblem() {
this.showState('1')
this.zone.run(() => {
fetch('http://www.google.com/robots.txt',{mode:'no-cors'}).then((response:any) => {
this.showState('2')
response.text().then((value) => {
this.showState('3')
});
});
});
}
Смотрите соответствующий plunkr: http://plnkr.co/edit/EJgZKWVx6FURrelMEzN0?p=preview.
Обновить
Не уверен насчет объяснения больше, но обходной путь работает. Но я думаю, что есть другая проблема.
Смотри также https://github.com/angular/angular/issues/7792
оригинал
Я предполагаю, что проблема вызвана fetch
не залатан зоной Angulars
To work around make the code execute inside Angulars zone manually
export class App {
constructor(private zone:NgZone) {}
private stateIndicator:string = "0";
public showState(state:string) {
console.log('State: ' + state);
this.stateIndicator = state;
}
public showFetchProblem() {
this.showState('1')
fetch('http://www.google.com/robots.txt',{mode:'no-cors'}).then((response:any) => {
this.showState('2')
response.text().then((value) => {
this.zone.run(() => this.showState('3'));
});
});
}
}