How to access parent scope from within a custom directive *with own scope* in AngularJS?

后端 未结 6 678
终归单人心
终归单人心 2020-11-22 13:50

I\'m looking for any manner of accessing the \"parent\" scope within a directive. Any combination of scope, transclude, require, passing in variables (or the scope itself)

6条回答
  •  生来不讨喜
    2020-11-22 14:16

    Accessing controller method means accessing a method on parent scope from directive controller/link/scope.

    If the directive is sharing/inheriting the parent scope then it is quite straight forward to just invoke a parent scope method.

    Little more work is required when you want to access parent scope method from Isolated directive scope.

    There are few options (may be more than listed below) to invoke a parent scope method from isolated directives scope or watch parent scope variables (option#6 specially).

    Note that I used link function in these examples but you can use a directive controller as well based on requirement.

    Option#1. Through Object literal and from directive html template

    index.html

    
    
    
      
        
        AngularJS Plunker
        
        
        
        
      
    
      
        

    Hello {{name}}!

    Directive Content

    Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}}

    itemfilterTemplate.html

    
    

    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"
        }]
    
    });
    

    working plnkr: http://plnkr.co/edit/rgKUsYGDo9O3tewL6xgr?p=preview

    Option#2. Through Object literal and from directive link/scope

    index.html

    
    
    
      
        
        AngularJS Plunker
        
        
        
        
      
    
      
        

    Hello {{name}}!

    Directive Content

    Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}}

    itemfilterTemplate.html

    
    

    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"
        }]
    });
    

    working plnkr: http://plnkr.co/edit/BRvYm2SpSpBK9uxNIcTa?p=preview

    Option#3. Through Function reference and from directive html template

    index.html

    
    
    
      
        
        AngularJS Plunker
        
        
        
        
      
    
      
        

    Hello {{name}}!

    Directive Content

    Selected Items (in parent controller) set to: {{selectedItemsReturnFromDirective}}

    itemfilterTemplate.html

    
    

    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"
        }]
    });
    

    working plnkr: http://plnkr.co/edit/Jo6FcYfVXCCg3vH42BIz?p=preview

    Option#4. Through Function reference and from directive link/scope

    index.html

    
    
    
      
        
        AngularJS Plunker
        
        
        
        
      
    
      
        

    Hello {{name}}!

    Directive Content

    Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}}

    itemfilterTemplate.html

    
    

    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"
        }]
    
    });
    

    working plnkr: http://plnkr.co/edit/BSqx2J1yCY86IJwAnQF1?p=preview

    Option#5: Through ng-model and two way binding, you can update parent scope variables.. So, you may not require to invoke parent scope functions in some cases.

    index.html

    
    
    
      
        
        AngularJS Plunker
        
        
        
        
      
    
      
        

    Hello {{name}}!

    Directive Content

    Selected Items (in parent controller) set to: {{selectedItems}}

    itemfilterTemplate.html

    
    

    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"
        }]
    });
    

    working plnkr: http://plnkr.co/edit/hNui3xgzdTnfcdzljihY?p=preview

    Option#6: Through $watch and $watchCollection It is two way binding for items in all above examples, if items are modified in parent scope, items in directive would also reflect the changes.

    If you want to watch other attributes or objects from parent scope, you can do that using $watch and $watchCollection as given below

    html

    
    
    
    
      
      AngularJS Plunker
      
      
      
      
    
    
    
      

    Hello {{user}}!

    directive is watching name and current item

    Id:
    Name:
    Model:

    Directive Contents

    Selected Items (in parent controller) set to: {{selectedItems}}

    script app.js

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

    app.directive('sdItemsFilter', function() {
      return {
        restrict: 'E',
        scope: {
          name: '@',
          currentItem: '=',
          items: '=',
          selectedItems: '=ngModel'
        },
        template: '',
        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"
      }]
    });
    

    You can always refer AngularJs documentation for detailed explanations about directives.

提交回复
热议问题