Ben Drucker's contact information
$ npm install --save bendrucker
var bendrucker = require('bendrucker')
console.log(bendrucker)
//=> {name: 'Ben Drucker' ...}
MIT © Ben Drucker
Angular directives for parsing and validating credit card inputs
License: MIT License
Ben Drucker's contact information
$ npm install --save bendrucker
var bendrucker = require('bendrucker')
console.log(bendrucker)
//=> {name: 'Ben Drucker' ...}
MIT © Ben Drucker
In my particular case, I need to use ng-required on the input to determine if it should be validated or not. When ng-required="false", the this directive still wants tries to validate the input.
I'm getting this error on terminal when firing gulp
Cannot find module 'browserify-shim' from '/Users/omarfouad/Work/projects/products/finish/app/node_modules/angular-credit-cards'
Any Ideas?
Hi !
I was setting a codepen :
See the Pen Angular Credit Card by Hugo (@hugsbrugs) on CodePen.
<script async src="//assets.codepen.io/assets/embed/ei.js"></script>to show you my bug : when I select with my keyboard month 01 and year 2016, the key/pair was wrong until I quit year selection, get back to it, select another year and get back to 2016 ... but this bug has disappeared on my pen ... I will go on further investigations ... because it's unbelievable !
But by the way, I wanted to share with you my bootstrap markup with mandatory fields (bootstrap warning class and validate form button deactivated until form is valid), valid (success class) and invalid (error class) and thanks to you and your Card Eager Type, the card type icon ! This could interest people who uses your plugin since it's almost production ready : let me know what you think about it ...
Cheers !
I'm following the examples on the npm listing - using this with angular v1.3.5 on a node/express app. Angular loads the dependency successfully but the directives never seem to work. I can enter data in the form, click submit and the validation states never change and the credit card type is never appended.
Maybe I'm missing something but it's not clear in the documentation.
I'm using jade since this is in express.
form(method='post',ng-submit='buy()',novalidate,name="paymentForm")
ul
li
label Name on card
input(
type='text',
ng-model='card.name',
name='cardName',
required
)
li
label Card Number
input(
type='text',
ng-model='card.number',
name='cardNumber',
cc-type="cardType",
cc-number,
required
)
li(cc-exp)
label Expiration
input(
type="number",
ng-model="card.exp_month",
cc-exp-month,
required
)
input(
type="number",
ng-model="card.exp_year",
cc-exp-year,
required
)
li
label Verification Code
input(
type='text',
ng-model='card.cvc',
cc-type='cardNumber.$type'
)
li
input.btn(type='submit', value='Submit')
p Paying with {{cardNumber.$type}}
pattern="[0-9]*"
brings up the tel keyboard. Couldn't hurt to also apply type="text"
at the same time. Both would only be added if an element did not define the attr itself.
Detect card type faster for the purposes of user feedback. Examples of this feature can be seen here: http://tamas.io/custom-angularjs-filter-to-determine-credit-card-type/
And a demo of functionality:https://gumroad.com/l/demo
Press the "I want this" button and start typing cc number into the supplied field and note the icon highlight based on cc type
Using v 1.0.2 can you poke me how to display validation error for ccExp.
Also are name="ccNumber" attributes for each input required ?
In following markup ...
<form name="paymentForm">
<input style="border:1px solid black" type="text" ng-model="card.number" name="ccNumber" cc-number />
<p ng-show="paymentForm.ccNumber.$invalid">That's not a valid card Number</p>
<input style="border:1px solid black" type="text" ng-model="card.cvc" name="ccCvc" cc-cvc />
<p ng-show="paymentForm.ccCvc.$invalid">That's not a valid ccv code</p>
<div cc-exp>
<p ng-show="paymentForm.ccExp.$invalid">Expired Date</p>
<input style="border:1px solid black" type="number" ng-model="card.exp_month" cc-exp-month name="ccExpMonth" placeholder="mm" required />
<p ng-show="paymentForm.ccExpMonth.$invalid">That's not a right expiry Month</p>
<input style="border:1px solid black" type="number" ng-model="card.exp_year" cc-exp-year name="ccExpYear" placeholder="yy" required />
<p ng-show="paymentForm.ccExpYear.$invalid">That's not a right expiry Year</p>
</div>
<input type="submit" id="submit" ng-click="paymentForm.$valid && assignNonce()" value="Pay">
</form>
http://plnkr.co/edit/cU68yLPPqAVRDeHZQMQ7?p=preview
This is probably very edge-casey, but any input/advice would be appreciated. In my Angular project, my users use a numpad to fill in data into the checkout form. I would love to be able to use the new cc-format option, but at least on Chrome on my Macbook Air, the numbers reset after the first 5 digits are added.
link to live demo in plunkr in readme file is broken
I'm using Chrome and get the following tooltip validation message:
'Please match the requested format'
Any suggestions for how to bypass/override this?
This is my code:
<div class="icr-ccard icr-ccard-type-{{cardForm.ccNumber.$ccEagerType | ccLowercase}}">
<input type="text" ng-model="card.number" cc-number cc-type="cardType" name="ccNumber" cc-eager-type cc-format required>
</div>
Hey Ben,
The following line breaks the script when this file goes through minification:
https://github.com/bendrucker/angular-credit-cards/blob/master/release/angular-credit-cards.js#L273
After minification it looks life this:
var cvcRegex=/^\d{3,4}$/exports.isValid=function(cvc,type){if(typeof cvc!=='string')return false
And browser console says:
Uncaught SyntaxError: Invalid flags supplied to RegExp constructor 'exports'
It could be solved by adding semi-colon ; at the end of the line or by wrapping the regex so it won't break.
Doesn't work when used in a select box.
On https://www.npmjs.org/package/angular-credit-cards#readme in the Getting Started
section the method of importing is listed as
angular.module('myApp', [
'angular-credit-cards'
]);
When it should be
angular.module('myApp', [
'credit-cards' //note the angular-missing
]);
The readme in the repo is correct, so npm must be caching it or something
Hey - this module is such a timesaver! I have noticed a slight issue with it though...
Attempting to minify release/angular-credit-cards.js with JSMin (via http://compressorrater.thruhere.net) results in this browser console error:
Uncaught SyntaxError: Invalid flags supplied to RegExp constructor 'exports'
The line in question is:
var cvcRegex=/^\d{3,4}$/exports.isValid=function(cvc,type){if(typeof cvc!=='string')return false
The minifier doesn't seem to understand where the regular expression ends and the next line starts.
Have you been able to produce a minified version that could be added to the repository?
Many thanks.
As per your request based on my previous comment
I have addressed another issue related to the credit card form being pre-filled with data.
Expiration check would not work because both month and year would not be available to the isPast function.
Implementing a $formatters in addition to the $parsers solves the problem
// added by RER to allow pre-filled formed to pass cc-exp validation when only month or year are changed
ngModelCtrl.$formatters.unshift(function (year) {
year = expiration.year.parse(year, year.toString().length == 2 );
ccExpCtrl.set('year', year);
return year;
});
// added by RER to allow pre-filled formed to pass cc-exp validation when only month or year are changed
ngModelCtrl.$formatters.unshift(function (month) {
month = expiration.month.parse(month);
ccExpCtrl.set('month', month);
return month;
});
I'm getting an issue with card number validation. 4297 1038 5038 2
is passing but doesn't meet the minimum required length of 16.
Is there a check for the minimum length within your working for the Luhn algorithm? I'm happy to add one but just wanted to check that the algorithm was working correctly?
If the user enters bad input and/or the tabs off the credit card field the $dirty flag is not set on the form object.
i.e. formname.field name.$dirty is not set to true until a valid input has been received.
Can be reproduced by using the try it page: http://embed.plnkr.co/uE47aZ/preview and entering in anything like 4242 and tabbing off.
Can there be an option to allow invalid input to cause the form side of things to update?
<input type="text" class="input-text" id="cardNumber" data-cc-number data-cc-eager-type="payment.creditCardType" name="cardNumber" data-ng-model-options="{ allowInvalid: true }" data-ng-model="payment.creditCardNumber">
<span data-ng-show="paymentForm.cardNumber.$dirty && (paymentForm.cardNumber.$valid === false || paymentForm.cardNumber.$valid === true)" class="input-message-validate">
<span data-ng-messages="paymentForm.cardNumber.$error" data-ng-show="paymentForm.cardNumber.$valid === false">
<span data-ng-message="ccNumber">Bad credit card #</span>
</span>
<i class="icon-tick" data-ng-show="paymentForm.cardNumber.$valid === true"></i>
</span>
The ngModelController is updated but the value in the view doesn't kick in until after the first time the user has entered a valid cc number. This is happening even with allowInvalid the model options.
Hi just wondering if it was possible to expose credit card type/length information so we could kick off validation only once the user has entered the minimum number of characters for a given card type.
With attribute fullYear
set maxlength
to 4
and pass false to the year parser
I am attempting to use the most recent version of angular-credit-cards with Angular 1.3.15 using RequireJS (the last of which I'm admittedly a bit new to) and getting the following error when loading my app:
Uncaught TypeError: Cannot read property 'noop' of undefined
This is occurring within the following block of angular-credit-cards.js:
var nullCcExp = {
setMonth: _angular2['default'].noop,
setYear: _angular2['default'].noop
};
Any ideas?
Hi there and thanks for your great plugin !
I have a problem using your code with Stripe API since Stripe absolutely needs a 2 digits number as a month. With v2.0.0 and v2.2.0 everything went well but with the very last versions (2.3.4 & 2.3.5) I'm getting in trouble. Am I the only one who experience this problem ? Is it something (choose 1 or 2 digits for monthes between 1 and 9) that could easily be added as an option or is there a simple hack that would allow me the get a 2 digits ?
Thanks for any advises
Hugo
Your ccNumber
and ccNumberType
validators always fail if the card number is not specified.
Typically users would only expect this behavior if the required
attribute (or ng-required) is in place, and then the validation error would be required
(and not, for example, ccNumber
, which should be reserved for an invalid card number instead of a missing card number).
I would suggest that your validators pass on empty inputs, e.g.:
ngModel.$validators.ccNumber = function validateCcNumber (number) {
return !number || card.isValid(number)
}
ngModel.$validators.ccNumberType = function validateCcNumberType (number) {
return !number || card.isValid(number, $parse($attributes.ccType)($scope))
}
The validation pattern added to the credit card number input[1] fails the form validation when the number is formatted, since it then contains also white space.
Since the number is validated on the model, is there really a need for the input pattern as well? In any case, it should probably allow single whitespaces between number groups, or be specific to the detected card type.
[1] https://github.com/bendrucker/angular-credit-cards/blob/master/src/number.js#L17
//behaves as expected
Month: <input type="text" ng-model="card.exp_month" cc-exp-month /><br />
Year: <input type="text" ng-model="card.exp_year" cc-exp-year />
//does not behave as expected
Month: <input type="number" ng-model="card.exp_month" cc-exp-month /><br />
Year: <input type="number" ng-model="card.exp_year" cc-exp-year />
https://github.com/bendrucker/creditcards
This works fine in JSPM because here you have "main": "index.js",
and in your /index.js you export
'use strict'
exports.card = require('./src/card')
exports.cvc = require('./src/cvc')
exports.expiration = require('./src/expiration')
If you do the same for this repo. I won't need to use a fork, your 2 projects will be consistent (after all isn't that your argument?).
If you do this JSPM will be happy, browserify will be happy, and your 2 projects will be similar in that respect.
get cardType towards the beginning and mask the credit card view accordingly.
if(amex) 3700 000000 00000
if(visa || discover || mastercard) 4111 1111 1111 1111
limit to that card types max chars and only allow numbers
Correct this please
<select ng-model="cardType" ng-options="type in ['Visa', 'American Express', 'MasterCard']"></select>
to something like
<select ng-model="cardType" ng-options="type as type for type in ['Visa', 'American Express', 'MasterCard']"></select>
Hi,
I've noticed a broken link in README: see "Exposes the card type as $ccType
on the model controller".
I think this link should use https://github.com/bendrucker/creditcards-types#card-types
Nice touch on the correct spacing for Amex cards using cc-format
👍
Bower.json in releases points to './src/index.js' rather than the released file 'release/angular-credit-cards.js'
This makes binding with gulp's bowerfiles plugin difficult.
If month and year are set as strings not numbers, validation is not in sync.
Like
myCard = {
year: '2019',
month: '10'
};
ccExpMonth.$valid and ccExpYear.$valid are equal to false
.
ccExp.$valid is equal to true
.
Hi, I'm getting the following error when loading the module:
TypeError: Cannot set property 'ccNumber' of undefined
The problem is in this line:
ngModelController.$validators.ccNumber = card.luhn;
Apparently the $validators property was introduced in angular 1.3, but the bower file in the repo requires
"angular": "~1.2.20"
Am I doing something wrong or does the module depend on 1.3?
It works just fine for me with angular 1.3.14 but the bower.json states 1.4.0 is the minimum supported version, is that definitely accurate?
If it is, any idea what bugs I might experience? I haven't noticed any so far.
The documentation for your app is a little unclear about how to properly implement it. Using the examples in the readme, I received two TypeErrors that were due to a missing cc-type attribute. This was also replicated when hosting the plunkr code locally. You list this attribute as optional, but I'm not sure this is the case, can you verify?
Additionally, it would be useful to have a complete quick start example to copy-paste from as included below.
Broken Code
<form name="paymentForm">
<input type="text" ng-model="card.number" name="cardNumber" cc-number cc-eager-type />
<input type="text" ng-model="card.cvc" cc-cvc />
<div cc-exp>
<input ng-model="card.exp_month" cc-exp-month />
<input ng-model="card.exp_year" cc-exp-year />
</div>
</form>
Working Code
<form name="paymentForm">
<input type="text" ng-model="card.number" name="cardNumber" cc-type="cardType" cc-number cc-eager-type />
<input type="text" ng-model="card.cvc" cc-type="cardNumber.$ccType" cc-cvc />
<div cc-exp>
<input ng-model="card.exp_month" cc-exp-month />
<input ng-model="card.exp_year" cc-exp-year />
</div>
</form>
cc-number Error
TypeError: Cannot read property 'exp' of undefined
at ng.config.$provide.decorator.watchFnToHumanReadableString (<anonymous>:703:19)
at Scope.ng.config.$provide.decorator.$delegate.__proto__.$watch (<anonymous>:735:28)
at module.exports.compile (http://192.168.33.10/static/libs/angular-credit-cards/release/angular-credit-cards.js:461:15)
at invokeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:8258:9)
at nodeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:7768:11)
at compositeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:7117:13)
at nodeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:7763:24)
at compositeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:7117:13)
at compositeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:7120:13)
at publicLinkFn (http://192.168.33.10/static/libs/angular/angular.js:6996:30) <input type="text" ng-model="card.number" name="cardNumber" cc-number="" cc-eager-type="" class="ng-pristine ng-untouched ng-valid" pattern="[0-9]*">
cc-cvc Error
TypeError: Cannot read property 'exp' of undefined
at ng.config.$provide.decorator.watchFnToHumanReadableString (<anonymous>:703:19)
at Scope.ng.config.$provide.decorator.$delegate.__proto__.$watch (<anonymous>:735:28)
at module.exports.compile (http://192.168.33.10/static/libs/angular-credit-cards/release/angular-credit-cards.js:318:15)
at invokeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:8258:9)
at nodeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:7768:11)
at compositeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:7117:13)
at nodeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:7763:24)
at compositeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:7117:13)
at compositeLinkFn (http://192.168.33.10/static/libs/angular/angular.js:7120:13)
at publicLinkFn (http://192.168.33.10/static/libs/angular/angular.js:6996:30) <input type="text" ng-model="card.cvc" cc-cvc="" class="ng-pristine ng-untouched ng-valid" maxlength="4" pattern="[0-9]*">
What do you think about auto-selecting the cardType
based on the model passed to cc-type
?
Since the cc-type
already validates the number with the type selected we could just use the cc-type
param in the scope to auto-select it.
I think it would be cool if this was also applied to cc-eager-type
and have a real-time selection.
I can create a PR if you like the idea:
/cc @bendrucker
Hi, using select field in year, onChange fails when you use keydown (stay in month field, select one month, and then, tab key to year field and just keydown. 2015 to 2016 doesn´t call onchange at first time,
neither validations or change of model occurs ).
In order to reproduce this bug, I create this stage: http://plnkr.co/edit/FDtoRFrOUW8gKhOXfNgu?p=preview
Sincerely,
Does it make sense to change maxlength
based on cc-type
?
Not sure if 3 or 4 is a better default when there's no card type — 3 because it's more common, 4 because it's more permissive (like for whatever reason a user fills in the cvc before card type is detected).
The live demo plunker was used to reproduced it. I added cc-format to the card number input and updated the version to the latest one. http://embed.plnkr.co/wXctSM/preview
If you check the inspector, you can see the CSS ng-pristine class is not present but ng-dirty is.
Ben, I would really love to use this library in my Angular browser app. I don't have npm or bower in my project. Is it still possible to use this library? I can't figure out how to view the source javascript files and include them in my project.
Apologies for filing this as an "issue". Let me know if there's a better way to contact you.
You have the following comment in your documentation:
If you're using cc-format, you'll want to apply the novalidate attribute to disable native browser validation.
Is there a reason you couldn't just change the pattern you add to the input to be [0-9 ]
so that browser validation passes the formatted card number? I briefly tested this, and it seems to just work since your card number directive strips spaces that are input anyways.
Thanks so much for making this. I love what I see but getting it to work is a whole other monster. It'd be so much easier and I feel so many more people would take advantage of this if it was just one JS file that I have to include and then add it to my list of modules.
I'm knew to angular and the "installation" side of this is very confusing if you've never used bower/npm. I've been staring at this page for about 30minutes and will probably just end up using jquery.payments :\
package.json depends on angular ~1.4.0, bower.json depends on angular ~1.3.0. Any plans to update bower.json?
4 for Amex, 3 for rest
In the demo, I am trying Maestro demo number - 5018 0000 0009, which is a valid number, but Its showing invalid and unknown.
Demo Link I am trying - http://embed.plnkr.co/uE47aZ/preview
@bbean86 Care to weigh in on how thoroughly you've tested your implementation? I specifically left out any formatting because it adds a ton of complexity. You have to worry about data being pasted in and where the cursor's positioned as users are typing. In order to support this I'd have to get a suite of tests written up with Protractor to even consider releasing it. Before I spend that time I'd like to hear whether you've encountered any issues to date.
Hey Ben,
At the moment I have to store expiration year in my database as two digit number.
I can POST expiration year as 4 digit number but when I make GET, I retrieve that value as two digit number. I know that API could convert two digit number to four digit on GET but at the moment I cannot change anything in API because I don't have access to it.
Now if model value is defined as two digit number, validation of expiration year fails.
To sum up, if I have something like this
$scope.myCard = {
year: 29
// other props...
};
The Value in year input is not set and the whole form is not valid.
Plnkr: http://plnkr.co/edit/t53u0fUfXuyNuY5pCv3Q?p=preview
Simple test which fails
it('is valid for this year defined as two digit number retrieved from the model', function() {
expiration.year = 14;
$scope.$digest();
expect(controller.$valid).to.be.true;
});
I made a fast fix for that specific case. Here is the commit: https://github.com/hinok/angular-credit-cards/commit/2d23bbb377668e0fd26ed24f8fdc545b90391b09
If you want, I can make a PR.
I found that in certain situations (not in your demos for some reason) - more specifically when using angular-material which I think has many more watches/formatters/parsers on the input directive, I can end up with the cursor ending up in the wrong place as it incorrectly tries to move my cursor around.
I found I fixed this issue by changing the $watch for the ccFormat to have the following if statement:
(Line 65 of number.js)
if (formatted && (!formatted.charAt(selectionEnd - 1).trim() || formatted.length !== input.length)) {
Not sure if this will break things or not but it seemed to fix my issue.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.