Each time we want to update the UI we are forced to use the zone.run() method and this in not an option since it's unintuitive and force devs to add more repetitive code.
Here our main dependencies:
"dependencies": {
"@angular/animations": "4.0.0",
"@angular/common": "4.0.0",
"@angular/compiler": "4.0.0",
"@angular/compiler-cli": "4.0.0",
"@angular/core": "4.0.0",
"@angular/forms": "4.0.0",
"@angular/http": "4.0.0",
"@angular/platform-browser": "4.0.0",
"@angular/platform-browser-dynamic": "4.0.0",
"@angular/platform-server": "4.0.0",
"@angular/router": "4.0.0",
"@angular/upgrade": "4.0.0",
"@types/electron": "^1.4.34",
Here a snippet of our index.html :
<!-- 1. Load libraries -->
<script src="../node_modules/zone.js/dist/zone.js"></script>
<script src="../node_modules/reflect-metadata/Reflect.js"></script>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
Here the systemjs.config.js relevant part
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': '../node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js',
'@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js',
// other libraries
'ng2-translate': 'npm:ng2-translate/bundles',
'rxjs': 'npm:rxjs',
'underscore.string': 'npm:underscore.string/dist',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
},
Now there is no error reported inside the Chrome dev console , but there are issues that are not working:
Other relevent sources are the component and the html
Component and it's template (as we type inside a field we expect the form.value | json to display 'live' the content of the input text)
import { Component, OnInit, NgZone } from '@angular/core';
import { Router } from '@angular/router';
import { AuthenticationService, ILoginAjaxResponse } from './service/authentication.service';
export class Credentials {
email: string;
password: string;
}
@Component({
selector: 'as-login',
templateUrl: 'app/login/login.component.html',
})
export class LoginComponent implements OnInit {
credentials = new Credentials();
constructor(
private authenticationService: AuthenticationService,
private router: Router,
private zone: NgZone) {
}
public ngOnInit() {
// Test A
// -------------------------------
// this is visible in UI text box
// this is visible in the UI {{credentials | json}} output
// this is NOT visible in the UI {{form.value | json}} output
this.credentials.email = 'john.doe@planet.com';
// Test B
// -------------------------------
// this is NOT visible in UI text box
// this is NOT visible in the UI {{credentials | json}} output
// this is NOT visible in the UI {{form.value | json}} output
setTimeout(() => {
this.credentials.email = '11111111@planet.com'
}, 3000);
// Test C
// -------------------------------
// this is visible in UI text box
// this is visible in the UI {{credentials | json}} output
// this is visible in the UI {{form.value | json}} output
setTimeout(() => {
this.zone.run(() => {
this.credentials.email = '22222222@planet.com'
});
}, 6000);
}
public onSubmit() {
this.authenticationService.login(this.credentials)
.subscribe((response) => this.handleResponse(response));
}
private handleResponse(response: ILoginAjaxResponse) {
this.router.navigateByUrl('spa/sync')
.catch((reason) => { console.log(reason); });
}
}
<p>Form:</p>
<pre>
{{ form.value | json }}
</pre>
<p>Model:</p>
<pre>
{{ credentials | json }}
</pre>
<form #form="ngForm" novalidate>
<input type="text" class="form-control"
name="email" [(ngModel)]="credentials.email">
<input type="password" class="form-control"
name="password" [(ngModel)]="credentials.password">
<input class="btn btn-lg btn-primary btn-block"
(click)="onSubmit()"
type="submit" value="Submit">
</form>
Finally found the fix. This has nothing to do with the order or imports or tags inside index.html as I was originaly suspecting. This is related to This issue causing angular to drop out the zone. So the solution was to use Zone.current.wrap like mentioned in the issue workaround...