在格式编号后将插入符号设置回原来的位置

时间:2017-10-03 16:11:26

标签: javascript html knockout.js numbers

我有一个输入字段,它有一个数据操作并且是一个十进制字段。一切正常,但是当我输入3个以上的数字时,由于字段格式化,它会丢失当前的插入符并将其设置为字段的末尾。 例: 123工作正常 1234将导致1'234.00并且插入符号位于最后0之后。如何将插入符号设置回其原始位置? (在4和之间。)



function thousenderSign(number) {
  number = '' + number;
  if (number.length > 3) {
    var mod = number.length % 3;
    var output = (mod > 0 ? (number.substring(0, mod)) : '');
    for (i = 0; i < Math.floor(number.length / 3); i++) {
      if ((mod == 0) && (i == 0)) {
        output += number.substring(mod + 3 * i, mod + 3 * i + 3);
      } else {
        output += "'" + number.substring(mod + 3 * i, mod + 3 * i + 3); // set the sign
      }
    }
    return (output);
  } else return number;
}
ko.extenders.numeric = function(target, precision) {
  var result = ko.pureComputed({
    read: target,
    write: function(newValue) {
      var current = target();
      var roundingMultiplier = Math.pow(10, precision);
      var newValueAsNum = null;

      if (newValue !== undefined && newValue !== 0 && newValue !== null) {
        newValueAsNum = newValue.toString().replace("'", "");
        // provide only int fort he function
        var onlyInt = newValueAsNum.split(".");
        // Remove more then 2 digits after the dot
        if (onlyInt.length > 1 && onlyInt[1].length > 2) {
          onlyInt[1] = onlyInt[1].toString().substring(0, 2);
        }
      }

      var valueToWrite = (Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier) === 0 ? null : Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;

      // thousender sign
      if (newValueAsNum !== null && newValueAsNum.length > 3) {
        valueToWrite = thousenderSign(onlyInt[0]) + "." + (onlyInt.length > 1 ? onlyInt[1] : '00');
      }
      if (valueToWrite !== current) {
        target(valueToWrite);
      } else {
        if (newValue !== current) {
          target.notifySubscribers(valueToWrite);
        }
      }
    }
  }).extend({
    notify: 'always'
  });
  result(target());
  return result;
};


function ExampleViewModel() {
  self = this;
  self.counterofferPremium = ko.observable().extend({
    numeric: 2
  });
};

var viewModel = new ExampleViewModel();
ko.applyBindings(viewModel);
&#13;
<!doctype html>
<html>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
</head>

<body>
  <input data-bind="value: counterofferPremium, valueUpdate: 'afterkeydown'" type="text" />
</body>

</html>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:2)

最简单的做法是摆脱valueUpdate设置,以便在用户完成编辑后完成格式化。

要让它以交互方式工作,您需要添加一个<{1}}事件处理程序

  1. 查找光标后面有多少位数(这在重新格式化之前发生)
  2. input是否允许重新格式化
  3. 设置相同位数后的光标位置
  4. 另请注意,对于非常长的数字,格式化程序会变得奇怪。您可能希望将其替换为toLocaleString,并进行一些额外的替换。

    &#13;
    &#13;
    setTimeout
    &#13;
    function thousenderSign(number) {
      number = '' + number;
      if (number.length > 3) {
        var mod = number.length % 3;
        var output = (mod > 0 ? (number.substring(0, mod)) : '');
        for (i = 0; i < Math.floor(number.length / 3); i++) {
          if ((mod == 0) && (i == 0)) {
            output += number.substring(mod + 3 * i, mod + 3 * i + 3);
          } else {
            output += "'" + number.substring(mod + 3 * i, mod + 3 * i + 3); // set the sign
          }
        }
        return (output);
      } else return number;
    }
    ko.extenders.numeric = function(target, precision) {
      var result = ko.pureComputed({
        read: target,
        write: function(newValue) {
          var current = target();
          var roundingMultiplier = Math.pow(10, precision);
          var newValueAsNum = null;
    
          if (newValue !== undefined && newValue !== 0 && newValue !== null) {
            newValueAsNum = newValue.toString().replace("'", "");
            // provide only int fort he function
            var onlyInt = newValueAsNum.split(".");
            // Remove more then 2 digits after the dot
            if (onlyInt.length > 1 && onlyInt[1].length > 2) {
              onlyInt[1] = onlyInt[1].toString().substring(0, 2);
            }
          }
    
          var valueToWrite = (Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier) === 0 ? null : Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
    
          // thousender sign
          if (newValueAsNum !== null && newValueAsNum.length > 3) {
            valueToWrite = thousenderSign(onlyInt[0]) + "." + (onlyInt.length > 1 ? onlyInt[1] : '00');
          }
          if (valueToWrite !== current) {
            target(valueToWrite);
          } else {
            if (newValue !== current) {
              target.notifySubscribers(valueToWrite);
            }
          }
        }
      }).extend({
        notify: 'always'
      });
      result(target());
      return result;
    };
    
    function ExampleViewModel() {
      self = this;
      self.counterofferPremium = ko.observable().extend({
        numeric: 2
      });
      self.findPlace = function (data, event) {
        const pos = event.target.selectionEnd;
        var numbersBeforePos = event.target.value.substr(0, pos).replace(/\D/g, '').length;
        setTimeout(function() {
          const formattedValue = event.target.value;
          const numbersNow = event.target.value.replace(/\D/g, '').length;
          
          if (numbersNow >= numbersBeforePos) {
            // find the numbersBeforePos-th number
            const re = /\d/g;
            var newPos;
            while (numbersBeforePos--) {
              newPos = 1 + re.exec(formattedValue).index;
            }
            event.target.setSelectionRange(newPos, newPos);
          }
        }, 0);
      };
    };
    
    var viewModel = new ExampleViewModel();
    ko.applyBindings(viewModel);
    &#13;
    &#13;
    &#13;