AngularJS - एक निर्देश बनाएँ जो एनजी-मॉडल का उपयोग करता है


294

मैं एक निर्देश बनाने की कोशिश कर रहा हूं जो उसी एनजी-मॉडल के साथ एक इनपुट फ़ील्ड बनाएगा जो निर्देश बनाता है।

यहाँ मैं क्या अब तक के साथ आया है:

एचटीएमएल

<!doctype html>
<html ng-app="plunker" >
<head>
  <meta charset="utf-8">
  <title>AngularJS Plunker</title>
  <link rel="stylesheet" href="style.css">
  <script>document.write("<base href=\"" + document.location + "\" />");</script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script>
  <script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
  This scope value <input ng-model="name">
  <my-directive ng-model="name"></my-directive>
</body>
</html>

जावास्क्रिप्ट

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.name = "Felipe";
});

app.directive('myDirective', function($compile) {
  return {
    restrict: 'E',
    scope: {
      ngModel: '='
    },
    template: '<div class="some"><label for="{{id}}">{{label}}</label>' +
      '<input id="{{id}}" ng-model="value"></div>',
    replace: true,
    require: 'ngModel',
    link: function($scope, elem, attr, ctrl) {
      $scope.label = attr.ngModel;
      $scope.id = attr.ngModel;
      console.debug(attr.ngModel);
      console.debug($scope.$parent.$eval(attr.ngModel));
      var textField = $('input', elem).
        attr('ng-model', attr.ngModel).
        val($scope.$parent.$eval(attr.ngModel));

      $compile(textField)($scope.$parent);
    }
  };
});

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

यहां ऊपर दिए गए कोड का प्लंकर है: http://plnkr.co/edit/IvrDbJ

इससे निपटने का सही तरीका क्या है?

EDIT : ng-model="value"टेम्प्लेट से हटाने के बाद , यह ठीक काम कर रहा है। हालांकि, मैं इस प्रश्न को खुला रखूंगा क्योंकि मैं यह जांचना चाहता हूं कि यह ऐसा करने का सही तरीका है।


1
क्या होगा अगर आप scopeइसे हटा दें और इसे सेट करें scope: false? ng-modelउस मामले में कैसे बांधें ?
सईद नेमाटी

जवाबों:


210

EDIT : यह उत्तर पुराना है और संभावित रूप से पुराना है। बस एक सिर ऊपर तो यह लोगों को भटक ​​नहीं करता है। मैं अब कोणीय का उपयोग नहीं करता हूं इसलिए मैं सुधार करने के लिए अच्छी स्थिति में नहीं हूं।


यह वास्तव में बहुत अच्छा तर्क है लेकिन आप चीजों को थोड़ा सरल कर सकते हैं।

आदेश

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.model = { name: 'World' };
  $scope.name = "Felipe";
});

app.directive('myDirective', function($compile) {
  return {
    restrict: 'AE', //attribute or element
    scope: {
      myDirectiveVar: '=',
     //bindAttr: '='
    },
    template: '<div class="some">' +
      '<input ng-model="myDirectiveVar"></div>',
    replace: true,
    //require: 'ngModel',
    link: function($scope, elem, attr, ctrl) {
      console.debug($scope);
      //var textField = $('input', elem).attr('ng-model', 'myDirectiveVar');
      // $compile(textField)($scope.$parent);
    }
  };
});

निर्देश के साथ एच.टी.एम.एल.

<body ng-controller="MainCtrl">
  This scope value <input ng-model="name">
  <my-directive my-directive-var="name"></my-directive>
</body>

सीएसएस

.some {
  border: 1px solid #cacaca;
  padding: 10px;
}

आप इसे इस प्लंकर के साथ क्रिया में देख सकते हैं ।

यहाँ मैं देख रहा हूँ:

  • मैं समझता हूं कि आप 'एनजी-मॉडल' का उपयोग क्यों करना चाहते हैं, लेकिन आपके मामले में यह आवश्यक नहीं है। एनजी-मॉडल मौजूदा एचटीएमएल तत्वों को दायरे में एक मूल्य के साथ जोड़ना है । चूंकि आप स्वयं एक निर्देश बना रहे हैं, इसलिए आप एक 'नया' html तत्व बना रहे हैं, इसलिए आपको एनजी-मॉडल की आवश्यकता नहीं है।

संपादित करें जैसा कि मार्क ने अपनी टिप्पणी में उल्लेख किया है, इसका कोई कारण नहीं है कि आप एनजी-मॉडल का उपयोग नहीं कर सकते हैं , बस सम्मेलन के साथ रखने के लिए।

  • स्पष्ट रूप से अपने निर्देशांक (एक 'अलग-थलग') दायरे में एक गुंजाइश बनाकर, निर्देश का दायरा मूल नाम के दायरे में 'नाम' चर तक नहीं पहुंच सकता (यही वजह है कि, मुझे लगता है, आप एनजी-मॉडल का उपयोग करना चाहते थे)।
  • मैंने आपके निर्देश से ngModel को हटा दिया और इसे कस्टम नाम से बदल दिया, जिसे आप जो भी बदल सकते हैं।
  • यह सब अभी भी काम करता है कि बात गुंजाइश में '=' ​​संकेत है। 'स्कोप' हेडर के तहत डॉक्स डॉक्स चेकआउट करें ।

सामान्य तौर पर, आपके निर्देशों को अलग-थलग गुंजाइश (जो आपने सही ढंग से किया था) का उपयोग करना चाहिए और यदि आप अपने निर्देश में एक मान चाहते हैं, तो मूल = मान में मान के लिए '=' प्रकार के स्कोप का उपयोग करें।


18
+1, लेकिन मुझे यकीन नहीं है कि मैं इस कथन से सहमत हूं "एनजी-मॉडल मौजूदा HTML तत्वों को दायरे में एक मान के साथ जोड़ना है।" contenteditableकोणीय डॉक्स - प्रपत्र पृष्ठ , NgModelController पृष्ठ में दो प्रत्यक्ष उदाहरण - दोनों एनजी-मॉडल का उपयोग करते हैं। और ngModelController पृष्ठ कहता है कि यह नियंत्रक "अन्य निर्देशों द्वारा विस्तारित किया जाना है।"
मार्क राजकॉक

33
मुझे यकीन नहीं है कि इस उत्तर को इतना अधिक क्यों रेट किया गया है क्योंकि यह पूरा नहीं करता है कि मूल प्रश्न क्या पूछा गया है - जो ngModel का उपयोग करना है। हां, कोई भी पेरेंट कंट्रोलर में स्टेट लगाकर ngModel का उपयोग करने से बच सकता है लेकिन यह दो नियंत्रकों को कसकर बाध्य करने और स्वतंत्र रूप से उनका उपयोग / पुन: उपयोग करने में सक्षम नहीं होने की कीमत पर आता है। यह दो घटकों के बीच एक श्रोता को स्थापित करने के बजाय एक वैश्विक चर का उपयोग करने जैसा है - यह तकनीकी रूप से सरल हो सकता है लेकिन यह ज्यादातर मामलों में एक अच्छा समाधान नहीं है।
पाट नीमेयर

मुझे लगता है कि अगर वह मूल नियंत्रक पर भरोसा करना चाहता था, तो उसे 'आवश्यकता: ^ माता-पिता' के साथ वैसे भी इंजेक्ट करना चाहिए - ताकि वह निर्भरता को स्पष्ट और वैकल्पिक बना सके।
पाट नीमेयर

3
@Jeroen जिस तरह से मैं इसे देखता हूं मुख्य लाभ अन्य स्थानों के साथ संगतता है जहां मॉडल को पास किया जाता है hg-model(और युग्मन का मुद्दा नहीं, आईएमओ)। इस तरह डेटा संदर्भ हमेशा एनजी-मॉडल का उपयोग करता है चाहे वह एक <input>या एक कस्टम निर्देश हो, इस प्रकार HTML लेखक के लिए संज्ञानात्मक उपरि को सरल बनाता है । यानी यह HTML लेखक को यह पता लगाने के लिए बचाता है कि my-directive-varप्रत्येक निर्देश के लिए क्या नाम है, खासकर क्योंकि आपकी मदद करने के लिए कोई स्वत: पूर्ण नहीं है।
zai चांग

2
उम्म ... ठीक है ... लेकिन अब यह ng-model-optionsकिसी भी अन्य मॉडल की चीजों के साथ काम नहीं करता है , क्या यह करता है?
जॉर्ज मौअर

68

मैंने सभी उत्तरों का कॉम्बो लिया, और अब एनजी-मॉडल विशेषता के साथ ऐसा करने के दो तरीके हैं:

  • एक नए दायरे के साथ जो ngModel को कॉपी करता है
  • उसी दायरे के साथ जो लिंक पर एक संकलन करता है

मुझे यकीन नहीं है कि मुझे लिंक समय पर संकलन पसंद है। हालाँकि, यदि आप तत्व को दूसरे के साथ बदल रहे हैं तो आपको ऐसा करने की आवश्यकता नहीं है।

सभी में मैं पहले वाले को पसंद करता हूं। बस गुंजाइश सेट करें {ngModel:"="}और सेट करें ng-model="ngModel"जहां आप इसे अपने टेम्पलेट में चाहते हैं।

अपडेट : मैंने कोड स्निपेट को इनलाइन किया और इसे Angular v1.2 के लिए अपडेट किया। यह बताता है कि अलग-थलग गुंजाइश अभी भी सबसे अच्छा है, खासकर जब jQuery का उपयोग नहीं कर रहा है। तो यह करने के लिए नीचे फोड़े:

  • क्या आप किसी एकल तत्व को प्रतिस्थापित कर रहे हैं: बस इसे प्रतिस्थापित करें, अकेले गुंजाइश छोड़ दें, लेकिन ध्यान दें कि प्रतिस्थापित v2.0 के लिए पदावनत है:

    app.directive('myReplacedDirective', function($compile) {
      return {
        restrict: 'E',
        template: '<input class="some">',
        replace: true
      };
    });
  • अन्यथा इसका उपयोग करें:

    app.directive('myDirectiveWithScope', function() {
      return {
        restrict: 'E',
        scope: {
          ngModel: '=',
        },
        template: '<div class="some"><input ng-model="ngModel"></div>'
      };
    });

1
मैंने सभी तीन गुंजाइश संभावनाओं के साथ और टेम्पलेट के बाल तत्वों या टेम्पलेट के मूल तत्व के लिए प्लंकर को अपडेट किया।
w00t

1
यह बहुत अच्छा है, लेकिन आप इसे अनिवार्य रूप से वैकल्पिक कैसे बनाते हैं? मैं UI लाइब्रेरी के लिए एक टेक्स्टबॉक्स निर्देशन बना रहा हूं, और मैं चाहता हूं कि मॉडल वैकल्पिक हो, जिसका अर्थ है कि टेक्स्टबॉक्स अभी भी काम करेगा यदि एनकोमॉडल सेट नहीं है।
निक रेडफोर्ड

1
@NickRadford बस जांचें कि क्या ngModel को $ स्कोप पर परिभाषित किया गया है और यदि नहीं, तो इसका उपयोग न करें?
w00t

1
क्या ng-modelअलग-अलग दायरे में पुन: उपयोग के साथ कोई समस्या या अतिरिक्त ओवरहेड होगा ?
जेफ लिंग

2
@ जफलिंग निश्चित नहीं है, लेकिन मुझे ऐसा नहीं लगता। NgModel की नकल करना बहुत हल्का वजन है और अलग-अलग स्कोप एक्सपोज़र को सीमित करता है।
w00t

52

यह इतना जटिल नहीं है: अपने स्वभाव में, एक उपनाम का उपयोग करें: scope:{alias:'=ngModel'}

.directive('dateselect', function () {
return {
    restrict: 'E',
    transclude: true,
    scope:{
        bindModel:'=ngModel'
    },
    template:'<input ng-model="bindModel"/>'
}

अपने html में, सामान्य रूप से उपयोग करें

<dateselect ng-model="birthday"></dateselect>

1
Kendo UI जैसी पुस्तकालयों के साथ काम करते समय यह बहुत आसान है। धन्यवाद!
बाइटबेंडर

30

जब आपको मॉडल के $ viewValue या $ modelValue तक पहुंचने की आवश्यकता होती है, तो आपको केवल एनजी-मॉडल की आवश्यकता होती है। NgModelController देखें । और उस स्थिति में, आप उपयोग करेंगे require: '^ngModel'

बाकी के लिए, Roys उत्तर देखें ।


2
एनजी-मॉडल भी उपयोगी है, भले ही आपको $ व्यूवैल्यू या $ मॉडलवैल्यू की आवश्यकता न हो। यह उपयोगी है भले ही आप एनजी-मॉडल की डेटा-बाइंडिंग सुविधाओं को पसंद करते हों, जैसे @ कोली का उदाहरण।
मार्क राजकॉक

1
और ^वहां केवल तभी होना चाहिए जब एनजी-मॉडल को मूल तत्व में लागू किया गया हो
georgiosd

18

यह थोड़ा देर से जवाब है, लेकिन मुझे इस भयानक पोस्ट के बारे में पता चला NgModelController, जो मुझे लगता है कि वास्तव में आप क्या देख रहे थे।

TL; DR - आप उपयोग कर सकते हैं require: 'ngModel'और फिर NgModelControllerअपने लिंकिंग फ़ंक्शन में जोड़ सकते हैं :

link: function(scope, iElement, iAttrs, ngModelCtrl) {
  //TODO
}

इस तरह, किसी हैक की जरूरत नहीं है - आप एंगुलर के बिल्ट-इन का उपयोग कर रहे हैं ng-model


2

मैं एक विशेषता के माध्यम से ngmodel सेट नहीं करूंगा, आप इसे सही टेम्पलेट में निर्दिष्ट कर सकते हैं:

template: '<div class="some"><label>{{label}}</label><input data-ng-model="ngModel"></div>',

प्लंकर : http://plnkr.co/edit/9vtmnw?p=preview


0

कोणीय 1.5 के बाद से घटकों का उपयोग करना संभव है। घटक इस तरह से आसान हैं और इस समस्या को हल करते हैं।

<myComponent data-ng-model="$ctrl.result"></myComponent>

app.component("myComponent", {
    templateUrl: "yourTemplate.html",
    controller: YourController,
    bindings: {
        ngModel: "="
    }
});

YourController के अंदर आपको बस इतना करना है:

this.ngModel = "x"; //$scope.$apply("$ctrl.ngModel"); if needed

मैंने जो पाया वह यह है कि अगर आप वास्तव में "<" के बजाय "=" का उपयोग करते हैं तो यह काम करता है जो अन्यथा अवयवों का उपयोग करने का सबसे अच्छा अभ्यास है। मुझे यकीन नहीं है कि इस उत्तर के अंदर "YourController" भाग का क्या मतलब है, इस बिंदु को घटक के अंदर ngModel सेट नहीं करना है?
मार्क स्ट्रोब

1
@MarcStober "YourController के अंदर" के साथ मैं केवल यह दिखाना चाहता था कि ngModel गेट्टर और सेटर के रूप में उपलब्ध है। इस उदाहरण में $ ctrl.result "x" बन जाएगा।
नील्स स्टीनबीक

ठीक है। मुझे लगता है कि जो दूसरा हिस्सा महत्वपूर्ण है वह यह है कि आप अपने नियंत्रक टेम्पलेट में भी कर सकते हैं, input ng-model="$ctrl.ngModel"यह $ ctrl.result के साथ भी सिंक करेगा।
मार्क स्ट्रोब

0

एक अलग गुंजाइश बनाना अवांछनीय है। मैं गुंजाइश विशेषता का उपयोग करने से बचता हूं और ऐसा कुछ करता हूं। स्कोप: सच्चा आपको एक नया चाइल्ड स्कोप देता है लेकिन अलग-थलग नहीं। फिर पार्स का उपयोग स्थानीय स्कोप वैरिएबल को उसी ऑब्जेक्ट को इंगित करने के लिए करें जिसे उपयोगकर्ता ने एनकोमॉडल विशेषता को आपूर्ति की है।

app.directive('myDir', ['$parse', function ($parse) {
    return {
        restrict: 'EA',
        scope: true,
        link: function (scope, elem, attrs) {
            if(!attrs.ngModel) {return;}
            var model = $parse(attrs.ngModel);
            scope.model = model(scope);
        }
    };
}]);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.