Reputation: 57
In my APP I've loaded an external library "braintree.js"... everything is correctly working, but there's a strange behaviour that I can't understand.
In my template a block of divs are loaded depending on the value of a var (regStep): when I call the external library, even if the value of regStep changes, the template doesn't show the changes, If I comment the call to the external library and change the value of regStep, template changes accordingly.
I haven't copied all the code,but I assure that all the needed variables are declared.
I'm pretty new to Angular,maybe I'm losing something, but I really do not understand where's the problem.
These are the involved files:
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;
}
}
UPDATE
Even using :
client.tokenizeCard({
number: '',
expirationDate: '',
cvv : ''
}, (err, nonce) => {
console.log(nonce);
this.addPayment(nonce);
});
Problem persists. Template remains blocked to STEP == 1 block.
If I do not call new braintree and related code, everything works.
In both cases I can see the console.log RESPONSE ADD PYMNT, so AddPayment function is in both cases called; also forward function is in both cases called.
In both cases I can see that regStep is 2, but
if i called braintree, template remains blocked to the previous state.
if i didn't call braintree, template changes as soon as regStep changes.
Upvotes: 1
Views: 275
Reputation: 57
Problem was related to an asynchronous function exiting the Angular zone.
This will resolve the issue:
client.tokenizeCard({
number: '',
expirationDate: '',
cvv : ''
}, (err, nonce) => {
this.zone.run(() => { //<=== added
console.log(nonce);
this.addPayment(nonce);
})
});
logically you have to import NgZone
import { NgZone } from '@angular/core';
export class RegisterService {
constructor(private zone:NgZone ) {}
}
Upvotes: 1
Reputation: 499
If you want to use the component variables/methods inside the callback, a better way is using a lambda (=>) function instead of using literal or anonymous functions. In your case, you may use the following:
(err, nonce) => {
if (nonce) {
console.log(nonce);
this.addPayment(nonce);
}
}
Upvotes: 0