Why show this error,",Uncaught ReferenceError: c3 is not defined" - javascript

I have created one calculator in that calculator i have use pie chart to show data dynamically,but chart throw error.The code is given below,
custom.min.js in this js file i have usen c3 chart,
var chart = c3.generate({
data: {
columns: [
["Interest Payable", 3900519],
["Principal", 3e6]
],
type: "pie"
},
axis: { x: { label: "Sepal.Width" }, y: { label: "Petal.Width" } },
legend: { show: !1 },
tooltip: { format: { title: function(t) { return "" }, value: function(t, e, n) { return t } }, contents: tooltip_contents }
});
I have usen this plugin to done this : c3.min.js,c3_renderers.min.js,d3.min.js,d3.v3.min.js,pivot.min.js.
I have downloaded this plugin and put inside the asset folder and I am call this js file by scriptloaderService, and this scriptloaderService imported inside component.
DynamicScriptLoaderServiceService this is scriptloaderServise code.
import { Injectable } from '#angular/core';
interface Scripts {
name: string;
src: string;
}
export const ScriptStore: Scripts[] = [
{ name: 'd3.v3.min.js', src: './assets/Scripts/d3.v3.min.js' },
{ name: 'd3.min.js', src: './assets/Scripts/d3.min.js'},
{ name: 'c3.min.js', src: './assets/Scripts/c3.min.js' },
{ name: 'custom.min.js', src: './assets/Scripts/custom.min.js' },
];
declare var document: any;
#Injectable()
export class DynamicScriptLoaderServiceService {
private scripts: any = {};
constructor() {
ScriptStore.forEach((script: any) => {
this.scripts[script.name] = {
loaded: false,
src: script.src
};
});
}
load(...scripts: string[]) {
const promises: any[] = [];
scripts.forEach((script) => promises.push(this.loadScript(script)));
return Promise.all(promises);
}
loadScript(name: string) {
return new Promise((resolve, reject) => {
if (!this.scripts[name].loaded) {
//load script
let script = document.createElement('script');
script.type = 'text/javascript';
script.src = this.scripts[name].src;
if (script.readyState) { //IE
script.onreadystatechange = () => {
if (script.readyState === "loaded" || script.readyState === "complete") {
script.onreadystatechange = null;
this.scripts[name].loaded = true;
resolve({script: name, loaded: true, status: 'Loaded'});
}
};
} else { //Others
script.onload = () => {
this.scripts[name].loaded = true;
resolve({script: name, loaded: true, status: 'Loaded'});
};
}
script.onerror = (error: any) => resolve({script: name, loaded: false, status: 'Loaded'});
document.getElementsByTagName('head')[0].appendChild(script);
} else {
resolve({ script: name, loaded: true, status: 'Already Loaded' });
}
});
}
}
CalcyComponent this is component in which service and JS file was called to show pie chart.
import { Component, OnInit, AfterViewInit } from '#angular/core';
import { DynamicScriptLoaderServiceService } from '../../../ScriptLoaderService/dynamic-script-loader-service.service';
#Component({
selector: 'app-calcy',
templateUrl: './calcy.component.html',
styleUrls: ['./calcy.component.css']
})
export class CalcyComponent implements OnInit, AfterViewInit {
constructor(private dynamicScriptLoader:DynamicScriptLoaderServiceService) { }
ngOnInit() {
this.loadScripts();
}
ngAfterViewInit() { }
loadScripts() {
// You can load multiple scripts by just providing the key as argument into load method of the service
this.dynamicScriptLoader.load(
'd3.v3.min.js','d3.min.js','c3.min.js','custom.min.js',).then(data => {
// Script Loaded Successfully
}).catch(error => console.log(error));
}
}
calcy.component.html this is template where chart should be show, I have given small code of that.
<div class="abc">
<div id="chart" class="chart" style="width: 320px; height: 285px;"></div>
<div style="display: none;">
<div title="" style="width: 454px;
height: 319px;">
<!-- <div id="Graph"></div> -->
</div>
</div>
</div>
Main error shown by browser is this. "Uncaught ReferenceError: c3 is not defined"
any one can help in this code????

Related

How to get Paypal Checkout to work with Vue.JS 3

I am trying to make Paypal Checkout work with Vue.JS 3 (using the loader)
Right now I got this far:
setPaypal() {
const script = document.createElement('script');
script.src = 'https://www.paypal.com/sdk/js?client-id=AdlvqGHWrrwVpGXreZuf5VHBXjIeUWGLHBJmDzbI44Ib2w1MMN7P-UJysCHFb_W7BWTvpz0ofji0SiYB';
document.body.appendChild(script);
script.addEventListener('load', this.setLoaded())
}
This function is called in the mounted(): and inserts the script tag in my page.
setLoaded() {
window.paypal.Buttons({
createOrder: (actions) => {
return actions.order.create({
purchase_units: [
{
description: this.prestation.courtedescription,
amount: {
currency_code: "EUR",
value: this.total
}
}
]
});
},
onApprove: async () => {
this.paidFor = true;
this.loading = false;
},
onError: err => {
console.log(err)
}
})
.render(this.$refs.paypal)
}
This is the setLoaded() function called when the script is loaded.
Well obviously window.paypal is undefined
I tried using the official docs and same shit, they ask you to
const PayPalButton = paypal.Buttons.driver("vue", window.Vue);
But hey, paypal is not defined
For reference, this is the official docs
Add the SDK <script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>
Vue integration
<div id="container">
<app></app>
</div>
<script>
const PayPalButton = paypal.Buttons.driver("vue", window.Vue);
Vue.component("app", {
template: `
<paypal-buttons :on-approve="onApprove" :create-order="createOrder" />
`,
components: {
"paypal-buttons": PayPalButton,
},
computed: {
createOrder: function () {
return (data, actions) => {
return actions.order.create({
purchase_units: [
{
amount: {
value: "10",
},
},
],
});
}
},
onApprove: function () {
return (data, actions) => {
return actions.order.capture();
}
},
},
});
const vm = new Vue({
el: "#container",
});
</script>
Instead of using this in your setPaypal() function
script.addEventListener('load', this.setLoaded())
Use this
script.addEventListener('load', () => this.setLoaded())

[Vue warn]: Failed to resolve async component: datatables and nuxt js

I'm developing an admin panel with "SCUTUM" admin template with nuxt.js.
When I trying to use datatables component in the template it gives following error in the console. Component is made by template provider. And I used it as the example given by them.
[Vue warn]: Failed to resolve async component: function Datatable() {
return Promise.all(/*! import() */[__webpack_require__.e(0), __webpack_require__.e(1)]).then(__webpack_require__.bind(null, /*! ~/components/datatables/Datatables */ "./components/datatables/Datatables.vue"));
}
Reason: TypeError: Cannot read property 'display' of undefined
What is the reason for this?
Here is my code
<template>
<div id="sc-page-wrapper">
<div id="sc-page-content">
<ScCard class="">
<ScCardHeader seperator>
<div class="uk-flex-middle uk-grid-small uk-grid" data-uk-grid>
<div class="uk-flex-1">
<ScCardTitle>
List of Lecturers
</ScCardTitle>
</div>
<div class="uk-width-auto#s">
<div id="sc-dt-buttons"></div>
</div>
</div>
</ScCardHeader>
<ScCardBody>
<client-only>
<Datatable
id="sc-dt-buttons-table"
ref="buttonsTable"
:data="dtDData"
:options="dtDOptions"
:buttons="true"
#initComplete="dtButtonsInitialized"
/>
</client-only>
</ScCardBody>
</ScCard>
</div>
</div>
</template>
<script>
const rows = require('~/data/pages/datatables.json');
import ScCard from "#/components/card/";
import {ScCardTitle, ScCardBody, ScCardHeader} from "#/components/card"
export default {
name: 'Lecturer',
components: {
Datatable: () => import('~/components/datatables/Datatables'),
ScCard,
ScCardTitle,
ScCardHeader,
ScCardBody
},
data: () => ({
dtDData: JSON.parse(JSON.stringify(rows)),
dtDOptions: {
buttons: [
{
extend: "copyHtml5",
className: "sc-button",
text: 'Copy'
},
{
extend: "csvHtml5",
className: "sc-button",
text: 'CSV '
},
{
extend: "excelHtml5",
className: "sc-button",
text: 'Excel '
},
{
extend: "pdfHtml5",
className: "sc-button sc-button-icon",
text: '<i class="mdi mdi-file-pdf md-color-red-800"></i>'
},
{
extend: "print",
className: "sc-button sc-button-icon",
text: '<i class="mdi mdi-printer"></i>',
title: 'Custom Title',
messageTop: 'Custom message on the top',
messageBottom: 'Custom message on the bottom',
autoPrint: true
}
]
}
}),
mounted () {
this.$nextTick(() => {
})
},
methods: {
dtButtonsInitialized () {
// append buttons to custom container
this.$refs.buttonsTable.$dt.buttons().container().appendTo(document.getElementById('sc-dt-buttons'))
},
}
}
</script>
<style lang="scss">
</style>
Here is the Datatables component
<template>
<div>
<table :id="id" class="uk-table uk-table-striped uk-table-middle" :class="[tableClass]" style="width:100%">
<thead>
<tr>
<th v-for="header in headers" :key="header" class="uk-text-nowrap">
{{ header }}
</th>
</tr>
</thead>
<slot name="footer"></slot>
</table>
</div>
</template>
<script>
import { mapState } from 'vuex'
import { scMq } from '~/assets/js/utils'
require('~/plugins/jquery');
require('datatables.net/js/jquery.dataTables');
require('datatables.net-responsive');
require('datatables.net-select');
require('./dataTables.uikit');
require('./dataTables.responsive.uikit');
export default {
name: 'Datatable',
props: {
data: {
type: Array,
default: () => [],
required: true
},
options: {
type: Object,
default: () => {}
},
id: {
type: String,
required: true
},
buttons: {
type: Boolean,
default: false
},
autoWidth: Boolean,
tableClass: {
type: String,
default: ''
},
customEvents: {
type: Array,
default: () => []
}
},
data: () => ({
$dt: null
}),
computed: {
dtData () {
return JSON.parse(JSON.stringify(this.data))
},
headers () {
let names = [];
Object.keys(this.data[0]).map(k => {
let name = k.replace(/_/g, ' ');
names.push(name.charAt(0).toUpperCase() + name.slice(1))
});
return names
},
columns () {
let columns = [];
Object.keys(this.data[0]).map(k => {
columns.push({
data: k
})
});
return columns;
},
...mapState([
'vxSidebarMainExpanded'
])
},
watch: {
dtData (newVal, oldVal) {
const newLength = newVal.length;
const oldLength = oldVal.length;
const newIds = newVal.map(k => {
return k.id
});
const oldIds = oldVal.map(k => {
return k.id
});
if(newLength > oldLength) {
let uniq = newIds.filter(k => {
return !oldIds.includes(k)
});
if (uniq.length) {
const newEl = newVal.filter(obj => {
return obj.id === uniq[0]
});
this.$dt.row.add(newEl[0]).draw('full-hold');
}
} else {
let uniq = oldIds.filter(k => {
return !newIds.includes(k)
});
if (uniq.length) {
this.$dt.row(':eq('+ uniq[0] +')').remove().draw('full-hold')
}
}
},
vxSidebarMainExpanded () {
if(scMq.mediumMin()) {
setTimeout(() => {
$('#' + this.id).resize()
}, 300);
}
}
},
mounted () {
const self = this;
if(self.buttons) {
const pdfMake = require('~/assets/js/vendor/pdfmake/pdfmake');
const pdfFonts =require('~/assets/js/vendor/pdfmake/vfs_fonts');
pdfMake.vfs = pdfFonts.pdfMake.vfs;
window.JSZip = require("~/assets/js/vendor/jszip");
require('datatables.net-buttons');
require('datatables.net-buttons/js/buttons.html5');
require('datatables.net-buttons/js/buttons.print');
}
let _options = {
data: self.data,
columns: self.columns,
responsive: true,
"initComplete" (settings, json) {
self.$dt = this.api();
self.$emit('initComplete');
}
};
const options = $.extend(_options, self.options);
if(options.responsive === 'responsiveModal') {
_options.responsive = {
details: {
display: $.fn.dataTable.Responsive.display.modal({
header (row) {
return 'Details for row ' + (parseInt(row[0]) + 1);
}
}),
renderer: $.fn.dataTable.Responsive.renderer.tableAll({
tableClass: 'table'
})
}
}
}
$('#' + this.id).DataTable(options);
if(this.customEvents.length) {
this.customEvents.forEach(event => {
this.$dt.on(event.name, event.function)
})
}
}
}
</script>
Is there a way to resolve this?

How to create,edit and delete data in Ng2 smart table

I used [ng2 smart table] in my angular 2 project, I need to send an API request using http.post() method but the problem happened when I click on the button to confirm data face this error in console:
ERROR TypeError: _co.addClient is not a function.
this is code in service.ts :
import { Injectable } from '#angular/core';
import { Clients } from './clients.model';
import { HttpClient, HttpErrorResponse } from '#angular/common/http';
import { Observable} from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class ClientsService {
url="http://localhost:21063/api/clints"
clients:Clients[];
client:Clients;
constructor(private http:HttpClient) { }
getAllClients(): Observable<Clients[]>{
return this.http.get<Clients[]>(this.url);
}
addClient(event){
this.http.post<Clients>(this.url,this.client)
.subscribe(
res=>{
console.log(res);
event.confirm.resolve(event.Clients);
},
(err: HttpErrorResponse) => {
if (err.error instanceof Error) {
console.log("Client-side error occurred.");
} else {
console.log("Server-side error occurred.");
}
}
)
}
and this my template :
<div class="mainTbl">
<ng2-smart-table
[settings]="settMain"
[source]="this.Service.clients"
(createConfirm)="addClient($event)"
(editConfirm)="onEditConfirm($event)"
(deleteConfirm)="onDeleteConfirm($event)"
></ng2-smart-table>
</div>
compontent .ts
settMain = {
noDataMessage: 'عفوا لا توجد بيانات',
actions: {
columnTitle: 'إجراءات',
position: 'right',
},
pager: {
perPage: 5,
},
add: {
addButtonContent: ' إضافة جديد ',
createButtonContent: '',
cancelButtonContent: '',
confirmCreate: true,
},
edit: {
editButtonContent: '',
saveButtonContent: '',
cancelButtonContent: '',
confirmSave: true,
},
delete: {
deleteButtonContent: '',
confirmDelete: true,
},
columns: {
id: {
title: 'كود العميل',
width: '80px',
},
name: {
title: 'اسم العميل',
width: '160px'
},
phone: {
title: ' الهاتف'
},
address: {
title: ' العنوان'
},
account: {
title: 'الرصيد '
},
notes: {
title: 'ملاحظات'
}
}
};
private myForm: FormGroup;
constructor(private formBuilder: FormBuilder, private Service: ClientsService) { }
ngOnInit() {
this.Service.getAllClients().subscribe(data => this.Service.clients = data);
this.Service.client={
id:0,
name:null,
phone:null,
address:null,
type:null,
account:0,
nots:null,
branchId:0,
};
so how can I find my mistake also what the best way to handle create, edit and delete operations?
thanks in advance
That is because addClient is a method on service.ts, whereas the ng2-smart-table is instantiated on that component, and you shouldn't directly call your service method on the template.
Therefore, the right way of doing things would be to create a method on your component.ts which calls the addClient method.
On your component.html template, we bind the editConfirm event to another method onAddClient
<div class="mainTbl">
<ng2-smart-table
[settings]="settMain"
[source]="this.Service.clients"
(createConfirm)="onAddClient($event)"
(editConfirm)="onEditConfirm($event)"
(deleteConfirm)="onDeleteConfirm($event)"
></ng2-smart-table>
</div>
On your component.ts,
onAddClient(event) {
this.Service.addClient(event).subscribe(
(res) => {
// handle success
}, (error) => {
// handle error
});
}
And in addition, on your service.ts, you will pass the data from the compnoent, and return the response from the http request from the HTTP Client.
addClient(data){
console.log(data);
return this.http.post<Clients>(this.url, data);
}

Use external JavaScript library in Angular 8 application

I am new to Angular and i want to develop a funnel-graph. i like the funnel-graph-js library. i tried a lot but haven't succeed.
here is my funnel-graph-directive.ts
import { Directive, ElementRef } from '#angular/core';
// import * as graph from '../../../assets/js/funnel-graph.js';
import * as graph from 'funnel-graph-js/dist/js/funnel-graph.js';
var graph = new FunnelGraph({
container: '.funnel',
gradientDirection: 'horizontal',
data: {
labels: ['Impressions', 'Add To Cart', 'Buy'],
subLabels: ['Direct', 'Social Media', 'Ads'],
colors: [
['#FFB178', '#FF78B1', '#FF3C8E'],
['#A0BBFF', '#EC77FF'],
['#A0F9FF', '#7795FF']
],
values: [
[3500, 2500, 6500],
[3300, 1400, 1000],
[600, 200, 130]
]
},
displayPercent: true,
direction: 'horizontal'
});
graph.draw();
#Directive({
selector: '[appFunnelGraph]'
})
export class FunnelGraphDirective {
style: any;
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
}
I have added these lines in my angular.json
"styles": [
"src/styles.scss",
"./node_modules/funnel-graph-js/dist/css/main.css",
"./node_modules/funnel-graph-js/dist/css/theme.css"
],
"scripts": [
"./node_modules/funnel-graph-js/dist/js/funnel-graph.js"
]
Here is the error i am getting
As long as you linked the javascript file in the html, it will work fine.
EDIT:
A better way to include an addition javascript file is to put it into the "scripts" section in the angular.json file. You can also add
declare const FunnelGraph: any
in order to compile without errors. This has been taken from an answer to a stackoverflow question and this guide. Remember to include the css files in that json too!
EDIT END
You get that error because the code tries to look for an HTML element with a class named "funnel", but cannot find it. Since this is a directive, it would be better if it was a little more generalized.
First of all, you should move your graph-generating code inside the constructor, since that's were the directive logic resides. To better generalize this directive, it would be best if you gave a unique id to that element and change the code accordingly. This is how I would do it:
HTML:
<div id="funnel-graph-1" appFunnelGraph></div>
JS:
import { Directive, ElementRef } from '#angular/core';
// It should be fine to just import this in the html with a script tag
// import * as graph from 'funnel-graph-js/dist/js/funnel-graph.js';
#Directive({
selector: '[appFunnelGraph]'
})
export class FunnelGraphDirective {
style: any;
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
var graph = new FunnelGraph({
// Generalize the container selector with the element id
container: '#' + el.nativeElement.id,
gradientDirection: 'horizontal',
data: {
labels: ['Impressions', 'Add To Cart', 'Buy'],
subLabels: ['Direct', 'Social Media', 'Ads'],
colors: [
['#FFB178', '#FF78B1', '#FF3C8E'],
['#A0BBFF', '#EC77FF'],
['#A0F9FF', '#7795FF']
],
values: [
[3500, 2500, 6500],
[3300, 1400, 1000],
[600, 200, 130]
]
},
displayPercent: true,
direction: 'horizontal'
});
graph.draw();
}
}
I ended up by creating service instead of using directive approach.
First i generated a service called dynamic-script-loader-service in
my dashboard module.
dynamic-service-loader.service.service.ts
import { Injectable } from '#angular/core';
interface Scripts {
name: string;
src: string;
}
export const ScriptStore: Scripts[] = [
{ name: 'chartjs', src: 'https://unpkg.com/funnel-graph-js#1.3.9/dist/js/funnel-graph.min.js' },
];
declare var document: any;
#Injectable()
export class DynamicScriptLoaderServiceService {
private scripts: any = {};
constructor() {
ScriptStore.forEach((script: any) => {
this.scripts[script.name] = {
loaded: false,
src: script.src
};
});
}
load(...scripts: string[]) {
const promises: any[] = [];
scripts.forEach((script) => promises.push(this.loadScript(script)));
return Promise.all(promises);
}
loadScript(name: string) {
return new Promise((resolve, reject) => {
if (!this.scripts[name].loaded) {
//load script
let script = document.createElement('script');
script.type = 'text/javascript';
script.src = this.scripts[name].src;
if (script.readyState) { //IE
script.onreadystatechange = () => {
if (script.readyState === 'loaded' || script.readyState === 'complete') {
script.onreadystatechange = null;
this.scripts[name].loaded = true;
resolve({ script: name, loaded: true, status: 'Loaded' });
}
};
} else { //Others
script.onload = () => {
this.scripts[name].loaded = true;
resolve({ script: name, loaded: true, status: 'Loaded' });
};
}
script.onerror = (error: any) => resolve({ script: name, loaded: false, status: 'Loaded' });
document.getElementsByTagName('head')[0].appendChild(script);
} else {
resolve({ script: name, loaded: true, status: 'Already Loaded' });
}
});
}
}
dashboard.component.ts
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { DynamicScriptLoaderServiceService } from '../dynamic-script-loader-service.service';
import * as FunnelGraph from 'funnel-graph-js';
function dashboardFunnel() {
const graph = new FunnelGraph({
container: '.funnel',
// gradientDirection: 'horizontal',
data: {
labels: ['Label 7', 'Label 1', 'Label 2', 'Label 3', 'Label 4', 'Label 5', 'Label 6'],
colors: ['#00A8FF', '#00A8FF', '#00A8FF', '#00A8FF', '#00A8FF', '#00A8FF', '#00A8FF'],
// color: '#00A8FF',
values: [12000, 11000, 10000, 9000, 8000, 7000, 6000]
},
displayPercent: true,
direction: 'horizontal',
});
graph.draw();
}
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class DashboardComponent implements OnInit {
constructor(
private dynamicScriptLoader: DynamicScriptLoaderServiceService
) {}
ngOnInit() {
this.loadScripts();
dashboardFunnel();
}
private loadScripts() {
// You can load multiple scripts by just providing the key as argument into load method of the service
this.dynamicScriptLoader.load('chartjs', 'random-num').then(data => {
// Script Loaded Successfully
}).catch(error => console.log(error));
}
}
added providers in my dashboard.module.ts
providers: [DynamicScriptLoaderServiceService],
added css in my angular.json
"styles": [
"src/styles.scss",
"./node_modules/funnel-graph-js/dist/css/main.css",
"./node_modules/funnel-graph-js/dist/css/theme.css"
],
added div with class funnel in dashboard.component.html
<div class="funnel"></div>

React js Stripe checkout is not working

I am trying to render a stripe checkout default form in React js application.
<form action="/your-server-side-code" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" className="stripe-button"
data-key="pk_test_oDALA0jNyxDzbRz5RstV4qOr"
data-amount="999"
data-name="test"
data-description="Widget"
data-image="https://stripe.com/img/documentation/checkout/marketplace.png"
data-locale="auto">
</script>
</form>
Its not displaying anything and not getting error also.
How do i get that pay button and form.
The main issue you are probably having is loading a script within React.
One approach is to load the checkout script only when needed (assuming some form of spa), then just directly call it. This is akin to the "custom" version on the documentation page: https://stripe.com/docs/checkout#integration-custom
If you are already loading checkout.js (for example before your "app.js"), then the below can be simplified a bit by not manually loading in the script.
import React from 'react';
export default class Cards extends React.Component {
constructor(props:Object) {
super(props);
this.state = {
loading: true,
stripeLoading: true,
};
}
loadStripe(onload:Function) {
if(! window.StripeCheckout) {
const script = document.createElement('script');
script.onload = function () {
console.info("Stripe script loaded");
onload();
};
script.src = 'https://checkout.stripe.com/checkout.js';
document.head.appendChild(script);
} else {
onload();
}
}
componentDidMount() {
this.loadStripe(() => {
this.stripehandler = window.StripeCheckout.configure({
key: 'pk_test_xxxxxxxxxxxxxxxxxxxxxxxx',
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: (token) => {
this.setState({ loading: true });
axios.post('/your-server-side-code', {
stripeToken: token.id,
});
}
});
this.setState({
stripeLoading: false
});
});
}
componentWillUnmount() {
if(this.stripehandler) {
this.stripehandler.close();
}
}
onStripeUpdate(e:Object) {
this.stripehandler.open({
name: 'test',
description: 'widget',
panelLabel: 'Update Credit Card',
allowRememberMe: false,
});
e.preventDefault();
}
render() {
const { stripeLoading, loading } = this.state;
return (
<div>
{(loading || stripeLoading)
? <p>loading..</p>
: <button onClick={this.onStripeUpdate}>Add CC</button>
}
</div>
);
}
}
Chris's answer was excellent, however I had to make a few minor changes in order for the code to function. I've also removed the TypeScript function types (for those of us not using TypeScript). Comments are added where changes to the answer have been made. FYI this is my first post, please let me know if this should be a Comment instead of an Answer.
export default class Cards extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
stripeLoading: true,
};
// onStripeUpdate must be bound or else clicking on button will produce error.
this.onStripeUpdate = this.onStripeUpdate.bind(this);
// binding loadStripe as a best practice, not doing so does not seem to cause error.
this.loadStripe = this.loadStripe.bind(this);
}
loadStripe(onload) {
if(! window.StripeCheckout) {
const script = document.createElement('script');
script.onload = function () {
console.info("Stripe script loaded");
onload();
};
script.src = 'https://checkout.stripe.com/checkout.js';
document.head.appendChild(script);
} else {
onload();
}
}
componentDidMount() {
this.loadStripe(() => {
this.stripeHandler = window.StripeCheckout.configure({
key: 'pk_test_xxxxxxxxxxxxxxxxxxxxxxxx',
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: (token) => {
this.setState({ loading: true });
// use fetch or some other AJAX library here if you dont want to use axios
axios.post('/your-server-side-code', {
stripeToken: token.id,
});
}
});
this.setState({
stripeLoading: false,
// loading needs to be explicitly set false so component will render in 'loaded' state.
loading: false,
});
});
}
componentWillUnmount() {
if(this.stripeHandler) {
this.stripeHandler.close();
}
}
onStripeUpdate(e) {
this.stripeHandler.open({
name: 'test',
description: 'widget',
panelLabel: 'Update Credit Card',
allowRememberMe: false,
});
e.preventDefault();
}
render() {
const { stripeLoading, loading } = this.state;
return (
<div>
{(loading || stripeLoading)
? <p>loading..</p>
: <button onClick={this.onStripeUpdate}>Add CC</button>
}
</div>
);
}
}

Categories

Resources