it-swarm.asia

كيفية الوصول إلى نطاق الأصل من داخل توجيه مخصص * بنطاق خاص * في AngularJS؟

أنا أبحث عن أي طريقة للوصول إلى النطاق "الأصل" ضمن التوجيه. أي مزيج من النطاق ، يشمل ، يتطلب ، ويمر في المتغيرات (أو النطاق نفسه) من أعلاه ، وما إلى ذلك. أنا على استعداد تام للانحناء للخلف ، لكنني أريد أن أتجنب شيئًا مخترقًا أو يتعذر إصلاحه تمامًا. على سبيل المثال ، أعرف أن بإمكاني القيام بذلك الآن عن طريق أخذ $scope من معلمات preLink والتكرار عبر نطاقات $sibling للعثور على "الأصل" المفاهيمي.

ما أريده حقًا هو أن أتمكن من $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?
                }
            }
        }
    };
});
318
colllin

انظر ما هي الفروق الدقيقة في الميراث النموذجي/الأولي في AngularJS؟

للتلخيص: تعتمد الطريقة التي يصل بها التوجيه إلى نطاقه الأصلي ($parent) على نوع النطاق الذي ينشئه التوجيه:

  1. افتراضي (scope: false) - لا ينشئ التوجيه نطاقًا جديدًا ، لذلك لا يوجد هنا ميراث. نطاق التوجيه هو نفس نطاق الأصل/الحاوية. في وظيفة الارتباط ، استخدم المعلمة الأولى (عادة scope).

  2. scope: true - ينشئ التوجيه نطاقًا فرعيًا جديدًا يرث نموذجًا أوليًا من النطاق الأصل. الخصائص التي تم تعريفها في النطاق الأصل متاحة للتوجيه scope (بسبب الوراثة النموذجية). فقط احذر من الكتابة إلى خاصية النطاق البدائية - والتي ستنشئ خاصية جديدة على نطاق التوجيه (الذي يخفي/يظل خاصية النطاق الأصل بنفس الاسم).

  3. scope: { ... } - يخلق التوجيه نطاق عزل/عزل جديد. لا يرث النموذج الأصل النموذج الأولي. لا يزال بإمكانك الوصول إلى النطاق الأصل باستخدام $parent ، لكن لا ينصح بهذا عادة. بدلاً من ذلك ، يجب عليك تحديد خصائص النطاق الأصل (و/أو الوظيفة) التي يحتاجها التوجيه عبر سمات إضافية في نفس العنصر حيث يتم استخدام التوجيه ، وذلك باستخدام رمز = و @ و &.

  4. transclude: true - يُنشئ التوجيه نطاقًا فرعيًا جديدًا "transcluded" ، يرث نموذجًا أوليًا من النطاق الأصل. إذا كان التوجيه يخلق أيضًا نطاقًا عزلًا ، فإن النطاقات المعزولة ونطاقات العزل هي أشقاء. تشير الخاصية $parent لكل نطاق إلى النطاق الأصل نفسه.
    Angular v1.3 update : إذا كان التوجيه أيضًا ينشئ نطاقًا معزولًا ، فإن النطاق المضمن هو الآن تابع لنطاق العزل. لم تعد النطاقات المنقولة والمعزولة أشقاء. تشير الخاصية $parent للنطاق المتجاوز الآن إلى نطاق العزل.

يحتوي الرابط أعلاه على أمثلة وصور لجميع الأنواع الأربعة.

لا يمكنك الوصول إلى النطاق في وظيفة ترجمة التوجيه (كما هو مذكور هنا: https://github.com/angular/angular.js/wiki/Understanding-Directives ). يمكنك الوصول إلى نطاق التوجيه في وظيفة الارتباط.

المشاهدة:

بالنسبة إلى 1. و 2. أعلاه: عادةً ما تقوم بتحديد الخاصية الأصل التي يحتاجها التوجيه عبر سمة ، ثم $ مشاهدتها:

<div my-dir attr1="prop1"></div>
scope.$watch(attrs.attr1, function() { ... });

إذا كنت تشاهد خاصية كائن ، فستحتاج إلى استخدام $ parse:

<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() { ... });
624
Mark Rajcok

الوصول إلى طريقة تحكم يعني الوصول إلى طريقة على نطاق الأصل من وحدة تحكم التوجيه/الارتباط/النطاق.

إذا كان التوجيه هو مشاركة/وراثة النطاق الأصل ، فسيكون من السهل جدًا إعادة توجيه أسلوب النطاق الأصل.

مطلوب المزيد من العمل عندما تريد الوصول إلى طريقة النطاق الأصل من نطاق التوجيه المعزول.

هناك خيارات قليلة (قد تكون أكثر من المذكورة أدناه) لاستدعاء طريقة النطاق الأصل من نطاق التوجيهات المعزولة أو مشاهدة متغيرات النطاق الأصل ( الخيار رقم 6 خاصة).

ملاحظة التي استخدمتها link function في هذه الأمثلة ، لكن يمكنك استخدام directive controller أيضًا بناءً على المتطلبات.

الخيار رقم 1. من خلال كائن حرفي ومن قالب HTML التوجيهي

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. من خلال مرجع الوظيفة ومن قالب html التوجيهي

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: من خلال طراز ng وربط ثنائي الاتجاه ، يمكنك تحديث متغيرات النطاق الأصل. . لذلك ، قد لا تحتاج إلى استدعاء وظائف نطاق الأصل في بعض الحالات.

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 و $watchCollectionإنه ملتزم في اتجاهين لـ items في جميع الأمثلة المذكورة أعلاه ، إذا تم تعديل العناصر في نطاق الأصل ، فإن العناصر الموجودة في التوجيه ستعكس التغييرات أيضًا.

إذا كنت ترغب في مشاهدة السمات أو الكائنات الأخرى من النطاق الأصل ، يمكنك القيام بذلك باستخدام $watch و $watchCollection كما هو موضح أدناه

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 {{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>

script 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 للحصول على توضيحات مفصلة حول التوجيهات.

48
Yogesh Manware
 scope: false
 transclude: false

وسيكون لديك نفس النطاق (مع العنصر الأصل)

$scope.$watch(...

هناك الكثير من الطرق لكيفية الوصول إلى نطاق الأصل استنادًا إلى نطاق الخيارين & transclude.

11
Stepan Suvorov

إليك خدعة استخدمتها مرة واحدة: إنشاء توجيه "دمية" للاحتفاظ بالنطاق الأصل ووضعه في مكان ما خارج التوجيه المطلوب. شيء مثل:

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>

ربما لا يكون الحل الأكثر رشاقة ، لكنه أنجز المهمة.

7
anewcomer

إذا كنت تستخدم فئات ES6 و بناء جملة ControllerAs، فأنت بحاجة إلى القيام بشيء مختلف قليلاً.

راجع القصاصة أدناه ولاحظ أن vm هي قيمة ControllerAs لوحدة التحكم الأصل كما هو مستخدم في HTML الأصل

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

        scope.vm.func(...)
4
Simon H

بعد أن جربت كل شيء ، توصلت أخيرًا إلى حل.

فقط ضع ما يلي في القالب الخاص بك:

{{currentDirective.attr = parentDirective.attr; ''}}

يكتب فقط السمة/المتغير للنطاق الأصل الذي تريد الوصول إلى النطاق الحالي.

لاحظ أيضًا ; '' في نهاية البيان ، إنه للتأكد من عدم وجود إخراج في القالب الخاص بك. (الزاوي يقيم كل عبارة ، لكن يخرج آخر عبارة فقط).

إنه أمر مخترق بعض الشيء ، ولكن بعد بضع ساعات من التجربة والخطأ ، تقوم بهذه المهمة.

0
Jeffrey Roosendaal