angularjs - कस्टम निर्देश के लिए एनजी-परिवर्तन को कैसे लागू किया जाए




angularjs-directive angularjs-ng-change (4)

मेरे पास एक टेम्पलेट जैसा निर्देश है

<div>
    <div ng-repeat="item in items" ng-click="updateModel(item)">
<div>

मेरे निर्देश के रूप में घोषित किया गया है:

return {
    templateUrl: '...',
    restrict: 'E',
    require: '^ngModel',
    scope: {
        items: '=',
        ngModel: '=',
        ngChange: '&'
    },
    link: function postLink(scope, element, attrs) 
    {
        scope.updateModel = function(item)
        {
             scope.ngModel = item;
             scope.ngChange();
        }
    }
}

जब वस्तु पर क्लिक किया जाता है और foo के मूल्य को पहले ही बदल दिया जाता है, तो मैं ng-change करना चाहता हूं।

यदि मेरा निर्देश इस प्रकार लागू किया जाता है:

<my-directive items=items ng-model="foo" ng-change="bar(foo)"></my-directive>

जब foo का मूल्य अद्यतन किया गया है तो मैं bar को कॉल करने की उम्मीद करूंगा।

ऊपर दिए गए कोड के साथ, ngChange को सफलतापूर्वक कहा जाता है, लेकिन इसे नए अपडेटेड मूल्य के बजाय foo के पुराने मूल्य के साथ कहा जाता है।

समस्या को हल करने का एक तरीका भविष्य में किसी बिंदु पर इसे निष्पादित करने के लिए समय-सीमा के भीतर ngChange को कॉल ngChange है, जब foo के मूल्य को पहले ही बदल दिया गया है। लेकिन यह समाधान मुझे उस आदेश पर ढीला नियंत्रण बनाता है जिसमें चीजों को निष्पादित किया जाना है और मेरा मानना ​​है कि अधिक सुरुचिपूर्ण समाधान होना चाहिए।

मैं पैरेंट के दायरे में foo ऊपर एक वॉचर का भी इस्तेमाल कर सकता था, लेकिन यह सॉल्यूशन वास्तव में ngChange मेथड को ngChange नहीं कर सकता है और मुझे बताया गया है कि ngChange महान मेमोरी उपभोक्ता हैं।

क्या ngChange करने के लिए एक टाइमआउट या एक चौकीदार के बिना ngChange रूप से निष्पादित किया जा सकता है?

उदाहरण: http://plnkr.co/edit/8H6QDO8OYiOyOx8efhyJ?p=preview


कुछ शोध के बाद, ऐसा लगता है कि सबसे अच्छा तरीका $timeout(callback, 0)

कॉलबैक निष्पादित होने के तुरंत बाद यह स्वचालित रूप से $digest चक्र लॉन्च करता है।

तो, मेरे मामले में, समाधान का उपयोग करना था

$timeout(scope.ngChange, 0);

इस तरह, इससे कोई फर्क नहीं पड़ता कि आपके कॉलबैक के हस्ताक्षर क्या हैं, इसे वैसे ही निष्पादित किया जाएगा जैसे आपने इसे मूल दायरे में परिभाषित किया था।

इस तरह के बदलावों के बारे में यहां बताया गया है: http://plnkr.co/edit/9MGptJpSQslk8g8tD2bZ?p=preview


यदि आपको ngModel आवश्यकता है तो आप $setViewValue पर केवल $setViewValue को कॉल कर सकते हैं, जो ngModelController ng-change मूल्यांकन करता है। लिंकिंग फ़ंक्शन का चौथा पैरामीटर ngModelCtrl होना चाहिए। निम्नलिखित कोड आपके निर्देश के लिए ng-change काम करेगा।

link : function(scope, element, attrs, ngModelCtrl){
    scope.updateModel = function(item) {
        ngModelCtrl.$setViewValue(item);
    }
}

अपने समाधान के लिए काम करने के लिए, कृपया माइग्रेशन के अलग-अलग दायरे से ngChange और ngModel को हटा दें।

यहाँ एक प्लंक है: http://plnkr.co/edit/UefUzOo88MwOMkpgeX07?p=preview


सैमुली उलेमेनन और लुसिएन बर्टिन के उत्तर इसे कीलित करते हैं, हालांकि एंगुलरजेएस दस्तावेज़ीकरण में थोड़ा आगे पढ़ने से यह सलाह दी जाती है कि इसे कैसे संभालें ( ngModelCtrl )

विशेष रूप से उन मामलों में जहां आप ऑब्जेक्ट को $ setViewValue (myObj) में दे रहे हैं। एंगुलरजेएस डॉक्यूमेंटेशन स्टेट्स:

जब मानक इनपुट के साथ उपयोग किया जाता है, तो दृश्य मान हमेशा एक स्ट्रिंग होगा (जो कुछ मामलों में दूसरे प्रकार में पार्स किया जाता है, जैसे कि इनपुट के लिए दिनांक ऑब्जेक्ट [तिथि]।) हालांकि, कस्टम नियंत्रण भी इस पद्धति से ऑब्जेक्ट पास कर सकते हैं। इस मामले में, हमें $ setViewValue को पास करने से पहले ऑब्जेक्ट की एक प्रति बनाना चाहिए। ऐसा इसलिए है क्योंकि ngModel वस्तुओं की गहरी घड़ी का प्रदर्शन नहीं करता है, यह केवल पहचान के परिवर्तन के लिए दिखता है। यदि आप केवल ऑब्जेक्ट की संपत्ति को बदलते हैं तो ngModel को एहसास नहीं होगा कि ऑब्जेक्ट बदल गया है और $ पार्सर्स और $ सत्यापनकर्ता पाइपलाइनों का आह्वान नहीं करेगा। इस कारण से, आपको $ setViewValue को पास करने के बाद कॉपी के गुणों को नहीं बदलना चाहिए। अन्यथा आप गलत तरीके से बदलने की गुंजाइश पर मॉडल मूल्य का कारण बन सकते हैं।

मेरे विशिष्ट मामले के लिए, मेरा मॉडल एक क्षण की तारीख की वस्तु है, इसलिए मुझे पहले सेटव्यूवैल्यू को कॉल करने से पहले ऑब्जेक्ट को क्लोन करना होगा। मैं यहाँ भाग्यशाली हूँ क्योंकि पल एक सरल क्लोन विधि प्रदान करता है: var b = moment(a);

link : function(scope, elements, attrs, ctrl) {
    scope.updateModel = function (value) {
        if (ctrl.$viewValue == value) {
            var copyOfObject = moment(value);
            ctrl.$setViewValue(copyOfObject);
        }
        else
        {
            ctrl.$setViewValue(value);
        }
    };
}

tl; डॉ

मेरे अनुभव में आपको सिर्फ ngModelCtrl से वारिस ngModelCtrl । जब आप विधि ngModelCtrl.$setViewValue उपयोग करते हैं तो ng-change अभिव्यक्ति का स्वचालित रूप से मूल्यांकन किया जाएगा

angular.module("myApp").directive("myDirective", function(){
  return {
    require:"^ngModel", // this is important, 
    scope:{
      ... // put the variables you need here but DO NOT have a variable named ngModel or ngChange 
    }, 
    link: function(scope, elt, attrs, ctrl){ // ctrl here is the ngModelCtrl
      scope.setValue = function(value){
        ctrl.$setViewValue(value); // this line will automatically eval your ng-change
      };
    }
  };
});

ज्यादा ठीक

ngModelCtrl.$commitViewValue() दौरान ng-change का मूल्यांकन किया ngModelCtrl.$commitViewValue() यदि आपके ngModel का ऑब्जेक्ट संदर्भ बदल गया है। यदि आप ट्रिगर तर्क का उपयोग नहीं करते हैं या किसी भी ngModelOptions को तैयार नहीं किया है, तो विधि $commitViewValue() $setViewValue(value, trigger) द्वारा स्वचालित रूप से कहा जाता है।

मैंने निर्दिष्ट किया कि यदि $viewValue का संदर्भ बदल गया तो ng-chage $viewValue स्वचालित रूप से चालू हो जाएगा। जब आपका ngModel एक string या एक int , तो आपको इसके बारे में चिंता करने की ज़रूरत नहीं है। यदि आपका ngModel एक वस्तु है और आपका बस इसके कुछ गुणों को बदल रहा है, तो $setViewValue , $setViewValue को $setViewValue नहीं करेगा।

यदि हम पोस्ट के प्रारंभ से कोड का उदाहरण लेते हैं

scope.setValue = function(value){
    ctrl.$setViewValue(value); // this line will automatically evalyour ng-change
};
scope.updateValue = function(prop1Value){
    var vv = ctrl.$viewValue;
    vv.prop1 = prop1Value;
    ctrl.$setViewValue(vv); // this line won't eval the ng-change expression
};




angularjs-ng-change