입력의 ng-model에 대한 필터


124

텍스트 입력이 있고 사용자가 공백을 사용하는 것을 원하지 않으며 입력 한 모든 내용이 소문자로 바뀝니다.

예를 들어 ng-model에서 필터를 사용할 수 없다는 것을 알고 있습니다.

ng-model='tags | lowercase | no_spaces'

나는 내 자신의 지시문을 만드는 것을 보았지만 입력에 함수를 추가 $parsers하고 $formatters업데이트하지 않았으며 ng-model그것에있는 다른 요소 만 업데이트 했습니다.

현재 입력중인 입력을 어떻게 변경할 수 있습니까?

저는 본질적으로 여기 StackOverflow의 것과 똑같이 작동하는 '태그'기능을 만들려고합니다.


ng-change와 함께 $ timeout (..., 0)을 사용하면 도움이
되는지 확인하십시오

답변:


28

모델 값을보고 변경시 업데이트하는 것이 좋습니다. http://plnkr.co/edit/Mb0uRyIIv1eK8nTg3Qng?p=preview

유일한 흥미로운 문제는 공백입니다. 입력시 AngularJS 1.0.3 ng-model에서 자동으로 문자열을 트리밍하므로 끝이나 시작에 공백을 추가하면 모델이 변경되었음을 감지하지 못합니다 (따라서 공백은 자동으로 제거되지 않습니다. 암호). 그러나 1.1.1에는이 기능을 비활성화 할 수있는 'ng-trim'지시문이 있습니다 ( commit ). 따라서 질문에서 설명한 정확한 기능을 얻기 위해 1.1.1을 사용하기로 결정했습니다.


이것이 바로 제가 찾던 것입니다. 이미 angularjs 1.1.1을 사용하고 있습니다
Andrew WC Brown

@Valentyn, 귀하의 솔루션은 위의 의견에서 언급 한 SO 질문에 적용되었습니다. 감사. stackoverflow.com/questions/12176925/…
Mark Rajcok 2013 년

이 솔루션은 나쁜 부작용을 가질 수 있습니다. 아래 다른 답변을 참조하십시오. 이에 대한 지시문을 사용해야합니다
pilavdzice

내에서 범위 변수를 $watch다시 할당 하면 리스너가 다시 호출됩니다. 간단한 경우 (필터가 멱등 성인 경우)에는 필터가 수정 될 때마다 두 번 실행됩니다.
2014

204

AngularJS 입력과 ngModeldirecive 의 의도는 유효하지 않은 입력이 모델에서 끝나서는 안된다는 것입니다 . 모델은 항상 유효해야합니다. 잘못된 모델을 갖는 문제는 잘못된 모델을 기반으로 (부적절한) 조치를 취하고 실행하는 감시자가있을 수 있다는 것입니다.

내가보기에 적절한 해결책은 $parsers파이프 라인 에 연결 하고 잘못된 입력이 모델에 들어 가지 않도록하는 것입니다. 나는 당신이 어떻게 접근하려고했는지 또는 정확히 당신에게 효과가 없었던 것이 무엇인지 잘 $parsers모르겠지만 여기에 문제를 해결하는 간단한 지시문이 있습니다 (또는 적어도 문제에 대한 나의 이해).

app.directive('customValidation', function(){
   return {
     require: 'ngModel',
     link: function(scope, element, attrs, modelCtrl) {

       modelCtrl.$parsers.push(function (inputValue) {

         var transformedInput = inputValue.toLowerCase().replace(/ /g, ''); 

         if (transformedInput!=inputValue) {
           modelCtrl.$setViewValue(transformedInput);
           modelCtrl.$render();
         }         

         return transformedInput;         
       });
     }
   };
});

위 지시문이 선언 되 자마자 다음과 같이 사용할 수 있습니다.

<input ng-model="sth" ng-trim="false" custom-validation>

@Valentyn Shybanov가 제안한 솔루션 ng-trim에서와 같이 입력의 시작 / 끝에 공백을 허용하지 않으려면 지시문 을 사용해야합니다 .

이 접근 방식의 장점은 2 배입니다.

  • 잘못된 값은 모델에 전파되지 않습니다.
  • 지시어를 사용하면 감시자를 반복해서 복제하지 않고도 입력에이 사용자 지정 유효성 검사를 쉽게 추가 할 수 있습니다.

1
나는 modelCtrl.$setViewValue(transformedInput); modelCtrl.$render();유용한 부분이 문서에 대한 링크가 될 것이라고 확신합니다 . docs.angularjs.org/api/ng.directive:ngModel.NgModelController 내 솔리 션을 "보호"하기위한 한마디는 범위 속성이 뷰에서뿐만 아니라 변경 될 수 있다는 것입니다. 내 방식대로 이걸 다뤄 그래서 실제 상황에 따라 범위가 어떻게 수정 될 수 있는지에 따라 달라진다고 생각합니다.
Valentyn Shybanov 2013 년

2
예제에서 'modelCtrl'은 무엇을 참조합니까?
GSto 2013 년

4
inputValue는 어디에서 얻습니까?
Dofs

2
@GSto modelCtrl는 지시문에 필요한 컨트롤러입니다. ( require 'ngModel')
Nate-Wilkins 2014

7
유효하지 않은 문자를 입력 할 때마다 커서가 텍스트 필드의 끝으로 이동하고 'world'를 작성하고 'HeLLo world'로 수정하십시오!
Hafez Divandari

23

이 문제에 대한 해결책은 컨트롤러 측에 필터를 적용하는 것입니다.

$scope.tags = $filter('lowercase')($scope.tags);

$filter종속성 으로 선언하는 것을 잊지 마십시오 .


4
하지만 제대로 업데이트하려면 $ watch가 필요합니다.
Mr Mikkél 2014 년

이것은 한 번만 실행됩니다. 시계에 추가하는 것은 초기에도 모델이 무효화 될 수 있기 때문에 올바른 해결책이 아닙니다. 올바른 해결책은 모델의 $ 구문 분석기에 추가하는 것입니다.
icfantv

4
내 대답을 좋아할 필요는 없지만 그것이 틀렸다는 의미는 아닙니다. 반대 투표하기 전에 자존심을 확인하십시오.
icfantv

6

읽기 전용 입력 필드를 사용하는 경우 필터와 함께 ng-value를 사용할 수 있습니다.

예를 들면 :

ng-value="price | number:8"

4

$ formatters 및 $ parsers 컬렉션 모두에 추가하는 지시문을 사용하여 변환이 양방향으로 수행되도록합니다.

jsfiddle에 대한 링크를 포함하여 자세한 내용 은 이 다른 답변 을 참조하십시오.


3

비슷한 문제가 있었고

ng-change="handler(objectInScope)" 

내 처리기에서 objectInScope의 메서드를 호출하여 자신을 올바르게 수정합니다 (거친 입력). 컨트롤러에서 나는 어딘가에서 시작했습니다.

$scope.objectInScope = myObject; 

나는 이것이 어떤 멋진 필터 나 감시자를 사용하지 않는다는 것을 알고있다. 그러나 그것은 간단하고 훌륭하게 작동한다. 이것의 유일한 단점은 objectInScope가 핸들러에 대한 호출로 전송된다는 것입니다.


1

복잡한 비동기 입력 유효성 검사를 수행하는 경우 ng-model자체 유효성 검사 메서드가있는 사용자 지정 클래스의 일부로 한 수준 을 추상화 하는 것이 좋습니다.

https://plnkr.co/edit/gUnUjs0qHQwkq2vPZlpO?p=preview

HTML

<div>

  <label for="a">input a</label>
  <input 
    ng-class="{'is-valid': vm.store.a.isValid == true, 'is-invalid': vm.store.a.isValid == false}"
    ng-keyup="vm.store.a.validate(['isEmpty'])"
    ng-model="vm.store.a.model"
    placeholder="{{vm.store.a.isValid === false ? vm.store.a.warning : ''}}"
    id="a" />

  <label for="b">input b</label>
  <input 
    ng-class="{'is-valid': vm.store.b.isValid == true, 'is-invalid': vm.store.b.isValid == false}"
    ng-keyup="vm.store.b.validate(['isEmpty'])"
    ng-model="vm.store.b.model"
    placeholder="{{vm.store.b.isValid === false ? vm.store.b.warning : ''}}"
    id="b" />

</div>

암호

(function() {

  const _ = window._;

  angular
    .module('app', [])
    .directive('componentLayout', layout)
    .controller('Layout', ['Validator', Layout])
    .factory('Validator', function() { return Validator; });

  /** Layout controller */

  function Layout(Validator) {
    this.store = {
      a: new Validator({title: 'input a'}),
      b: new Validator({title: 'input b'})
    };
  }

  /** layout directive */

  function layout() {
    return {
      restrict: 'EA',
      templateUrl: 'layout.html',
      controller: 'Layout',
      controllerAs: 'vm',
      bindToController: true
    };
  }

  /** Validator factory */  

  function Validator(config) {
    this.model = null;
    this.isValid = null;
    this.title = config.title;
  }

  Validator.prototype.isEmpty = function(checkName) {
    return new Promise((resolve, reject) => {
      if (/^\s+$/.test(this.model) || this.model.length === 0) {
        this.isValid = false;
        this.warning = `${this.title} cannot be empty`;
        reject(_.merge(this, {test: checkName}));
      }
      else {
        this.isValid = true;
        resolve(_.merge(this, {test: checkName}));
      }
    });
  };

  /**
   * @memberof Validator
   * @param {array} checks - array of strings, must match defined Validator class methods
   */

  Validator.prototype.validate = function(checks) {
    Promise
      .all(checks.map(check => this[check](check)))
      .then(res => { console.log('pass', res)  })
      .catch(e => { console.log('fail', e) })
  };

})();

0

당신은 이것을 시도 할 수 있습니다

$scope.$watch('tags ',function(){

    $scope.tags = $filter('lowercase')($scope.tags);

});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.