programing

각도 사용범위 변수를 변경하지 않고 입력 필드의 형식을 지정하는 JS 지시문

lovejava 2023. 10. 21. 09:48

각도 사용범위 변수를 변경하지 않고 입력 필드의 형식을 지정하는 JS 지시문

기본 범위 변수를 포맷하지 않고 입력 필드를 포맷하는 데 문제가 있습니다.

제가 이루고 싶은 것은 통화를 표시하는 텍스트 필드입니다.잘못된 입력을 처리하는 동안, 즉시 포맷해야 합니다.작동은 했지만, 제 문제는 비정형화된 값을 스코프 변수에 저장하고 싶다는 것입니다.입력의 문제는 양방향으로 진행되는 모델이 필요하기 때문에 입력 필드를 변경하면 모델이 업데이트되고 반대로 진행된다는 것입니다.

내가 찾아왔습니다.$parsers그리고.$formatters그게 제가 찾고 있는 것 같네요불행히도 이들은 서로에게 영향을 미치지 않습니다(이는 실제로 무한 루프를 피하는 것이 좋을 수도 있음).

간단한 jsFiddle: http://jsfiddle.net/cruckie/yE8Yj/ 을 만들었고 코드는 다음과 같습니다.

HTML:

<div data-ng-app="app" data-ng-controller="Ctrl">
    <input type="text" data-currency="" data-ng-model="data" />
    <div>Model: {{data}}</div>
</div>

JS:

var app = angular.module("app", []);

function Ctrl($scope) {
    $scope.data = 1234567;
}

app.directive('currency', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attr, ctrl) {

            ctrl.$formatters.push(function(modelValue) {
                return modelValue.toString().replace(/\B(?=(?:\d{3})+(?!\d))/g, ',');
            });

            ctrl.$parsers.push(function(viewValue) {
                return parseFloat(viewValue.replace(new RegExp(",", "g"), ''));
            });
        }
    };
});

다시 말하지만, 이것은 단순한 예시일 뿐입니다.그것이 적재될 때 모든 것이 원래대로 보입니다.입력 필드의 형식은 지정되고 변수는 지정되지 않습니다.그러나 입력 필드의 값을 변경하면 더 이상 자체 형식이 지정되지 않습니다. 그러나 변수는 올바르게 업데이트됩니다.

변수가 그렇지 않은 상태에서 텍스트 필드를 포맷할 수 있는 방법이 있습니까?제가 찾고 있는 것은 텍스트 필드용 필터인 것 같은데, 그 위에 아무것도 안 보이네요.

안부 전합니다

여기 애플리케이션에 동일한 동작을 구현한 방법을 보여주는 fiddle이 있습니다.제가 결국.ngModelController#render대신에$formatters, 그 다음에 다른 행동들을 추가하는 겁니다keydown그리고.change사건.

http://jsfiddle.net/KPeBD/2/

Wade Tandy가 수행한 작업을 약간 수정하고 몇 가지 기능에 대한 지원을 추가했습니다.

  1. 수천 개의 분리판을 $에서 가져갑니다.
  2. 소수점 이후의 자릿수는 기본적으로 $ locale에서 추출되며, 분수 특성에 의해 재정의될 수 있습니다.
  3. 파서는 변경할 때만 활성화되며, 변경할 때마다 입력의 끝에 커서를 보내지 않도록 키다운, 잘라내기 및 붙여넣기에서는 활성화되지 않습니다.
  4. Home(홈) 키와 End(끝) 키도 사용할 수 있습니다(키보드를 사용하여 텍스트 전체를 선택할 수 있음).
  5. 입력이 숫자가 아닌 경우 validity를 false로 설정합니다. 이 작업은 파서에서 수행됩니다.

            // This runs when we update the text field
        ngModelCtrl.$parsers.push(function(viewValue) {
            var newVal = viewValue.replace(replaceRegex, '');
            var newValAsNumber = newVal * 1;
    
            // check if new value is numeric, and set control validity
            if (isNaN(newValAsNumber)){
                ngModelCtrl.$setValidity(ngModelCtrl.$name+'Numeric', false);
            }
            else{
                newVal = newValAsNumber.toFixed(fraction);
                ngModelCtrl.$setValidity(ngModelCtrl.$name+'Numeric', true);
            }
            return newVal;
    
        });
    

여기에서 제 개정판을 보실 수 있습니다 - http://jsfiddle.net/KPeBD/64/

키보드 이벤트를 듣는 대신 $pars와 $formatter를 사용하도록 원래 지시를 수정했습니다.또한 $browser.dfer를 사용할 필요가 없습니다.

여기서 작업 데모 보기 http://jsfiddle.net/davidvotrubec/ebuqo6Lm/

    var myApp = angular.module('myApp', []);

    myApp.controller('MyCtrl', function($scope) {
      $scope.numericValue = 12345678;
    });

    //Written by David Votrubec from ST-Software.com
    //Inspired by http://jsfiddle.net/KPeBD/2/
    myApp.directive('sgNumberInput', ['$filter', '$locale', function ($filter, $locale) {
            return {
                require: 'ngModel',
                restrict: "A",
                link: function ($scope, element, attrs, ctrl) {
                    var fractionSize = parseInt(attrs['fractionSize']) || 0;
                    var numberFilter = $filter('number');
                    //format the view value
                    ctrl.$formatters.push(function (modelValue) {
                        var retVal = numberFilter(modelValue, fractionSize);
                        var isValid = isNaN(modelValue) == false;
                        ctrl.$setValidity(attrs.name, isValid);
                        return retVal;
                    });
                    //parse user's input
                    ctrl.$parsers.push(function (viewValue) {
                        var caretPosition = getCaretPosition(element[0]), nonNumericCount = countNonNumericChars(viewValue);
                        viewValue = viewValue || '';
                        //Replace all possible group separators
                        var trimmedValue = viewValue.trim().replace(/,/g, '').replace(/`/g, '').replace(/'/g, '').replace(/\u00a0/g, '').replace(/ /g, '');
                        //If numericValue contains more decimal places than is allowed by fractionSize, then numberFilter would round the value up
                        //Thus 123.109 would become 123.11
                        //We do not want that, therefore I strip the extra decimal numbers
                        var separator = $locale.NUMBER_FORMATS.DECIMAL_SEP;
                        var arr = trimmedValue.split(separator);
                        var decimalPlaces = arr[1];
                        if (decimalPlaces != null && decimalPlaces.length > fractionSize) {
                            //Trim extra decimal places
                            decimalPlaces = decimalPlaces.substring(0, fractionSize);
                            trimmedValue = arr[0] + separator + decimalPlaces;
                        }
                        var numericValue = parseFloat(trimmedValue);
                        var isEmpty = numericValue == null || viewValue.trim() === "";
                        var isRequired = attrs.required || false;
                        var isValid = true;
                        if (isEmpty && isRequired) {
                            isValid = false;
                        }
                        if (isEmpty == false && isNaN(numericValue)) {
                            isValid = false;
                        }
                        ctrl.$setValidity(attrs.name, isValid);
                        if (isNaN(numericValue) == false && isValid) {
                            var newViewValue = numberFilter(numericValue, fractionSize);
                            element.val(newViewValue);
                            var newNonNumbericCount = countNonNumericChars(newViewValue);
                            var diff = newNonNumbericCount - nonNumericCount;
                            var newCaretPosition = caretPosition + diff;
                            if (nonNumericCount == 0 && newCaretPosition > 0) {
                                newCaretPosition--;
                            }
                            setCaretPosition(element[0], newCaretPosition);
                        }
                        return isNaN(numericValue) == false ? numericValue : null;
                    });
                } //end of link function
            };
            //#region helper methods
            function getCaretPosition(inputField) {
                // Initialize
                var position = 0;
                // IE Support
                if (document.selection) {
                    inputField.focus();
                    // To get cursor position, get empty selection range
                    var emptySelection = document.selection.createRange();
                    // Move selection start to 0 position
                    emptySelection.moveStart('character', -inputField.value.length);
                    // The caret position is selection length
                    position = emptySelection.text.length;
                }
                else if (inputField.selectionStart || inputField.selectionStart == 0) {
                    position = inputField.selectionStart;
                }
                return position;
            }
            function setCaretPosition(inputElement, position) {
                if (inputElement.createTextRange) {
                    var range = inputElement.createTextRange();
                    range.move('character', position);
                    range.select();
                }
                else {
                    if (inputElement.selectionStart) {
                        inputElement.focus();
                        inputElement.setSelectionRange(position, position);
                    }
                    else {
                        inputElement.focus();
                    }
                }
            }
            function countNonNumericChars(value) {
                return (value.match(/[^a-z0-9]/gi) || []).length;
            }
            //#endregion helper methods
        }]);

Github 코드는 여기 [https://github.com/ST-Software/STAngular/blob/master/src/directives/SgNumberInput ]

정말로$parsers그리고.$formatters당신이 말하는 대로 "독립적"입니다(루프에 대한 probably, 당신이 말하는 대로 다시).우리의 애플리케이션에서 우리는 명시적으로 다음과 같이 포맷합니다.onchange이벤트(inside 더link함수), 대략 다음과 같습니다.

element.bind("change", function() {
    ...
    var formattedModel = format(ctrl.$modelValue);
    ...
    element.val(formattedModel);
});

자세한 내용과 작동 예는 업데이트된 fiddle을 참조하십시오. http://jsfiddle.net/yE8Yj/1/

저는 에 묶는 것을 좋아합니다.onchange이벤트, 사용자가 입력할 때 입력을 변경하는 것이 귀찮기 때문입니다.

피들은 이전 버전의 각도(1.0.7)를 사용하고 있습니다.

ngModelCtrl의 $render 함수는 최신 버전인 1.2.6으로 업데이트할 때 결코 호출되지 않습니다. 즉, 컨트롤러에서 모델 값이 변경될 경우,

보기에서 필요에 따라 번호 형식이 지정되지 않습니다.

//check if new value is numeric, and set control validity
if (isNaN(newValAsNumber)){
  ngModelCtrl.$setValidity(ngModelCtrl.$name+'Numeric', false);
}

업데이트된 fiddle http://jsfiddle.net/KPeBD/78/ 입니다.

Wade Tandy의 답변을 바탕으로 다음과 같은 개선점이 있는 새로운 jspidle을 소개합니다.

  • 가능한 십진법
  • 현지인을 기준으로 수천 개의 구분자와 소수점 구분자
  • 그리고 다른 수정사항들도...

또한 모든 것을 교체했습니다.String.replace(regex)타고split().join(), 이것은 제가 그 표현에 변수를 사용할 수 있게 해주기 때문입니다.

http://jsfiddle.net/KPeBD/283/

언급URL : https://stackoverflow.com/questions/19094150/using-angularjs-directive-to-format-input-field-while-leaving-scope-variable-unc