You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular输入框光标位置设置异常及onlyDecimal指令问题求助

Fixing Cursor Position in Angular's onlyDecimal Directive

Hey there, I’ve run into this exact cursor jump issue with input directives before—let’s get it sorted out for you. The core problem is that when you modify the input value (cleaning out invalid characters), the browser defaults to resetting the cursor to the end of the input. We need to manually calculate and set the correct position after processing the value.

Here’s the revised version of your directive with cursor position fixes and some extra decimal validation logic (like preventing multiple dots):

myApp.directive('onlyDecimal', function ($timeout) {
    return {
        require: '?ngModel',
        link: function(scope, element, attrs, ngModelCtrl) {
            if(!ngModelCtrl) {
                return;
            }

            ngModelCtrl.$parsers.push(function(val) {
                // Handle undefined or null values gracefully
                const originalVal = val || '';
                let clean = originalVal.replace(/[^0-9.]/g, '');
                
                // Ensure only one decimal point exists
                clean = clean.replace(/(\..*)\./g, '$1');

                // Only proceed if the value actually changed
                if (clean !== originalVal) {
                    ngModelCtrl.$setViewValue(clean);
                    ngModelCtrl.$render();

                    // Wait for Angular to update the DOM before adjusting cursor
                    $timeout(() => {
                        const originalCursorPos = element[0].selectionStart;
                        const charRemovedCount = originalVal.length - clean.length;
                        
                        // Calculate adjusted cursor position: subtract removed characters, but clamp to valid range
                        let adjustedPos = originalCursorPos - charRemovedCount;
                        adjustedPos = Math.max(0, Math.min(adjustedPos, clean.length));
                        
                        // Set the cursor to the correct position
                        element[0].setSelectionRange(adjustedPos, adjustedPos);
                    });
                }

                // Return cleaned value to the model (null for empty input)
                return clean === '' ? null : clean;
            });
        }
    };
});

Key Fixes & Explanations:

  • Prevent Multiple Decimal Points: The regex replace(/(\..*)\./g, '$1') ensures users can’t type more than one dot, which is essential for decimal inputs and avoids weird cursor jumps from unexpected value truncation.
  • $timeout for DOM Sync: When we call $setViewValue and $render, Angular needs a digest cycle to update the input’s DOM value. Using $timeout delays the cursor adjustment until after the DOM is updated, so we’re working with the fresh cleaned value.
  • Accurate Cursor Calculation: We compare the original value length to the cleaned length to find how many characters were removed, then adjust the cursor position accordingly. The Math.max/Math.min ensures we don’t set the cursor outside the bounds of the input content.
  • Graceful Edge Cases: Handles undefined/null values and returns null for empty inputs to align with Angular’s ngModel behavior.

Optional Extra: Auto-Pad Leading Zero

If you want to handle cases where users type .5 instead of 0.5, you can add this line right after cleaning the value:

if (clean.startsWith('.')) clean = '0' + clean;

This will automatically prepend a zero, and the cursor logic will still work correctly since we’re adjusting based on length differences.

内容的提问来源于stack exchange,提问作者J.Do

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:47:13