2017-10-03 5 views
1

私はデータ操作を持つ入力フィールドを持ち、小数フィールドです。 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);
<!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>

+0

あなたが元の位置とはどういう意味ですか? 3文字未満の数字の場合は表示されません。どのように元の位置を決定しますか? – LiverpoolOwen

+0

これはエクステンダで行うことができるのか分かりません。キャレットの位置を設定するには、要素への参照が必要になります。そのため、代わりにカスタムバインドで行う必要があります。 –

答えて

2

最も簡単な方法は、valueUpdate設定を取り除くれます。それは対話的に動作していることが

、あなたは

  • (これは再フォーマットする前に起こる)

    1. は、多くの桁がカーソルの後ろにあるかを検索していることinputイベントハンドラを追加する必要がありますに再フォーマットを許可するようにsetTimeoutをい

    はまた、あなたのフォーマッタがために奇妙な取得することに注意して同じ桁数の後にカーソル位置を設定します起こります非常に長い数字。 toLocaleStringへの呼び出しで置き換えることもできます。

    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" />

  • 関連する問題