2014-04-08 13 views
12

के साथ कर्सर स्थिति को संरक्षित करना निम्नलिखित स्निपेट करता है जो मैं input चाहता हूं, यानी, यह सभी गैर-अल्फान्यूमेरिकल वर्णों को हटा देता है, अपरकेस में परिवर्तित होता है, और कर्सर की स्थिति को संरक्षित करता है।angularjs

element = $(element); 

element.keyup(function() { 
    var x = element.val(); 
    var y = x && x.toUpperCase().replace(/[^A-Z\d]/g, ''); 
    if (x===y) return; 
    var start = this.selectionStart; 
    var end = this.selectionEnd + y.length - x.length; 
    element.val(y); 
    this.setSelectionRange(start, end); 
}); 

मैं एक निर्देश के link में इस स्निपेट रखा जाता है और यह काम करता है .... ज्यादातर।

समस्या यह है कि angular मॉडल से पहले मान को लागू करता है। मैंने Google को $apply या $digest या यहां जो भी कुछ भी उपयोग करने के लिए Google की कोशिश की, लेकिन कुछ भी काम नहीं किया।

(वास्तव में, मैं किसी भी तरह यह कामयाब रहे, लेकिन फिर सामग्री को फिर से गाया गया था और मैं स्थिति को खो दिया। मैं इसे पुन: पेश नहीं कर सकते हैं, लेकिन यह वैसे भी, काफी अच्छा नहीं था।)

उत्तर

21

जहां

  • इनपुट केवल इनपुट पर एक बार साफ किया जाता है
  • ngChange ऐसा करने का एक तरीका तो है ही एक बार गोली चलाई

$parsers सरणी का उपयोग करने कि ngModelController प्रदान करता है । यह मॉडल मान को प्रभावित करने के लिए एक स्थान के रूप में डिज़ाइन किया गया है (इसके वापसी मूल्य के माध्यम से), लेकिन इसे ईवेंट इनपुट करने के लिए श्रोता के रूप में भी उपयोग किया जा सकता है।

app.directive('cleanInput', function() { 
    return { 
    require: 'ngModel', 
    link: function(scope, element, attrs, ngModelController) { 
     var el = element[0]; 

     function clean(x) { 
     return x && x.toUpperCase().replace(/[^A-Z\d]/g, ''); 
     } 

     ngModelController.$parsers.push(function(val) { 
     var cleaned = clean(val); 

     // Avoid infinite loop of $setViewValue <-> $parsers 
     if (cleaned === val) return val; 

     var start = el.selectionStart; 
     var end = el.selectionEnd + cleaned.length - val.length; 

     // element.val(cleaned) does not behave with 
     // repeated invalid elements 
     ngModelController.$setViewValue(cleaned); 
     ngModelController.$render(); 

     el.setSelectionRange(start, end); 
     return cleaned; 
     }); 
    } 
    } 
}); 

हालांकि, मैं यकीन नहीं करता है, तो $parsers के इस प्रयोग हैक का एक सा है। निर्देश के रूप में इस्तेमाल किया जा सकता:

<input type="text" clean-input ng-model="name"> 

या आप एक ngChange समारोह करना चाहते हैं:

<input type="text" clean-input ng-model="name" ng-change="onChange()"> 

इस पर http://plnkr.co/edit/dAJ46XmmC49wqTgdp2qz?p=preview

+0

महान समाधान, धन्यवाद! कैरेट की स्थिति निर्धारित करने के अन्य सभी तरीकों से कैरेट आगे बढ़ रहा है, और आपका समाधान केवल – trushkevich

+0

@ मिचल-चेरेम्ज़ा काम करता है, अलग-अलग मॉडल को बनाए रखना संभव है और देखें वैल्यू। उदाहरण के लिए, मैं फ्लाई पर XXX-XXX-XXXX जैसे इनपुट प्रारूपित करना चाहता हूं लेकिन मॉडल में केवल XXXXXXXXXX होना चाहिए। – dearvivekkumar

1

मुख्य चीजें हैं जो की जरूरत है कर रहे हैं:

  • आवश्यकता ngModelController अपने तरीकों कॉल और मिल/अपने मूल्यों को निर्धारित करने में सक्षम हो। विशेष रूप से ...

  • ngModelController.$setViewValue(y); 
    ngModelController.$render(); 
    

    साथ कॉल element.val(y) बदलें मैं मैं स्वीकार करना चाहिए लगता है, मैं पूरी तरह से ngModelController की अंदरूनी कामकाज पर यकीन है कि समझने के लिए क्यों यह जरूरी है कि नहीं कर रहा हूँ।

  • वैकल्पिक है, लेकिन element.val() द्वारा ध्यान में रखते हुए मौजूदा मूल्य हो रही बजाय द्वारा किया जा सकता:

    ngModelController.$viewValue; 
    

    जो कम से कम दृश्य मूल्य स्थापित करने का रास्ता साथ एक अधिक संगत है।

  • फिर वैकल्पिक है, लेकिन input घटना को सुन इंटरफ़ेस थोड़ा अच्छे बनाता है, के रूप में यह keyup घटना से पहले थोड़ा आग है, तो आप असंसाधित इनपुट की एक फ्लैश नहीं मिलता है लगता है।

  • इनपुट को संसाधित करने के लिए $parsers सरणी में जोड़ने से इनपुट के अन-संसाधित संस्करण के लिए किसी भी ngChange कॉलबैक को रोक दिया जा रहा है।

    ngModelController.$parsers.push(function(val) { 
        // Return the processed value 
    }) 
    

इस सबको एक साथ रखें एक कस्टम के निर्देश के रूप में:

app.directive('cleanInput', function() { 
    return { 
    require: 'ngModel', 
    link: function(scope, element, attrs, ngModelController) { 
     function clean(x) { 
     return x && x.toUpperCase().replace(/[^A-Z\d]/g, ''); 
     } 

     ngModelController.$parsers.push(function(val) { 
     return clean(val); 
     }) 

     element.on('input', function() { 
     var x = ngModelController.$viewValue; 
     var y = clean(x); 

     var start = this.selectionStart; 
     var end = this.selectionEnd + y.length - x.length; 

     ngModelController.$setViewValue(y); 
     ngModelController.$render(); 
     this.setSelectionRange(start, end); 
     }); 
    } 
    } 
}); 

रूप में इस्तेमाल किया है जो किया जा सकता है:

<input type="text" clean-input ng-model="name"> 

या आप एक ngChange समारोह करना चाहते हैं:

<input type="text" clean-input ng-model="name ng-change="onChange()"> 

और कम से http://plnkr.co/edit/FymZ8QEKwj2xXTmaExrH?p=preview

संपादित कार्रवाई में देखी गई: $parsers सरणी के बारे में हिस्सा जोड़ें। मुझे स्वीकार करना चाहिए, यह @ अभियंता का जवाब था जिसने मुझे इसके बारे में सोचा।

+0

यह ठीक है, यह सिर्फ काम करने के लिए लगता है में कार्रवाई देखा जा सकता है सही नहीं लगता: मुझे इसे दो बार साफ करना होगा, एक बार 'ऑनपूट' में और एक बार '$ पार्सर्स' में। – maaartinus

+0

मैं सही महसूस नहीं करने के बारे में सहमत हूं। अपने आप को स्वयं को मनाने के लिए प्रयास करना कि यह ठीक है, मुझे एहसास हुआ कि ngModelController नियंत्रण/2 चीजों के साथ बातचीत करता है। मॉडल मान, और दृश्य मान। तो फिर प्रत्येक के लिए एक बार इनपुट की सफाई ठीक से देखा जा सकता है। हालांकि, अब मैंने एक विकल्प के बारे में सोचा है जहां इसे एक बार साफ किया गया है, लेकिन यह सुनिश्चित नहीं है कि यह थोड़ा सा है या नहीं। एक अलग जवाब के रूप में पोस्ट करेंगे। –