Electron + Angular 4 = 两种方式的数据绑定不起作用
Electron + Angular 4 = two ways data binding not working
每次我们想要更新 UI 时,我们都被迫使用 zone.run() 方法,这不是一种选择,因为它不直观并迫使开发人员添加更多重复代码。
这里是我们的主要依赖:
"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",
这里是我们 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>
这里是systemjs.config.js相关部分
(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'
},
现在 Chrome 开发控制台内没有错误报告,但有些问题无法正常工作:
- 没有 http 404,因此所有 js 文件都按预期顺序正确下载(从 index.html 开始,然后是脚本标签引用的所有 .js,然后是 system.config.js 引用的所有 .js 文件)
- 数据绑定的 2 种方式不起作用,我们被迫在组件构造函数中注入 zone.js 并使用它的 运行() 方法强制更新 UI
其他相关来源是组件和 html
组件及其模板(当我们在字段中键入时,我们期望 form.value | json显示'live'输入文本的内容)
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>
终于找到了解决办法。这与我最初怀疑的 index.html 内的订单或进口或标签无关。
这与This issue causing angular to drop out the zone有关。所以解决方案是像问题解决方法中提到的那样使用 Zone.current.wrap...
每次我们想要更新 UI 时,我们都被迫使用 zone.run() 方法,这不是一种选择,因为它不直观并迫使开发人员添加更多重复代码。
这里是我们的主要依赖:
"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",
这里是我们 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>
这里是systemjs.config.js相关部分
(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'
},
现在 Chrome 开发控制台内没有错误报告,但有些问题无法正常工作:
- 没有 http 404,因此所有 js 文件都按预期顺序正确下载(从 index.html 开始,然后是脚本标签引用的所有 .js,然后是 system.config.js 引用的所有 .js 文件)
- 数据绑定的 2 种方式不起作用,我们被迫在组件构造函数中注入 zone.js 并使用它的 运行() 方法强制更新 UI
其他相关来源是组件和 html
组件及其模板(当我们在字段中键入时,我们期望 form.value | json显示'live'输入文本的内容)
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>
终于找到了解决办法。这与我最初怀疑的 index.html 内的订单或进口或标签无关。 这与This issue causing angular to drop out the zone有关。所以解决方案是像问题解决方法中提到的那样使用 Zone.current.wrap...