angularjs एंगुलरजेएस में अपने दायरे के साथ कस्टम निर्देश*के भीतर से मूल दायरे तक कैसे पहुंचे?




angularjs-directive (5)

मैं निर्देश के भीतर "पैरेंट" दायरे तक पहुंचने के किसी भी तरीके की तलाश में हूं। उपरोक्त से चर (या स्वयं का दायरा) में गुजरने, गुजरने, आवश्यक, गुजरने के किसी भी संयोजन, आदि। मैं पूरी तरह से पीछे की तरफ झुकने के लिए तैयार हूं, लेकिन मैं पूरी तरह से हैकी या अनजान कुछ से बचना चाहता हूं। उदाहरण के लिए, मुझे पता है कि मैं इसे प्रीलिंक पैरामीटर से $scope लेकर और वैचारिक "पैरेंट" को खोजने के लिए $sibling scopes पर फिर से चलकर इसे कर सकता हूं।

मैं वास्तव में चाहता हूं कि माता-पिता के दायरे में अभिव्यक्ति को $watch सक्षम होना चाहिए। अगर मैं ऐसा कर सकता हूं, तो मैं यहां जो कुछ करने की कोशिश कर रहा हूं उसे पूरा कर सकता हूं: AngularJS - चर के साथ आंशिक कैसे प्रस्तुत करें?

एक महत्वपूर्ण नोट यह है कि निर्देश एक ही माता-पिता के दायरे में पुनः उपयोग करने योग्य होना चाहिए। इसलिए डिफ़ॉल्ट व्यवहार (दायरा: झूठा) मेरे लिए काम नहीं करता है। मुझे निर्देश के प्रति उदाहरण के एक अलग दायरे की आवश्यकता है, और फिर मुझे एक वैरिएबल $watch ज़रूरत है जो माता-पिता के दायरे में रहती है।

एक कोड नमूना 1000 शब्दों के लायक है, इसलिए:

app.directive('watchingMyParentScope', function() {
    return {
        require: /* ? */,
        scope: /* ? */,
        transclude: /* ? */,
        controller: /* ? */,
        compile: function(el,attr,trans) {
            // Can I get the $parent from the transclusion function somehow?
            return {
                pre: function($s, $e, $a, parentControl) {
                    // Can I get the $parent from the parent controller?
                    // By setting this.$scope = $scope from within that controller?

                    // Can I get the $parent from the current $scope?

                    // Can I pass the $parent scope in as an attribute and define
                    // it as part of this directive's scope definition?

                    // What don't I understand about how directives work and
                    // how their scope is related to their parent?
                },
                post: function($s, $e, $a, parentControl) {
                    // Has my situation improved by the time the postLink is called?
                }
            }
        }
    };
});

 scope: false
 transclude: false

और आपके पास एक ही दायरा होगा (मूल तत्व के साथ)

$scope.$watch(...

इन दो विकल्पों के दायरे और स्थानांतरित करने के आधार पर माता-पिता के दायरे तक पहुंचने के कई तरीके हैं।


नियंत्रक विधि तक पहुंच का मतलब है निर्देशक नियंत्रक / लिंक / स्कोप से मूल दायरे पर एक विधि का उपयोग करना।

यदि निर्देश माता-पिता के दायरे को साझा / विरासत में ले रहा है तो यह केवल माता-पिता के दायरे को लागू करने के लिए काफी आगे है।

जब आप पृथक निर्देश दायरे से अभिभावक स्कोप विधि तक पहुंचना चाहते हैं तो थोड़ा और काम आवश्यक है।

अलग-अलग निर्देश दायरे से अभिभावक स्कोप विधि का आह्वान करने के लिए कुछ विकल्प (नीचे सूचीबद्ध किए गए से अधिक हो सकते हैं) या अभिभावक स्कोप वेरिएबल ( विकल्प # 6 विशेष रूप से) देखें।

ध्यान दें कि मैंने इन उदाहरणों में link function उपयोग किया है लेकिन आप आवश्यकता के आधार पर directive controller का भी उपयोग कर सकते हैं।

विकल्प 1। ऑब्जेक्ट शाब्दिक और निर्देश एचटीएमएल टेम्पलेट के माध्यम से

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged(selectedItems)" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" ng-change="selectedItemsChanged({selectedItems:selectedItems})" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnedFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]

});

काम कर रहे plnkr: http://plnkr.co/edit/rgKUsYGDo9O3tewL6xgr?p=preview

विकल्प 2। ऑब्जेक्ट शाब्दिक और निर्देशक लिंक / दायरे से

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged(selectedItems)" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-change="selectedItemsChangedDir()" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html",
    link: function (scope, element, attrs){
      scope.selectedItemsChangedDir = function(){
        scope.selectedItemsChanged({selectedItems:scope.selectedItems});  
      }
    }
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnedFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

काम कर रहे plnkr: http://plnkr.co/edit/BRvYm2SpSpBK9uxNIcTa?p=preview

विकल्प # 3। फंक्शन संदर्भ और निर्देश एचटीएमएल टेम्पलेट के माध्यम से

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-change="selectedItemsChanged()(selectedItems)" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems:'=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

काम कर रहे plnkr: http://plnkr.co/edit/Jo6FcYfVXCCg3vH42BIz?p=preview

विकल्प # 4। फंक्शन संदर्भ और निर्देश लिंक / दायरे से

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" ng-change="selectedItemsChangedDir()" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=',
      selectedItemsChanged: '&'
    },
    templateUrl: "itemfilterTemplate.html",
    link: function (scope, element, attrs){
      scope.selectedItemsChangedDir = function(){
        scope.selectedItemsChanged()(scope.selectedItems);  
      }
    }
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.selectedItemsChanged = function(selectedItems1) {
    $scope.selectedItemsReturnedFromDirective = selectedItems1;
  }

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]

});

काम कर रहे plnkr: http://plnkr.co/edit/BSqx2J1yCY86IJwAnQF1?p=preview

विकल्प # 5: एनजी-मॉडल और दो तरह के बाध्यकारी के माध्यम से, आप मूल दायरे चर अद्यतन कर सकते हैं। । इसलिए, आपको कुछ मामलों में अभिभावक स्कोप फ़ंक्शन का आह्वान करने की आवश्यकता नहीं हो सकती है।

index.html

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <p>Hello {{name}}!</p>

    <p> Directive Content</p>
    <sd-items-filter ng-model="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>


    <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}} </p>

  </body>

</html>

itemfilterTemplate.html

<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>

app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=ngModel'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

काम कर रहे plnkr: http://plnkr.co/edit/hNui3xgzdTnfcdzljihY?p=preview

विकल्प # 6: $watch और $watch माध्यम से $watchCollection सभी उपरोक्त उदाहरणों में items लिए बाध्यकारी है, यदि आइटम मूल दायरे में संशोधित होते हैं, तो निर्देशों में आइटम भी परिवर्तनों को प्रतिबिंबित करेंगे।

यदि आप अभिभावक दायरे से अन्य विशेषताओं या ऑब्जेक्ट्स देखना चाहते हैं, तो आप $watch और $watchCollection $watch का चयन करके कर सकते हैं जैसा कि नीचे दिया गया है

एचटीएमएल

<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS Plunker</title>
  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="style.css" />
  <script data-require="[email protected]" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
  <script src="app.js"></script>
</head>

<body ng-controller="MainCtrl">
  <p>Hello {{user}}!</p>
  <p>directive is watching name and current item</p>
  <table>
    <tr>
      <td>Id:</td>
      <td>
        <input type="text" ng-model="id" />
      </td>
    </tr>
    <tr>
      <td>Name:</td>
      <td>
        <input type="text" ng-model="name" />
      </td>
    </tr>
    <tr>
      <td>Model:</td>
      <td>
        <input type="text" ng-model="model" />
      </td>
    </tr>
  </table>

  <button style="margin-left:50px" type="buttun" ng-click="addItem()">Add Item</button>

  <p>Directive Contents</p>
  <sd-items-filter ng-model="selectedItems" current-item="currentItem" name="{{name}}" selected-items-changed="selectedItemsChanged" items="items"></sd-items-filter>

  <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}}</p>
</body>

</html>

स्क्रिप्ट app.js

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

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      name: '@',
      currentItem: '=',
      items: '=',
      selectedItems: '=ngModel'
    },
    template: '<select ng-model="selectedItems" multiple="multiple" style="height: 140px; width: 250px;"' +
      'ng-options="item.id as item.name group by item.model for item in items | orderBy:\'name\'">' +
      '<option>--</option> </select>',
    link: function(scope, element, attrs) {
      scope.$watchCollection('currentItem', function() {
        console.log(JSON.stringify(scope.currentItem));
      });
      scope.$watch('name', function() {
        console.log(JSON.stringify(scope.name));
      });
    }
  }
})

 app.controller('MainCtrl', function($scope) {
  $scope.user = 'World';

  $scope.addItem = function() {
    $scope.items.push({
      id: $scope.id,
      name: $scope.name,
      model: $scope.model
    });
    $scope.currentItem = {};
    $scope.currentItem.id = $scope.id;
    $scope.currentItem.name = $scope.name;
    $scope.currentItem.model = $scope.model;
  }

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
  }]
});

निर्देशों के बारे में विस्तृत स्पष्टीकरण के लिए आप हमेशा AngularJs दस्तावेज़ों का संदर्भ ले सकते हैं।


देखें AngularJS में स्कोप प्रोटोटाइप / प्रोटोटाइपिकल विरासत की बारीकियों क्या हैं?

संक्षेप में: जिस तरह से निर्देशक अपने माता-पिता ( $parent ) दायरे तक पहुंचता है, निर्देश के आधार पर निर्भर करता है:

  1. डिफ़ॉल्ट ( scope: false ) - निर्देश एक नया दायरा नहीं बनाता है, इसलिए यहां कोई विरासत नहीं है। निर्देशक का दायरा माता-पिता / कंटेनर के समान दायरा है। लिंक फ़ंक्शन में, पहले पैरामीटर (आमतौर पर scope ) का उपयोग करें।

  2. scope: true - निर्देश एक नया बच्चा गुंजाइश बनाता है जो प्रोटोटाइपिक रूप से मूल दायरे से प्राप्त होता है। मूल दायरे पर परिभाषित गुण निर्देश scope (प्रोटोटाइप विरासत के कारण) के लिए उपलब्ध हैं। केवल एक प्राचीन दायरे की संपत्ति के लिए लिखने से सावधान रहें - जो निर्देशक दायरे पर एक नई संपत्ति तैयार करेगा (जो एक ही नाम की मूल दायरे की संपत्ति को छिपाता / छाया करता है)।

  3. scope: { ... } - निर्देश एक नया अलग / पृथक गुंजाइश बनाता है। यह प्रोटोटाइपिक रूप से मूल दायरे का वारिस नहीं करता है। आप अभी भी $parent का उपयोग करके मूल दायरे तक पहुंच सकते हैं, लेकिन इसकी सामान्य रूप से अनुशंसा नहीं की जाती है। इसके बजाए, आपको निर्दिष्ट करना चाहिए कि कौन सा मूल दायरा गुण (और / या फ़ंक्शन) निर्देश को उसी तत्व पर अतिरिक्त विशेषताओं के माध्यम से आवश्यक है जहां निर्देश का उपयोग किया जाता है, = , @ , और नोटेशन का उपयोग करके।

  4. transclude: true - निर्देश एक नया "स्थानांतरित" बाल क्षेत्र बनाता है, जो प्रोटोटाइपिक रूप से मूल दायरे से प्राप्त होता है। यदि निर्देश भी एक अलग गुंजाइश बनाता है, तो बहिष्कृत और पृथक क्षेत्र भाई बहन हैं। प्रत्येक गुंजाइश की $parent संपत्ति एक ही मूल दायरे का संदर्भ देती है।
    कोणीय v1.3 अद्यतन : यदि निर्देश भी एक अलग दायरा बनाता है, तो स्थानांतरित गुंजाइश अब अलग-अलग दायरे का बच्चा है। बहिष्कृत और पृथक क्षेत्र अब भाई बहन नहीं हैं। स्थानांतरित गुंजाइश की $parent संपत्ति अब अलग-अलग दायरे का संदर्भ देती है।

उपरोक्त लिंक में सभी 4 प्रकार के उदाहरण और चित्र हैं।

आप निर्देश के संकलन फ़ंक्शन में दायरे तक नहीं पहुंच सकते हैं (जैसा कि यहां बताया गया है: https://github.com/angular/angular.js/wiki/Understanding-Directives डायरेक्टिव्स)। आप लिंक फ़ंक्शन में निर्देश के दायरे तक पहुंच सकते हैं।

देख रहे:

1. और 2. के लिए: सामान्य रूप से आप निर्दिष्ट करते हैं कि कौन सी मूल संपत्ति निर्देश को एक विशेषता के माध्यम से आवश्यक है, फिर $ इसे देखें:

<div my-dir attr1="prop1"></div>

scope.$watch(attrs.attr1, function() { ... });

यदि आप ऑब्जेक्ट प्रॉपर्टी देख रहे हैं, तो आपको $ पार्स का उपयोग करना होगा:

<div my-dir attr2="obj.prop2"></div>

var model = $parse(attrs.attr2);
scope.$watch(model, function() { ... });

3. ऊपर (दायरे को अलग करें) के लिए, उस नाम को देखें जिसे आप निर्देशक संपत्ति देते हैं @ या = नोटेशन का उपयोग करते हुए:

<div my-dir attr3="{{prop3}}" attr4="obj.prop4"></div>

scope: {
  localName3: '@attr3',
  attr4:      '='  // here, using the same name as the attribute
},
link: function(scope, element, attrs) {
   scope.$watch('localName3', function() { ... });
   scope.$watch('attr4',      function() { ... });

यहां एक चाल है जिसे मैंने एक बार उपयोग किया था: माता-पिता के दायरे को पकड़ने के लिए "डमी" निर्देश बनाएं और इसे वांछित निर्देश के बाहर कहीं भी रखें। कुछ इस तरह:

module.directive('myDirectiveContainer', function () {
    return {
        controller: function ($scope) {
            this.scope = $scope;
        }
    };
});

module.directive('myDirective', function () {
    return {
        require: '^myDirectiveContainer',
        link: function (scope, element, attrs, containerController) {
            // use containerController.scope here...
        }
    };
});

और फिर

<div my-directive-container="">
    <div my-directive="">
    </div>
</div>

शायद सबसे खूबसूरत समाधान नहीं, लेकिन यह काम पूरा हो गया।


यदि आप ES6 क्लासेस और ControllerAs ए सिंटैक्स का उपयोग कर रहे हैं , तो आपको कुछ अलग करने की ज़रूरत है।

नीचे स्निपेट देखें और ध्यान दें कि vm मूल नियंत्रक में उपयोग किए गए पैरेंट कंट्रोलर का ControllerAs मान है

myApp.directive('name', function() {
  return {
    // no scope definition
    link : function(scope, element, attrs, ngModel) {

        scope.vm.func(...)






angularjs-directive