Angular6:外部js库和绑定问题
Angular 6 : external js library and binding problem
在我的应用程序中我加载了一个外部库"braintree.js"...一切正常,但有一个我无法理解的奇怪行为。
在我的模板中,根据 var (regStep) 的值加载了一个 div 块:当我调用外部库时,即使 regStep 的值发生变化,模板也不会显示变化,如果我评论了对外部库的调用并更改了 regStep 的值,模板相应地更改。
我没有复制所有代码,但我保证声明了所有需要的变量。
我是Angular的新手,也许我失去了一些东西,但我真的不明白问题在哪里。
这些是涉及的文件:
component.html
<div *ngIf="regservice.regStep == 1">
<form (ngSubmit)="regservice.savePay();
...tags...
</form>
</div>
<div *ngIf="regservice.regStep == 2">
...tags...
</div>
regservice.ts
declare var braintree: any;
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class RegisterService {
constructor(public router: Router, private http: HttpClient) {}
public regStep = 1;
public savePay() : void {
let self = this;
let client = new braintree.api.Client({clientToken: this.bt_token});
client.tokenizeCard({
number: '',
expirationDate: '',
cvv : ''
}, function (err, nonce) {
if (nonce) {
console.log(nonce);
self.addPayment(nonce);
}
});
//this.addPayment('fake-valid-nonce');
//If I uncomment the above line and comment all the others everything works perfectly
}
private addPayment(nonce) : void {
this.http.post(this.apiUrl+'/bt-add-payment-method/',
{
payment_method_nonce: nonce,
billing_address_id: this.business.braintree_customer.id,
make_default: true
},
{
headers:{
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.token['access_token']
}}).subscribe( {
next : response => { console.log('RESPONSE ADD PYMNT : ',response); },
error: err => {this.handleErrors(err); },
complete: () => { this.forward(); },
});
}
private forward() {
switch (this.regStep) {
case 1 : {
this.regStep_value = 'Step 2 of 5';
this.regStep++;
}
break;
}
}
更新
甚至使用:
client.tokenizeCard({
number: '',
expirationDate: '',
cvv : ''
}, (err, nonce) => {
console.log(nonce);
this.addPayment(nonce);
});
问题仍然存在。模板保持阻塞到 STEP == 1 块。
如果我不调用 new braintree 和相关代码,一切正常。
在这两种情况下,我都可以看到 console.log RESPONSE ADD PYMNT,因此在这两种情况下都调用了 AddPayment 函数;在这两种情况下也调用前向函数。
在这两种情况下,我都可以看到 regStep 是 2,但是
如果我调用了 braintree,模板会保持之前的状态。
如果我没有调用 braintree,模板会随着 regStep 的变化而变化。
如果您想在回调中使用组件 variables/methods,更好的方法是使用 lambda (=>) 函数,而不是使用文字或匿名函数。在您的情况下,您可以使用以下内容:
(err, nonce) => {
if (nonce) {
console.log(nonce);
this.addPayment(nonce);
}
}
问题与退出 Angular 区域的异步函数有关。
这将解决问题:
client.tokenizeCard({
number: '',
expirationDate: '',
cvv : ''
}, (err, nonce) => {
this.zone.run(() => { //<=== added
console.log(nonce);
this.addPayment(nonce);
})
});
逻辑上你必须导入 NgZone
import { NgZone } from '@angular/core';
export class RegisterService {
constructor(private zone:NgZone ) {}
}
在我的应用程序中我加载了一个外部库"braintree.js"...一切正常,但有一个我无法理解的奇怪行为。
在我的模板中,根据 var (regStep) 的值加载了一个 div 块:当我调用外部库时,即使 regStep 的值发生变化,模板也不会显示变化,如果我评论了对外部库的调用并更改了 regStep 的值,模板相应地更改。
我没有复制所有代码,但我保证声明了所有需要的变量。
我是Angular的新手,也许我失去了一些东西,但我真的不明白问题在哪里。
这些是涉及的文件:
component.html
<div *ngIf="regservice.regStep == 1">
<form (ngSubmit)="regservice.savePay();
...tags...
</form>
</div>
<div *ngIf="regservice.regStep == 2">
...tags...
</div>
regservice.ts
declare var braintree: any;
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class RegisterService {
constructor(public router: Router, private http: HttpClient) {}
public regStep = 1;
public savePay() : void {
let self = this;
let client = new braintree.api.Client({clientToken: this.bt_token});
client.tokenizeCard({
number: '',
expirationDate: '',
cvv : ''
}, function (err, nonce) {
if (nonce) {
console.log(nonce);
self.addPayment(nonce);
}
});
//this.addPayment('fake-valid-nonce');
//If I uncomment the above line and comment all the others everything works perfectly
}
private addPayment(nonce) : void {
this.http.post(this.apiUrl+'/bt-add-payment-method/',
{
payment_method_nonce: nonce,
billing_address_id: this.business.braintree_customer.id,
make_default: true
},
{
headers:{
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.token['access_token']
}}).subscribe( {
next : response => { console.log('RESPONSE ADD PYMNT : ',response); },
error: err => {this.handleErrors(err); },
complete: () => { this.forward(); },
});
}
private forward() {
switch (this.regStep) {
case 1 : {
this.regStep_value = 'Step 2 of 5';
this.regStep++;
}
break;
}
}
更新
甚至使用:
client.tokenizeCard({
number: '',
expirationDate: '',
cvv : ''
}, (err, nonce) => {
console.log(nonce);
this.addPayment(nonce);
});
问题仍然存在。模板保持阻塞到 STEP == 1 块。
如果我不调用 new braintree 和相关代码,一切正常。
在这两种情况下,我都可以看到 console.log RESPONSE ADD PYMNT,因此在这两种情况下都调用了 AddPayment 函数;在这两种情况下也调用前向函数。
在这两种情况下,我都可以看到 regStep 是 2,但是
如果我调用了 braintree,模板会保持之前的状态。
如果我没有调用 braintree,模板会随着 regStep 的变化而变化。
如果您想在回调中使用组件 variables/methods,更好的方法是使用 lambda (=>) 函数,而不是使用文字或匿名函数。在您的情况下,您可以使用以下内容:
(err, nonce) => {
if (nonce) {
console.log(nonce);
this.addPayment(nonce);
}
}
问题与退出 Angular 区域的异步函数有关。
这将解决问题:
client.tokenizeCard({
number: '',
expirationDate: '',
cvv : ''
}, (err, nonce) => {
this.zone.run(() => { //<=== added
console.log(nonce);
this.addPayment(nonce);
})
});
逻辑上你必须导入 NgZone
import { NgZone } from '@angular/core';
export class RegisterService {
constructor(private zone:NgZone ) {}
}