bir girişte ng modeli üzerinde filtreler


124

Bir metin girdim var ve kullanıcıların boşluk kullanmasına izin vermek istemiyorum ve yazılan her şey küçük harfe dönüştürülecek.

Ng modelinde filtre kullanmama izin verilmediğini biliyorum, örn.

ng-model='tags | lowercase | no_spaces'

Benim kendi yönergesini oluşturarak, ancak işlevleri ekleyerek baktı $parsersve $formattersgirişi vardı sadece diğer unsurlar güncelleme vermedi ng-modelüzerinde.

Şu anda yazmakta olduğum girişi nasıl değiştirebilirim?

Esasen, StackOverflow'da olduğu gibi çalışan 'etiketler' özelliğini oluşturmaya çalışıyorum.


Ng-change ile $ timeout (..., 0) kullanmanın yardımcı olup olmadığına bakın: stackoverflow.com/questions/12176925/…
Mark Rajcok

Yanıtlar:


28

Model değerini izlemenizi ve değişiklik üzerine güncellemenizi öneririm: http://plnkr.co/edit/Mb0uRyIIv1eK8nTg3Qng?p=preview

Tek ilginç sorun boşluklarla ilgilidir: AngularJS 1.0.3 ng-modelinde girdi otomatik olarak dizeyi kırpar, böylece sonunda veya başlangıçta boşluk eklerseniz modelin değiştirildiğini algılamaz (bu nedenle boşluklar benim tarafından otomatik olarak kaldırılmaz. kodu). Ancak 1.1.1'de bu işlevselliği ( commit ) devre dışı bırakmaya izin veren 'ng-trim' direktifi vardır . Bu yüzden, sorunuzda tanımladığınız işlevselliği tam olarak elde etmek için 1.1.1 kullanmaya karar verdim.


Bu tam olarak aradığım şeydi. Görünüşe göre zaten angularjs 1.1.1
Andrew WC Brown

@Valentyn, çözümünüz yukarıdaki yorumda bahsettiğim SO sorusuna uygulandı. Teşekkürler. stackoverflow.com/questions/12176925/…
Mark Rajcok

bu çözümün kötü yan etkileri olabilir, aşağıdaki diğer cevaba bakın, bunun için bir yönerge kullanmalısınız
pilavdzice

Kapsam değişkeninin içeriden yeniden atanması $watch, dinleyiciyi yeniden çağrılmaya zorlar. Basit durumlarda (filtrenizin idempotent olduğu durumlarda), filtrenin her değişiklikte iki kez çalışmasıyla sonuçlanırsınız.
enkarne

204

AngularJS girdilerinin ve ngModelyönergesinin amacının, geçersiz girdinin modelde asla bitmemesi olduğuna inanıyorum . Model her zaman geçerli olmalıdır. Geçersiz modele sahip olmakla ilgili sorun, geçersiz modele dayanarak ateş açan ve (uygunsuz) eylemler gerçekleştiren izleyicilerimiz olabilir.

Gördüğüm kadarıyla, buradaki doğru çözüm, $parsersardışık düzene bağlamak ve geçersiz girişin onu modele dahil etmediğinden emin olmaktır. Bir şeylere nasıl yaklaşmaya çalıştığından veya neyin işe yaramadığından emin değilim $parsersama işte probleminizi çözen basit bir yönerge (veya en azından benim problemi anladığım):

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

Yukarıdaki yönerge ilan edilir edilmez şu şekilde kullanılabilir:

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

@Valentyn Shybanov tarafından önerilen çözümde olduğu gibi, girdinin ng-trimbaşında / sonunda boşluklara izin vermemek istiyorsak yönergeyi kullanmamız gerekir .

Bu yaklaşımın avantajı 2 katlıdır:

  • Geçersiz değer modele yayılmaz
  • Bir yönerge kullanarak, bu özel doğrulamayı, izleyenleri tekrar tekrar kopyalamadan herhangi bir girdiye eklemek kolaydır.

1
Eminim ki modelCtrl.$setViewValue(transformedInput); modelCtrl.$render();yararlı kısım Useful ile dokümantasyona bağlantı olacaktır: docs.angularjs.org/api/ng.directive:ngModel.NgModelController Tek sözümü "korumak" için bir kelime, kapsam özelliğinin yalnızca görünümlerden ve benim yolum bunu örtmek. Dolayısıyla, kapsamın nasıl değiştirilebileceğinin gerçek bir duruma bağlı olduğunu düşünüyorum.
Valentyn Shybanov

2
Örneğinizde 'modelCtrl' neyi ifade ediyor?
GSto

4
İnputValue'yu nereden alıyorsunuz?
Dofs

2
@GSto modelCtrl, direktifin gerektirdiği denetleyicidir. ( require 'ngModel')
Nate-Wilkins

7
İmleç, geçersiz bir karakter yazdığınız her seferde metin alanının sonuna atlar, 'dünya' yazmayı deneyin ve onu 'HeLLo dünyası' olarak değiştirin!
Hafez Divandari

23

Bu soruna bir çözüm, filtreleri denetleyici tarafında uygulamak olabilir:

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

$filterBağımlılık ilan etmeyi unutmayın .


4
Ancak düzgün bir şekilde güncellenmesini istiyorsanız üzerinde bir $ watch'a ihtiyacınız olacak.
Bay Mikkél

bu yalnızca bir kez gerçekleştirilir. ve bir saate eklemek doğru çözüm değildir, çünkü başlangıçta bile modelin geçersiz olmasına izin verir - doğru çözüm, modelin $ ayrıştırıcılarına eklemektir.
icfantv

4
Cevabımı beğenmek zorunda değilsin, ama bu yanlış olduğu anlamına gelmez. Eksi oy kullanmadan önce egonuzu kontrol edin.
icfantv

6

Salt okunur giriş alanı kullanıyorsanız filtre ile ng değerini kullanabilirsiniz.

Örneğin:

ng-value="price | number:8"

4

Dönüşümün her iki yönde de gerçekleştirildiğinden emin olmak için hem $ formatters hem de $ parsers koleksiyonlarına ekleyen bir yönerge kullanın.

Jsfiddle'a bir bağlantı da dahil olmak üzere daha fazla ayrıntı için bu diğer yanıta bakın .


3

Benzer bir sorun yaşadım ve kullandım

ng-change="handler(objectInScope)" 

işleyicimde, kendisini doğru şekilde değiştirmek için objectInScope'un bir yöntemini çağırıyorum (kaba girdi). Denetleyicide bir yerde başlattım ki

$scope.objectInScope = myObject; 

Bunun herhangi bir süslü filtre veya izleyici kullanmadığını biliyorum ... ama basit ve harika çalışıyor. Bunun tek dezavantajı, objectInScope'un çağrıda işleyiciye gönderilmesidir ...


1

Karmaşık, zaman uyumsuz giriş doğrulaması yapıyorsanız ng-model, kendi doğrulama yöntemlerine sahip özel bir sınıfın parçası olarak bir seviye soyutlamaya değer olabilir .

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>

kod

(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

Bunu deneyebilirsin

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

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

});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.