简体   繁体   English

AngularJS覆盖指令控制器功能

[英]AngularJS override directive controller function

Here is the problem. 这是问题所在。 I have some 3rd party directive called main-directive . 我有一些称为main-directive的第三方指令

app.directive('mainDirective', function() {
  return {
    scope: {
      foo: '&'
      // attrs
    },
    controller: function($scope) {

      $scope.click = function() {
        window.alert($scope.foo());
      }

    },
    template: '<button ng-click="click()">Click me</button>'
  }
});

So I want to make my own directive called parent-directive which assign application specific default values to third party directive attributes. 因此,我想制作自己的名为父指令的指令 ,该指令将应用程序特定的默认值分配给第三方指令属性。

app.directive('parentDirective', function() {
  return {
    scope: {
      foo: '&?',
      attr2: '='
        // lots of attrs
    },
    controller: function($scope) {


      $scope.attr1 = "some default value"

      $scope.foo = function() {
        return "not overrided"
      }

      if (this.foo) {
        $scope.foo = this.foo
      }

    },
    template: '<div class="some-styling"><main-directive foo="foo()" attr1="attr1" attr2="attr2"></main-directive></div>'
  }
});

What if I want to make another child-directive that keeps parent-directive logic. 如果我想制作另一个保留父级指令逻辑的子级指令 ,该怎么办? Overloading attribute is easy i can use "compile" function. 重载属性很容易,我可以使用“编译”功能。 But what about overriding functions is it possible? 但是,可以覆盖功能呢?

app.directive('childDirective', function() {

  return {
    scope: false,
    require: 'parentDirective',
    link: function(scope, element, attr, controller) {

      controller.foo = function() {
        return "overrided";
      }

    },
    compile: function(element, attr) {
      attr.attr2 = "attr2";
    }
  }
});

Whole thing can be easily done by using child scope instead of isolated. 通过使用子范围而不是孤立范围,可以很容易地完成整个事情。 Or by using extending by template. 或通过使用扩展模板。 But if I extends directive with template I would have to copy parent "scope" and "template" definition to child-directive and forward all the non-default attributes this doesn't seem like an elegant solution. 但是,如果我用模板扩展指令,则必须将父“作用域”和“模板”定义复制到子指令并转发所有非默认属性,这似乎不是一个很好的解决方案。

So the key question, is there a way to override parent-directive function using isolated scope without forwarding attributes. 因此,关键问题是,有没有一种方法可以使用隔离范围覆盖父指令功能而无需转发属性。

Here is the DEMO 这是演示

Ok, I have done some research and it turns out that there can be several approaches there 好的,我做了一些研究,结果发现那里可以有几种方法

Scope inheritance 范围继承

Since child-directive is not creating own scope it just creating new methods at parent-directive parent scope. 由于子指令不创建自己的作用域,因此仅在父指令父作用域中创建新方法。 So we can modify attributes during compile and specify overridden foo method. 因此,我们可以在编译期间修改属性并指定重写的foo方法。

app.directive('parentDirective', function() {
  return {
    scope: {
      fooImpl: '&?',
      // lots of attrs
    },
    controller: function($scope) {

      $scope.foo = function() {
        if ($scope.fooImpl) {
          return $scope.fooImpl();
        }
        return "not overrided";
      }

    },
    template: '<div class="some-styling"><main-directive foo="foo()"></main-directive></div>'
  }
});

app.directive('childDirective', function() {

  return {
    scope: false,
    require: 'parentDirective',
    controller: function($scope) {

      $scope.foo = function() {
        return "overrided";
      }

    },
    compile: function(element, attr) {
      attr.fooImpl = "foo()";
    }
  }
});

Here is the DEMO1 这是DEMO1

Add to isolated scope 添加到隔离范围

Angular provides special function. Angular提供特殊功能。 That can get isolated scope from element. 那可以从元素中获得孤立的范围。 So we can override our method during linking phase. 因此,我们可以在链接阶段覆盖我们的方法。

app.directive('parentDirective', function() {
  return {
    scope: {
      fooImpl: '&?',
      // lots of attrs
    },
    controller: function($scope) {

      $scope.foo = function() {
        if ($scope.fooImpl) {
          return $scope.fooImpl();
        }
        return "not overrided";
      }

    },
    template: '<div class="some-styling"><main-directive foo="foo()"></main-directive></div>'
  }
});

app.directive('childDirective', function() {

  return {
    scope: false,
    require: 'parentDirective',
    link: function(scope, element, attr) {
      var innerScope = angular.element(element[0]).isolateScope();
      innerScope.foo = function() {
        return "overrided";
      }
    }
  }
});

Here is the DEMO2 这是DEMO2

Controller method 控制器方式

If we use controllerAs syntax. 如果我们使用controllerAs语法。 That means we exposing controller object variables as a scope. 这意味着我们将控制器对象变量作为范围公开。 We can override function in child directive during linking phase. 在链接阶段,我们可以在子指令中覆盖函数。

app.directive('parentDirective', function() {
  return {
    scope: {
      fooImpl: '&?',
      // lots of attrs
    },
    controller: function($scope) {

      var vm = this;

      vm.foo = function() {
        return "not overrided";
      }

    },
    controllerAs : 'vm',
    template: '<div class="some-styling"><main-directive foo="vm.foo()"></main-directive></div>'
  }
});

app.directive('childDirective', function() {

  return {
    scope: false,
    require: 'parentDirective',
    link: function (scope, element, attr, controller) {

       controller.foo = function() {
        return "overrided";
      }


    }
  }
});

Here is the DEMO3 这是DEMO3

Transclusion 包容性

Practically you can do the same thing with seperate parent and child directive and using transclusion. 实际上,您可以使用单独的父项和子项指令并使用转写来执行相同的操作。 But anyway it would be combination of above approaches. 但是无论如何,它将是上述方法的组合。 Thanks for "Extending an existing directive in AngularJS" 感谢“在AngularJS中扩展现有指令”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM