Как заставить угловую маску работать с разными кредитными картами?

Я использую AngularUI Mask (https://github.com/angular-ui/ui-mask) в поле кредитной карты.

<input type="text" placeholder="xxxx-xxxx-xxxx-xxxx" ui-mask="9999-9999-9999-9999" ng-model="card.number">

Но, согласно Stripe (https://stripe.com/docs/testing), не все карты имеют 16 цифры. Как я могу разрешить пользователям вводить от 14 до 16 цифр и автоматически форматировать их как:

  • xxxx-xxxxxx-xxxxx для American Express
  • xxxx-xxxx-xxxx-xx для Diners Club
  • xxxx-xxxx-xxxx-xxxx для всего остального

Plnkr: http://plnkr.co/edit/Qx9lv7t4jGDwtj8bvQSv?p=preview


person trs    schedule 28.01.2016    source источник
comment
первые несколько цифр в CC говорят вам, какой это тип карты (например, все карты VISA начинаются с 4). это скажет вам, что вам нужно сделать, чтобы отформатировать его.   -  person Marc B    schedule 28.01.2016
comment
Вы действительно хотите клиентов, у которых есть Amex или Diner's Club? ;)   -  person Jonathan M    schedule 28.01.2016
comment
@MarcB - Хорошо, спасибо, как мне работать с Маской в ​​контроллере?   -  person trs    schedule 28.01.2016
comment
@JonathanM - к сожалению, приходится;)   -  person trs    schedule 28.01.2016
comment
сомневаюсь, что вы могли бы использовать маску пользовательского интерфейса, поскольку потенциально существует 3 версии ввода. в лучшем случае вы можете произносить только цифры и пробелы, а затем переформатировать в соответствующий стиль.   -  person Marc B    schedule 28.01.2016
comment
Я полагаю, вы могли бы инициировать событие для keyup и keydown, которое проверяет первую цифру и изменяет атрибуты в зависимости от типа карты.   -  person Jonathan M    schedule 28.01.2016


Ответы (1)


Самый простой способ - использовать переменную в области действия вашего контроллера для значения маски. Следите за значением номера копии и динамически меняйте маску в зависимости от типа карты. Чтобы это сработало, вы должны отключить проверку ui-mask через ui-options. Затем $scope.$watch() значение номера карты по мере его изменения.

Чтобы определить тип карты. Для более надежного подхода вы можете использовать более подробную библиотеку, например тип кредитной карты

function getCreditCardType(creditCardNumber) { 
  // start without knowing the credit card type
  var result = "unknown";

  // first check for MasterCard
  if (/^5[1-5]/.test(creditCardNumber)) {
    result = "mastercard";
  } 
  // then check for Visa
  else if (/^4/.test(creditCardNumber)) {
    result = "visa";
  }
  // then check for AmEx
  else if (/^3[47]/.test(creditCardNumber)) {
    result = "amex";
  } 
  // then check for Diners
  else if (/3(?:0[0-5]|[68][0-9])[0-9]{11}/.test(creditCardNumber)) { 
    result = "diners"
  }
  // then check for Discover
  else if (/6(?:011|5[0-9]{2})[0-9]{12}/.test(creditCardNumber)) {
    result = "discover";
  } 

  return result;
}

Затем измените переменную маски в соответствии с требованиями конкретного типа карты.

function getMaskType(cardType){
  var masks = {
    'mastercard': '9999 9999 9999 9999',
    'visa': '9999 9999 9999 9999',
    'amex': '9999 999999 99999',
    'diners': '9999 9999 9999 99',
    'discover': '9999 9999 9999 9999',
    'unknown': '9999 9999 9999 9999'
  };
  return masks[cardType];
}

Соберите все это в своем контроллере.

myApp.controller("myCtrl", function($scope) {
  $scope.cc = {number:'', type:'', mask:''};
  $scope.maskOptions = {
    allowInvalidValue:true //allows us to watch the value
  };
  $scope.$watch('cc.number', function(newNumber){
    $scope.cc.type = getCreditCardType(newNumber);
    $scope.cc.mask = getMaskType($scope.cc.type);
  });
});

И HTML будет выглядеть так:

<input ng-model="cc.number" ui-mask="{{cc.mask}}" ui-options="maskOptions" />

Пример: https://jsfiddle.net/gq42wbL5/18/.

person ndmweb    schedule 19.03.2017
comment
Огромное спасибо. Это было очень полезно. Работает как шарм. - person tabish89; 05.06.2018
comment
@ndmweb - это довольно неприятно, когда вы пытаетесь вставить кредитную карту во вход. какой-нибудь обходной путь? - person james; 08.08.2018