एक इनपुट में एनजी-मॉडल पर फिल्टर


124

मेरे पास एक पाठ इनपुट है और मैं उपयोगकर्ताओं को रिक्त स्थान का उपयोग करने की अनुमति नहीं देना चाहता हूं, और टाइप किया गया सब कुछ लोअरकेस में बदल जाएगा।

मुझे पता है कि मुझे एनजी-मॉडल जैसे उदाहरणों पर फ़िल्टर का उपयोग करने की अनुमति नहीं है।

ng-model='tags | lowercase | no_spaces'

मैंने अपने स्वयं के निर्देश बनाने के लिए देखा, लेकिन उन कार्यों को जोड़ना $parsersऔर $formattersइनपुट को अद्यतन नहीं किया, केवल अन्य तत्व जो उस ng-modelपर थे ।

मैं उस समय के इनपुट को कैसे बदल सकता हूं, जिसमें मैं अभी टाइप कर रहा हूं?

मैं मूल रूप से 'टैग' फीचर बनाने की कोशिश कर रहा हूं जो स्टैकऑवरफ्लो पर यहां की तरह काम करता है।


देखें कि क्या $
-टाइमआउट

जवाबों:


28

मैं मॉडल मूल्य देखने और इसे चेज पर अपडेट करने का सुझाव दूंगा: http://plnkr.co/edit/Mb0uRyIIv1eK8nTg3Qng?p=preview

एकमात्र दिलचस्प मुद्दा रिक्त स्थान के साथ है: इनपुट पर AngularJS 1.0.3 एनजी-मॉडल स्वचालित रूप से स्ट्रिंग को ट्रिम कर देता है, इसलिए यह पता नहीं लगाता है कि यदि आप अंत में या शुरुआत में स्थान जोड़ते हैं तो मॉडल बदल गया था (इसलिए रिक्त स्थान स्वचालित रूप से मेरे द्वारा हटाए नहीं गए हैं कोड)। लेकिन 1.1.1 में 'एनजी-ट्रिम' निर्देश है जो इस कार्यक्षमता ( कमिट ) को अक्षम करने की अनुमति देता है । इसलिए मैंने आपके प्रश्न में वर्णित सटीक कार्यक्षमता प्राप्त करने के लिए 1.1.1 का उपयोग करने का निर्णय लिया है।


यह वास्तव में मैं क्या देख रहा था। यह पता चला है कि मैं पहले ही एंगुलरज 1.1.1 का उपयोग कर रहा हूं
एंड्रयू डब्ल्यूसी ब्राउन

@ वालेंटिन, आपके समाधान ने एसओ प्रश्न पर लागू किया था जो मैंने ऊपर टिप्पणी में संदर्भित किया था। धन्यवाद। stackoverflow.com/questions/12176925/…
मार्क राजकोक

इस समाधान के दुष्प्रभाव हो सकते हैं, नीचे दिए गए अन्य उत्तर देखें, आपको इसके लिए एक निर्देश का उपयोग करना चाहिए
pilavdzice

फिर से स्कोप रेज़िंग वैरिएबल $watchश्रोता को फिर से आमंत्रित करने के लिए मजबूर करता है। साधारण मामलों में (जहां आपका फ़िल्टर बेकार है) आप हर संशोधन पर दो बार निष्पादित निष्पादन के साथ समाप्त हो जाएंगे।
अवतार

204

मेरा मानना ​​है कि ngModelएंगुलरजेएस इनपुट्स और डाइरेक्टिव का आशय यह है कि अमान्य इनपुट को मॉडल में कभी खत्म नहीं होना चाहिए । मॉडल हमेशा मान्य होना चाहिए। अमान्य मॉडल के साथ समस्या यह है कि हमारे पास वॉचर्स हो सकते हैं जो अमान्य मॉडल के आधार पर आग और अनुचित (अनुचित) क्रियाएं करते हैं।

जैसा कि मैंने देखा है, यहाँ उचित समाधान $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 एक शब्द "मेरे" को बचाने के लिए "गुंजाइश" है कि गुंजाइश संपत्ति को केवल विचारों से नहीं बदला जा सकता है और मेरा रास्ता यह है। इसलिए मुझे लगता है कि यह एक वास्तविक स्थिति पर निर्भर करता है कि कैसे गुंजाइश को संशोधित किया जा सकता है।
वैलेंटाइन श्योनोव

2
'ModelCtrl' आपके उदाहरण में क्या दर्शाता है?
GSto

4
आपको इनपुटवैल्यू कहां से मिलेगा?
1913 को डॉफ्स

2
@GSto modelCtrlनिर्देश द्वारा आवश्यक नियंत्रक है। ( require 'ngModel')
नैट-विल्किंस

7
हर बार जब आप एक अमान्य चरित्र लिखते हैं, तो टेक्स्ट फ़ील्ड के अंत में कर्सर कूदता है, 'दुनिया' लिखने की कोशिश करें और इसे 'HeLLo दुनिया' में बदलें!
हाफिज दिवानंदरी

23

इस समस्या का हल नियंत्रक पक्ष पर फ़िल्टर लागू करने के लिए हो सकता है:

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

$filterनिर्भरता के रूप में घोषित करने के लिए मत भूलना ।


4
लेकिन अगर आप इसे ठीक से अपडेट करना चाहते हैं तो आपको इस पर $ वॉच की आवश्यकता होगी।
श्री मिकेल

इसे केवल एक बार निष्पादित किया जाता है। और घड़ी में जोड़ना सही समाधान नहीं है क्योंकि यह, यहां तक ​​कि शुरू में, मॉडल को अमान्य बनने की अनुमति देता है - सही समाधान मॉडल के $ पार्सर्स में जोड़ना है।
icfantv

4
आपको मेरा उत्तर पसंद नहीं है, लेकिन इसका मतलब यह नहीं है कि यह गलत है। नीचे उतरने से पहले अपने अहंकार की जाँच करें।
icfantv 17

6

यदि आप केवल इनपुट फ़ील्ड रीड पढ़ रहे हैं, तो आप फ़िल्टर के साथ एनजी-वैल्यू का उपयोग कर सकते हैं।

उदाहरण के लिए:

ng-value="price | number:8"

4

एक निर्देश का उपयोग करें, जो $ $ स्वरूप और $ पार्सर्स संग्रह दोनों को जोड़ता है ताकि यह सुनिश्चित हो सके कि परिवर्तन दोनों दिशाओं में किया गया है।

Jsfiddle के लिंक सहित अधिक जानकारी के लिए यह अन्य उत्तर देखें ।


3

मुझे भी इसी तरह की समस्या थी और मैंने इसका इस्तेमाल किया

ng-change="handler(objectInScope)" 

अपने हैंडलर में मैं खुद को सही तरीके से (मोटे इनपुट) संशोधित करने के लिए ऑब्जेक्टइन्स्कोप की एक विधि कहता हूं। नियंत्रक में मैंने कहीं पर पहल की है

$scope.objectInScope = myObject; 

मुझे पता है कि यह किसी भी फैंसी फिल्टर या वॉचर्स का उपयोग नहीं करता है ... लेकिन यह सरल है और बढ़िया काम करता है। इसका केवल एक ही पक्ष यह है कि objectInScope को हैंडलर को कॉल में भेजा जाता है ...


1

यदि आप जटिल, async इनपुट सत्यापन कर रहे हैं, तो यह हो सकता है कि यह ng-modelकस्टम वर्ग के एक स्तर के रूप में अपने सत्यापन विधियों के साथ सार करने के लिए लायक हो ।

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

एचटीएमएल

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

})();

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.