格式化数字后,将插入符号设置回其原始位置 [英] set caret back to it's original place after formating number

查看:36
本文介绍了格式化数字后,将插入符号设置回其原始位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an input field which has a data manipulation and is a decimal field. Everything works fine except when I put in more than 3 numbers it will lose the current caret and set it to the end of the field because of the field formatting. Example: 123 works fine 1234 will result in 1’234.00 and the caret is after the last 0. How is it possible to set the caret back to its original position? (Between 4 and the .)

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);

<!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>

推荐答案

最简单的方法是取消valueUpdate设置,以便在用户完成编辑数字后进行格式化.

The simplest thing to do is get rid of the valueUpdate setting so that the formatting happens after the user is done editing the number.

要使其交互工作,您需要添加一个input事件处理程序,该事件处理程序

To have it work interactively, you need to add an input event handler that

  1. 查找光标后面有多少个数字(此操作在重新格式化之前发生)
  2. 执行setTimeout来允许重新格式化
  3. 在相同位数后设置光标位置
  1. Finds how many digits are behind the cursor (this happens before reformatting)
  2. Does a setTimeout to allow the reformatting to happen
  3. Sets the cursor position after the same number of digits

还请注意,格式化程序对于很长的数字会变得很奇怪.您可能需要用对的调用来替换它toLocaleString 以及一些其他替换内容.

Also note that your formatter gets weird for very long numbers. You might want to replace it with a call to toLocaleString with some additional substitutions.

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);

  <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
  <input data-bind="value: counterofferPremium, valueUpdate: 'afterkeydown', event: {input: findPlace}" type="text" />

这篇关于格式化数字后,将插入符号设置回其原始位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆