被转换的内容需要transcluding指令的控制器

Daa*_*ron 4 javascript angularjs angularjs-directive

我有一个指令,它将转录它的内容.并且在被抄送的内容中是一个指令,它需要transcluding指令的控制器.如果我在transcluding指令中创建了一个transclude函数,则抛出一个错误.我认为这是因为当你提供一个transclude函数时,被克服的内容会被克隆(https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L846).

我也有一个描述我的问题的傻瓜:http://plnkr.co/edit/rRKWW6zfjZuUiw1BY4zs?p = preview

我想要做的是我想要转换内容并解析所有被转换的内容,然后将它放在DOM中的正确位置并自己编译.被抄送的内容实际上是我的指令的配置.

我也尝试清空我在transcluding函数中收到的克隆数组,因为我实际上不需要自动转换内容.我只需要解析它并在稍后的时间点手动转换它.Angular不需要对我的被抄送的内容做任何事情.但这不起作用,因为在调用transcluding函数时已经识别出指令.所以当我清空数组时,我收到一个错误(https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L961).

亲切的问候,

大安

Joe*_*ger 9

当您使用时,require: "^controller"您告诉Angular该指令需要controller在链接函数运行时附加到祖先DOM元素.

当你在不使用ngTransclude指令的情况下进行转换时,你的父指令链接函数get传递了一个transclude方法.(你已经知道了;这只是为了完整性.)这个transclude方法执行以下操作:

  1. 提取内容以进行翻译
  2. 如果cloneAttachFn传入了a,则克隆内容并调用cloneAttachFn
  3. 调用$compile()使用调用transclude提供的作用域编译和链接内容(或克隆的内容)(默认为从指令作用域的$ parent继承的新作用域).

如果您调用transclude,并且最终没有将内容作为具有所需控制器的元素的后代附加(或者根本不将内容添加到DOM),则内容将不具有所需控制器的父级.因为它找不到所需的控制器,所以会出错.

在您的示例中,如果您使用kmBar require: "^kmFoo",则只能将已转换的内容添加到DOM节点,这些DOM节点是具有kmFoo的节点的后代.

最简单的解决方法是继续将其附加到kmFoo的元素以用于$ compile()和链接,但立即分离.

分离(而不是删除)维护单击处理程序等,因此如果稍后附加元素,一切都将继续有效.如果您使用的是AngularJS的早期版本,则可能需要包含jQuery以进行分离,因为它未包含在早期版本的jqLit​​e中.

这是我放在一起的Plunk的片段

app.directive('kmFoo', function() {
  return {
    restrict: 'A',
    scope: true,
    template: '<div></div>',
    transclude: true,
    controller: function() {
      // ...
    },
    link: function(scope, $element, attrs, ctrl, transcludeFn) {
      console.log('linking foo');
      // We are going to temporarily add it to $element so it can be linked,
      //  but after it's linked, we detach it.
      transcludeFn(scope, function(clone) {
        console.log('transcluding foo');
        $element.append(clone);
        c = clone;
      }).detach();// <- Immediately detach it
    }
  };
});

app.directive('kmBar', function() {
  return {
    restrict: 'A',
    scope: true,
    require: '^kmFoo',
    link: function(scope, $element, attrs, fooCtrl) {
      console.log('linking bar');
      // Right now it's a child of the element containing kmFoo,
      //  but it won't be after this method is complete.
      // You can defer adding this element to the DOM
      //  for as long as you want, and you can put it wherever you want.
    }
  };
});
Run Code Online (Sandbox Code Playgroud)


Pie*_*len 0

首先,为什么需要 transclude 函数?这还不够吗?

app.directive('kmFoo', function() {
  return {
    'restrict': 'A',
    'scope': true,
    'controller': function() {
      this.tryMe = function() { console.log("Success!") };
    },
    'link': function(scope, element, attrs, ctrl) {
      console.log('linking foo');
      var innerHtml = element.html();
      // do something with innerHtml
      element.html("<div>Empty</div>");
    }
  };
});

app.directive('kmBar', function() {
  return {
    'restrict': 'A',
    'scope': true,
    'require': '^kmFoo',
    'link': function(scope, element, attrs, fooCtrl) {
      fooCtrl.tryMe();
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

但是,如果您确实想访问 fooController 并在 kmFoo 中具有 transclude 函数,则可以element.controller()在完成所有链接并初始化所有控制器后通过 访问控制器。

app.directive('kmFoo', function() {
  return {
    'restrict': 'A',
    'scope': true,
    'template': '<div ng-transclude></div>',
    'transclude': true,
    'controller': function() {
      this.tryMe = function() { console.log("Success!") };
    },
    'link': function(scope, $element, attrs, ctrl, transcludeFn) {
      console.log('linking foo');
      // when you put the transclude function in comments it won't throw an error
      transcludeFn(scope, function(clone) {
        console.log('transcluding foo');
      });
    }
  };
});

app.directive('kmBar', function() {
  return {
    'restrict': 'A',
    'scope': true,
    'template': "<button ng-click='tryMe()'>Feeling lucky?</button>",
    'link': function(scope, element, attrs) {
      scope.getFooCtrl = function() { 
        return element.parent().controller('kmFoo'); 
      };
      console.log('linking bar');
      console.log('parent not yet known: ' + element.parent().toString());
    },
    'controller': function($scope) {
      $scope.tryMe = function() {
        $scope.getFooCtrl().tryMe();
      };
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

使用plnkr查看它的实际效果。