New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

angular 4 and paypal express checkout #368

Closed
kodermax opened this Issue Jun 9, 2017 · 37 comments

Comments

@kodermax

kodermax commented Jun 9, 2017

How Can I integrate angular4 and paypal?

@bluepnume

This comment has been minimized.

Member

bluepnume commented Jun 14, 2017

Hi @kodermax -- don't currently have support for angular 4, but you can check here for progress:

krakenjs/zoid#23

In the mean time, you should be able to use the button with just a regular paypal.Button.render() somewhere in your angular controller, I'm sure.

@bluepnume bluepnume closed this Jun 14, 2017

@bluepnume bluepnume added this to Done in paypal-checkout Jun 19, 2017

@kodermax

This comment has been minimized.

kodermax commented Jun 27, 2017

What method should I use on Angular4?

@alaaeddinezammel

This comment has been minimized.

alaaeddinezammel commented Jul 28, 2017

any news ?

@bluepnume

This comment has been minimized.

Member

bluepnume commented Aug 3, 2017

Hi -- I don't have any official docs for this yet, but angular2+ support was just added to xcomponent, which powers paypal-checkout: https://medium.com/@harouny/introducing-xcomponent-support-for-angular-2-cb31a89f01 (thanks @harouny)

So you should be able to do something like:

import * as ngCore from '@angular/core';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app-component';

let PayPalButtonModule = paypal.Button.driver('angular2', ngCore);

@NgModule({
    imports: [ BrowserModule, PayPalButtonModule ],
    declarations: [ AppComponent ],
    bootstrap: [ AppComponent ]
})
export class AppModule {
    constructor () {
    }
}

Then in your template:

<paypal-button [props]="{ payment: payment, onAuthorize: onAuthorize }"></paypal-button>

I haven't personally tested the paypal button component with angular 2 yet, so please let me know if you see any issues.

@carlosost

This comment has been minimized.

carlosost commented Aug 14, 2017

Hello @bluepnume,

Any news about an specific documentation on how to use paypal-button on Angular2+?

Would be awesome to have something explaining the process since the "npm install paypal-checkout" to the use of the tag paypal-button.

I've tried the suggestion above, but I am getting an "Uncaught ReferenceError: paypal is not defined" on paypal.Button.driver....

Regards.

@bluepnume

This comment has been minimized.

Member

bluepnume commented Aug 14, 2017

I'll try to get to this soon. In the mean time did you add the checkout.js script somewhere on your page before referencing paypal?

<script src="https://www.paypalobjects.com/api/checkout.js"></script>
@carlosost

This comment has been minimized.

carlosost commented Aug 14, 2017

Thank you @bluepnume for your answer. It drove me a few steps ahead, but now I am not sure what to do next.

This is what I've done to get here:

  1. run 'npm install xcomponent'
  2. run 'npm instal paypal-checkout'
  3. add <script src="https://www.paypalobjects.com/api/checkout.js"></script> script to index.html
  4. add <paypal-button [props]="{ payment: payment, onAuthorize: onAuthorize }"></paypal-button> to the page I need the button to be rendered
  5. At app.module.ts, exported and imported (in NgModule imports list) a new Module
    declare const paypal:any; export const PayPalButtonModule = paypal.Button.driver('angular2', { Component, NgModule, ElementRef, NgZone });
  6. Add to the component (lets call it MyPayPalComponent.ts) I need to render the button:
    payment() { console.log('payment'); } onAuthorize() { console.log("onAuthorize"); }

And the button is being rendered, but what is the next step? How to, at MyPayPalComponent.ts, "overload" the functions payment, onAuthorize and on Cancel, to make everything work?

It is not your fault of course, but that is what I am talking about. As I am new with all this stuff of xcomponent, Angular, etc, I still need more complete instructions :-(.

Well.. I think I need to read once more all the documentation available.

Regards.

@bluepnume

This comment has been minimized.

Member

bluepnume commented Aug 16, 2017

How to, at MyPayPalComponent.ts, "overload" the functions payment, onAuthorize and on Cancel, to make everything work?

You should be able to implement these functions in the exact same way as in the examples at https://developer.paypal.com/demo/checkout/#/pattern/client -- there's nothing specific to Angular here.

But yep, will try to get a demo up for angular4 as soon as possible -- I'll reopen this issue in the mean time.

@bluepnume bluepnume reopened this Aug 16, 2017

@alaaeddinezammel

This comment has been minimized.

alaaeddinezammel commented Aug 18, 2017

@bluepnume i wish u put a demo with angular 4 those days

@srinivastamada

This comment has been minimized.

srinivastamada commented Aug 23, 2017

@carlosost You got any solution for PayPal

@bluepnume

This comment has been minimized.

Member

bluepnume commented Aug 29, 2017

@bluepnume bluepnume closed this Aug 29, 2017

@alaaeddinezammel

This comment has been minimized.

alaaeddinezammel commented Aug 30, 2017

im using angular 4

im getting an error in app.module when i put
paypal.Button.driver('angular2', ng.core) in ngModule import

im getting error

ERROR in C:/dev1/backup/admin-portal/src/app/app.module.ts (79,5): Cannot find name 'paypal'.

ERROR in C:/dev1/backup/admin-portal/src/app/app.module.ts (79,38): Cannot find name 'ng'.

how should i declare it in the ngModule or do i missed some imports ??? i ve added
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
in index.html
but nothing in app.module

@mjstecson

This comment has been minimized.

mjstecson commented Aug 31, 2017

@carlosost I followed your steps and did my own config for the paypal-button props.

in component.html:
<paypal-button [props]="paypalConfig"></paypal-button>

in component.ts:
paypalConfig = { env: 'sandbox', client: { sandbox: 'xxxxxxxxxx', production: 'xxxxxxxxxx' }, commit: true, payment: (data, actions) => { return actions.payment.create({ payment: {transactions: [{amount: {total: this.amount, currency: 'USD'}}]} }); }, onAuthorize: (data, actions) => { return actions.payment.execute().then(() => { /*show success*/ }); } };

Its working perfectly now but when I tried to do ng build --prod it returned an error:
ERROR in Error encountered resolving symbol values statically. Reference to a local (non-exported) symbol 'paypal'. Consider exporting the symbol (position 14:15 in the original .ts file), resolving symbol PayPalButtonModule in /../../../../src/app/app.module.ts, resolving symbol AppModule in /../../../../src/app/app.module.ts, resolving symbol AppModule in /../../../../src/app/app.module.ts

Does this also happen to you? If so, do you have a solution/workaround on this?

PS: The error also shows up when initially running ng serve but goes away when I edit something and it recompiles itself.

Regards.

@bluepnume

This comment has been minimized.

Member

bluepnume commented Aug 31, 2017

Could you do something like declare var paypal: any; ?

@mjstecson

This comment has been minimized.

mjstecson commented Aug 31, 2017

@bluepnume I believe your reply was for @alaaeddinezammel

On my case, I have

declare const paypal: any;

in my app.module.ts followed by

export const PayPalButtonModule = paypal.Button.driver('angular2', { Component, NgModule, ElementRef, NgZone });

Then imported PayPalButtonModule

@NgModule({
...
imports: [..., PayPalButtonModule],
...
})

PS. I'm also using angular-cli for compiling and building this.

Thanks.

@alaaeddinezammel

This comment has been minimized.

alaaeddinezammel commented Aug 31, 2017

image

image

that's awkward still not working guys @bluepnume @mjstecson

@mjstecson

This comment has been minimized.

mjstecson commented Sep 3, 2017

@alaaeddinezammel import Component, ElementRef and NgZone from @angular/core.

Just put them beside where you imported NgModule.

After that, it should fail to compile on the first ng serve, having the reference to a local non-exported symbol error, but will successfully compile when you save other changes.

It works perfectly in dev but when I try to build it for prod, it always fail on the non-exported error. Adding export in the declare const paypal: any line produces another error. Not sure on how to go about it. @bluepnume

@KevinShiCA

This comment has been minimized.

KevinShiCA commented Sep 3, 2017

@mjstecson After tinkering with this all day, I believe I have found a temporary solution.

Instead of exporting a PaypalButtonModule in the app.module and dealing with the failed AOT compilation, I had the following setup in the component wherein I used the paypal button.

Outside the component, in the same scope as the import statements:

declare let paypal: any;

Next, declare a class boolean to keep track of whether or not the button rendered:
private didRenderPaypal: boolean = false

Then, make a class method to manually load the paypal script and insert it into the DOM:
private loadPaypalScript(): Promise<any> { this.didRenderPaypal = true; return new Promise((resolve, reject) => { const scriptElement = document.createElement('script'); scriptElement.src = 'https://www.paypalobjects.com/api/checkout.js'; scriptElement.onload = resolve; document.body.appendChild(scriptElement); }); }

In your component template, insert <div id="paypal-btn"></div> wherever you want the button.

Finally, in ngAfterViewChecked (remember to import AfterViewChecked and implement it):

ngAfterViewChecked() { if(!this.didRenderPaypal) { this.loadPaypalScript().then(() => { paypal.Button.render(this.paypalConfig, '#paypal-btn'); }); } }

Let me know if this works for you.
P.S. Sorry for bad formatting, first time commenting

@harouny

This comment has been minimized.

harouny commented Sep 3, 2017

I haven't had time to try this but I have seen this AOT issue before. Could you guys try something like this in app.module.ts:

declare let paypal: any;

then:

export { paypal };

or:

export { paypalButton: paypal.Button };

and see if that fix the issue.

@mjstecson

This comment has been minimized.

mjstecson commented Sep 5, 2017

@harouny export paypal; and export paypalButton returns a 'Declaration or statement expected' errror.

@keeperofchem Your workaround works! 😄 Thanks for looking into this! 😄

@harouny

This comment has been minimized.

harouny commented Sep 5, 2017

@mjstecson
Sorry my bad. I meant:

export { paypal };
@harouny

This comment has been minimized.

harouny commented Sep 5, 2017

@mjstecson
I have updated my comment, and will try it myself now

@harouny

This comment has been minimized.

harouny commented Sep 5, 2017

@mjstecson Sorry my proposal doesn't work. Paypal.Button angular2 component currently doesn't work when AOT is enabled.

@harouny

This comment has been minimized.

harouny commented Sep 6, 2017

@mjstecson @keeperofchem @bluepnume

The following is an example of an angular cli project using paypal-button angular component:
https://github.com/harouny/paypal-button-ng2

Notice that I pass -aot false to ng -build to avoid ahead of time compilation.

@bluepnume

This comment has been minimized.

Member

bluepnume commented Sep 6, 2017

Thanks @harouny! Feel free to PR in a link to that repo in https://github.com/paypal/paypal-checkout/blob/master/docs/frameworks.md and I'll gladly merge.

I haven't had a lot of time to follow the discussion -- but do we know why AOT causes this to fail? Is it something we can fix in xcomponent or this repo?

@KevinShiCA

This comment has been minimized.

KevinShiCA commented Sep 6, 2017

@harouny Unfortunately, I think AOT is a bit too important towards production, since the speed difference is fairly noticeable. For now I'll be using my work around, until a better solution is presented (my solution takes quite a long time to load, since it is loading a script into the DOM). Not really worth it to slow down the whole project for a paypal button though.

@bluepnume From what I understand, because typescript is almost a typed language, the AOT does a static scan of your code to ensure that it will compile. Using a statement such as declare let paypal: any; will confuse the AOT since it is not exported yet imported into NgModule, whereas exporting the paypal variable makes the AOT uncomfortable since it is not clearly defined. This problem seems fairly common with including other (weakly typed) javascript libraries in typescript, so I am not sure it will be easy to fix in this repo.

@harouny

This comment has been minimized.

harouny commented Sep 6, 2017

@keeperofchem Yes, you are right. The JIT way is not for every project. That's why AOT is default now.

@keeperofchem @bluepnume

The problem is more than fixing declare let paypal: any; issue.
As @keeperofchem said, AOT pre compiles components before they can be used at runtime. In AOT mode, angular compiler is not even available at runtime. That's why AOT requires imported modules/components to be statically available at compile time.
In our case we load the module via script tag at runtime. Which means neither the module nor the component referenced here is available at compile time.

I'm still investigating if there is a way to dynamically load the component at runtime and let the rest of the app use AOT, I will keep you posted if I found a solution.

@KevinShiCA

This comment has been minimized.

KevinShiCA commented Sep 6, 2017

@harouny @bluepnume

https://github.com/keeperofchem/ng4-paypal-button
Repo containing an example of AOT passing paypal button integration. The paypal script is dynamically injected into the DOM at runtime to bypass AOT; note the slight delay on the rendering of the button.

@harouny

This comment has been minimized.

harouny commented Sep 7, 2017

Thanks @keeperofchem

Just to be clear, we have two ways of integration:

This issue here is related to native framework bindings (using a native angular component), your code sample (and your workaround) belongs to basic integration (directly render component to DOM using the render function).

@kandyjam

This comment has been minimized.

kandyjam commented Sep 22, 2017

@keeperofchem can you tell me any idea for ng4 implements this way?
https://developer.paypal.com/demo/checkout/#/pattern/server

@usamamalik75

This comment has been minimized.

usamamalik75 commented Oct 25, 2017

@carlosost
Thanks i follow you steps and now paypal checkout working
but one problem after payment successful Router object undefined
some sample code

onAuthorize(data: any, actions: any) {
debugger
return actions.payment.execute().then(function () {
// Show a success page to the buyer
console.log("onAuthorize");
//// after successful payment "router" object show undefined
this.router.navigate(['abc',id]);
});

}
@gate3

This comment has been minimized.

gate3 commented Dec 5, 2017

Hi guys, thanks for the tip. I implemented it and it works. But my question is how does one go about recurring payments?

@subramaniashiva

This comment has been minimized.

subramaniashiva commented Dec 22, 2017

Waiting for paypal + Angular4 integration library. Meanwhile I implemented it by calling paypal.Button.render function in the component where I needed paypal integration

@alexthelion

This comment has been minimized.

alexthelion commented Dec 30, 2017

Hi guys! Is there any way to catch and display error messages with onError method.
I want to display an error message to the user with the wrong field. With the current error message structure i can't extract the problematic fields.
I'm getting an error like this:

Error: Error: Request to post https://www.sandbox.paypal.com/v1/payments/payment failed with 400 error. Correlation id: 588c6ae350e0, 588c6ae350e0

{
"name": "VALIDATION_ERROR",
"details": [
{
"field": "zip",
"issue": "Value is invalid"
}
],
"message": "Invalid request - see details",
"information_link": "https://developer.paypal.com/docs/api/payments/#errors",
"debug_id": "588c6ae350e0"
}

at XMLHttpRequest.<anonymous> (https://www.paypalobjects.com/api/checkout.js:15187:39)
at Object._RECEIVE_MESSAGE_TYPE.(anonymous function) [as postrobot_message_response] (https://www.paypalobjects.com/api/checkout.js:3160:122)
at receiveMessage (https://www.paypalobjects.com/api/checkout.js:3059:77)
at messageListener (https://www.paypalobjects.com/api/checkout.js:3080:13)
at ZoneDelegate.invokeTask (webpack-internal:///../../../../zone.js/dist/zone.js:425:31)
at Zone.runTask (webpack-internal:///../../../../zone.js/dist/zone.js:192:47)
at ZoneTask.invokeTask [as invoke] (webpack-internal:///../../../../zone.js/dist/zone.js:499:34)
at invokeTask (webpack-internal:///../../../../zone.js/dist/zone.js:1540:14)
at globalZoneAwareCallback (webpack-internal:///../../../../zone.js/dist/zone.js:1577:21)
at Object._RECEIVE_MESSAGE_TYPE.(anonymous function) [as postrobot_message_response] (https://www.paypalobjects.com/api/checkout.js:3160:122)
at receiveMessage (https://www.paypalobjects.com/api/checkout.js:3059:77)
at messageListener (https://www.paypalobjects.com/api/checkout.js:3080:13)

at XMLHttpRequest.<anonymous> (https://www.paypalobjects.com/api/checkout.js:15187:39)
at Object._RECEIVE_MESSAGE_TYPE.(anonymous function) [as postrobot_message_response] (https://www.paypalobjects.com/api/checkout.js:3160:122)
at receiveMessage (https://www.paypalobjects.com/api/checkout.js:3059:77)
at messageListener (https://www.paypalobjects.com/api/checkout.js:3080:13)
at ZoneDelegate.invokeTask (webpack-internal:///../../../../zone.js/dist/zone.js:425:31)
at Zone.runTask (webpack-internal:///../../../../zone.js/dist/zone.js:192:47)
at ZoneTask.invokeTask [as invoke] (webpack-internal:///../../../../zone.js/dist/zone.js:499:34)
at invokeTask (webpack-internal:///../../../../zone.js/dist/zone.js:1540:14)
at globalZoneAwareCallback (webpack-internal:///../../../../zone.js/dist/zone.js:1577:21)
at Object._RECEIVE_MESSAGE_TYPE.(anonymous function) [as postrobot_message_response] (https://www.paypalobjects.com/api/checkout.js:3160:122)
at receiveMessage (https://www.paypalobjects.com/api/checkout.js:3059:77)
at messageListener (https://www.paypalobjects.com/api/checkout.js:3080:13)
at deserializeError (https://www.paypalobjects.com/api/checkout.js:3668:20)
at https://www.paypalobjects.com/api/checkout.js:3687:322
at https://www.paypalobjects.com/api/checkout.js:3779:30
at eachArray (https://www.paypalobjects.com/api/checkout.js:3762:51)
at each (https://www.paypalobjects.com/api/checkout.js:3768:35)
at replaceObject (https://www.paypalobjects.com/api/checkout.js:3778:13)
at https://www.paypalobjects.com/api/checkout.js:3780:169
at eachObject (https://www.paypalobjects.com/api/checkout.js:3765:65)
at each (https://www.paypalobjects.com/api/checkout.js:3768:144)
at replaceObject (https://www.paypalobjects.com/api/checkout.js:3778:13)
@jhourlad

This comment has been minimized.

jhourlad commented Jan 19, 2018

After a year: 2018. Angular already in v5.2. Still no Angular 4 support.
I think we can safely mark this as project as "abandoned" :D :D :D

@carlfm01

This comment has been minimized.

carlfm01 commented Jan 21, 2018

@KevinShiCA Thanks, working with Angular 5, @jhourlad take a look https://github.com/KevinShiCA/ng4-paypal-button

@svenkat18

This comment has been minimized.

svenkat18 commented Feb 9, 2018

@harouny
How to implement confirm payment button in Angular 4/5 ?
https://developer.paypal.com/demo/checkout/#/pattern/confirm

When user clicks on "Payment Checkout" call return actions.payment.get().then(function(data) ..
and then user clicks on "complete payment" ....then call actual execute method
return actions.payment.execute().then(function()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment