JSFiddle - React, Tailwind, and code Playground

by Evan Sharp

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<div ng-app="step">
    <input type="number" step="{{step}}" ng-model="idk"/>
    <input type="number" step="1.5" ng-model="step"/>
</div>

JavaScript

angular.module('step', [])
  .directive('step', step);

function step() {
  return {
    require: '?ngModel',
    restrict: 'A',
    link: function (scope, elem, attrs, ctrl) {
      if (!ctrl) {
        return;
      }

      if (ctrl.$$hasNativeValidators) {
        ctrl.$validators.step = function() {
          return elem[0].validity.stepMismatch === false;
        };
      } else {
        var step;
        ctrl.$validators.step = function(val) {
          return ctrl.$isEmpty(val) || angular.isUndefined(step) || floatSafeRemainder(val, step);
        };

        attrs.$observe('step', function (val) {
          if (angular.isDefined(val) && !angular.isNumber(val)) {
            val = parseFloat(val);
          }
          step = angular.isNumber(val) && !isNaN(val) && val > 0 ? val : undefined;
          ctrl.$validate();
        });
      }
        
      function floatSafeRemainder(val, step){
        var valDecCount = (val.toString().split('.')[1] || '').length;
        var stepDecCount = (step.toString().split('.')[1] || '').length;
        var decCount = valDecCount > stepDecCount? valDecCount : stepDecCount;
        var valInt = parseInt(val.toFixed(decCount).replace('.',''));
        var stepInt = parseInt(step.toFixed(decCount).replace('.',''));
        return (valInt % stepInt) / Math.pow(10, decCount);
      }
    }
  };
}