Sadly, elements is not a separate library.
It's just a part of the still in development Stripe.js v3, so the only way to include it is to include the whole script in the page somewhere. There is no bower library, no amd/require/commonjs package of any sort.
This is the only way to include it:
<script src="https://js.stripe.com/v3/"></script>
Additionally, the v3 does not cover all the features v2 does, so they recommend us including both for now, until that is the case, which would look like
<script src="https://js.stripe.com/v2/"></script>
<script src="https://js.stripe.com/v3/"></script>
An ember addon usually includes dependencies by adding a bower package to the project, or outright including the script file in the vendor
folder, but this is not the case here.
What we still can do, though, is use the contentFor
hook of the addon index
file, which can then insert content into the app html head or body.
Our own ember-stripe-service does this for v2:
contentFor: function(type) {
if (type === 'body') {
return '<script type="text/javascript" src="https://js.stripe.com/v2/"></script>';
}
}
This will include as a script inside the body. Looking at the app index.html
, it's clear where it goes:
<body>
{{content-for "body"}}
<script src="{{rootURL}}assets/vendor.js"></script>
<script src="{{rootURL}}assets/code-corps-ember.js"></script>
{{content-for "body-footer"}}
</body>
The procedure will give us a Stripe
global function/variable, which can be used to instantiate a stripe object by giving it an API key. However, we probably want a bit more than that, so my recommended way to proceed would be to create a service.
This service can have an init
function, like any other ember object. The function by default does nothing, but we can override it so that it initializes stripe using something like:
init() {
let { elements, createToken } = Stripe('our_public_key');
setProperties(this, { elements, createToken });
}
This should make it so that stripe is initialized on app load, and not every time we need it. From that point, we can use/expand service to use the documented elements features: https://stripe.com/docs/elements/reference
Our ember-stripe-service
uses an initializer to initialize and inject a similar service, but I think that's a remnant from the ember 1.x era, and is probably no longer necessary.
Mainly, I believe we'll want a card component. Let's say {{stripe-card}}
. On a basic level, it should be a tagName: 'form'
. It should contain something like <div role="mount-point"></div>
. On didInsertElement()
it should do something like:
stripeElements: service(),
didInsertElement() {
this._super(...arguments);
let elements = get(this, 'stripeElements.elements')();
let card = elements.create('card');
card.mount(this.$('[role="mount-point"]')[0]);
set(this, 'card', card);
}
Additionally, we should handle the submit
event of the component itself (since the component is a form):
submit(event) {
event.preventDefault();
let card = get(this, 'card');
let createToken = get(this, 'stripeElements.createToken');
createToken(card).then((result) => {
if (result.error) {
get(this, 'onError')(result.error);
} else {
get(this, 'onSuccess')(result.token);
}
});
}
The approach above should allow the user to specify an onSuccess
and onError
callback, while also allowing us to define default callbacks in the component. This is all just out of my head, though, so I'm not sure it works that way exactly. Either way, you get the gist.
The approach above should allow the user to specify an onSuccess
and onError
callback, while also allowing us to define default callbacks in the component. This is all just out of my head, though, so I'm not sure it works that way exactly. Either way, you get the gist.
Usually, you'd define and export the component from within ember-stripe-elements/addon/components/stripe-card.js
.
You'd define the template in ember-stripe-elements/app/templates/components/stripe-card.hbs
.
Youd also define a ember-stripe-elements/app/components/stripe-card.js
which simply does an import/export from the addon folder. I'm not sure if this is still the case, but it used to work that way.
What I have above are the basics.
We can expand from the basics. For example, we could add error handling by adding an error container to the component template and binding to the stripe card
object's change
event, then checking if there was an error and setting the error property.
Where to go from there, I'm not sure, but this should be enough for a basic addon and for a meetup. I'd say it's even 90% of a fully functional addon. Past that, it's a matter of how many features you want to support eventually.
The addon will be loading the v3 stripe script. Eventually, this script will have all the features of v2 and will replace it. Since ember-stripe-service
loads v2, it might be a good idea for the contentFor
hook for both addons to first check if the content being added (the <script>
tag) is already there, so it's not added twice. If these two addons will live together, I would not be surprised if they eventually both load the same script.
An addon can have a dummy app inside the test folder. I believe an ember init addon
command will setup the project folder so that running ember server
will run the dummy app, so it's a good idea to use that one for trying things out and later writing tests. It's been ages since I did this, though, so I'm not sure it works that way anymore.
You'll have to figure a few things out - how to run the dummy app, how to test, maybe how to include a dev version in another project using npm link
. I would put all that into the addon readme, for future contributors.