AngularJS覆盖指令控制器功能

时间:2016-08-11 12:34:57

标签: javascript angularjs

这是问题所在。我有一些名为 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>'
  }
});

所以我想创建一个名为 parent-directive 的指令,它将特定于应用程序的默认值分配给第三方指令属性。

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>'
  }
});

如果我想制作另一个子指令来保持父指令逻辑,该怎么办? 重载属性很容易我可以使用&#34;编译&#34;功能。但是覆盖功能怎么样呢?

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

通过使用子范围而不是隔离,可以轻松完成所有事情。 或者通过使用模板扩展。但如果我用模板扩展指令,我将不得不复制父&#34;范围&#34;和&#34;模板&#34;定义到child-directive并转发所有非默认属性,这似乎不是一个优雅的解决方案。

所以关键问题是,有没有办法使用隔离范围覆盖父指令函数而不转发属性。

以下是DEMO

1 个答案:

答案 0 :(得分:0)

好的,我做了一些研究,结果发现可以有几种方法

范围继承

由于child-directive未创建自己的范围,因此只需在parent-directive父范围创建新方法。因此我们可以在编译期间修改属性并指定重写的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()";
    }
  }
});

以下是DEMO1

添加到隔离范围

Angular提供特殊功能。这可以从元素中获得孤立的范围。所以我们可以在链接阶段覆盖我们的方法。

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

以下是DEMO2

控制器方法

如果我们使用controllerAs语法。这意味着我们将控制器对象变量公开为范围。我们可以在链接阶段覆盖子指令中的函数。

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


    }
  }
});

以下是DEMO3

<强> Transclusion

实际上,您可以使用单独的父级和子级指令以及使用翻译来执行相同的操作。但无论如何,它将是上述方法的组合。感谢"Extending an existing directive in AngularJS"