如何在实例化指令控制器之前扩充isolate指令范围?

时间:2015-08-19 16:23:28

标签: javascript angularjs

我正在编译并将指令与隔离范围链接起来(请注意这是手动编译和链接,原因超出了本问题的范围):

    outerElement = angular.element(domElement);
    $injector = outerElement.injector();
    $compile = $injector.get('$compile'); 
    getTheIsolateScopeForMyDirectiveInstance().myProperty = 'foo'; // Pseudocode. I want myProperty to be available on the scope from inside the controller constructor function.
    link = $compile(angular.element('<my-directive></my-directive>'));
    // IIUC, the following line will instantiate 
    // the controller for the directive, injecting 
    // the isolate scope. I want to augment the 
    // isolate scope that is injected *before* it 
    // is injected. 
    // The value to augment the scope resides in 
    // *this* execution context.
    // How can I do so?
    renderedElement = link(outerElement.scope());
    element.append(renderedElement);

MyDirective有一个隔离范围(我要扩充的范围),以及与之关联的控制器。

控制器MyDirectiveController利用注入器注入其隔离范围。

MyDirectiveController.$inject = [ '$scope' ];

我希望在注入到MyDirectiveController的实例之前扩充隔离范围,其值只能在上面代码的执行上下文中的运行时知道

我该怎么做?

MyDirective

function MyDirective() {
    return {
        scope: {}, // I want to augment this before it is injected into  MyDirectiveController
        restrict: 'E',
        template: template,
        controller: 'myDirectiveController',
        controllerAs: 'ctrl',
        replace: true,
    };
}

MyDirectiveController

function MyDirectiveController($scope) {
    console.log($scope.myProperty); // Should be 'foo'.
}

MyDirectiveController.$inject = ['$scope'];

如果这是不可能的,是否有其他方式可以使控制器可以使用特定于实例的信息和/或隔离指令的范围?

我现在能想到的唯一方法是扩充上面提供给link(outerElement.scope())的范围,然后在指令的隔离范围上定义=属性。

修改

这就是我现在正在做的事情,myProperty值最终会出现在控制器的隔离范围的父级上:

var isolate = outerElement.scope().$new(true);
isolate.myProperty = 'foo';
renderedElement = link(isolate);
element.append(renderedElement);

鉴于此,实例化MyDirectiveController时:

function MyDirectiveController($scope) {
  $scope.myProperty; // undefined
  $scope.$parent.myProperty; // 'foo'
}

2 个答案:

答案 0 :(得分:2)

这里的假设

  

控制器MyDirectiveController利用注入器   它的隔离范围注入。

     

MyDirectiveController。$ inject = ['$ scope'];

     

我希望在将隔离范围注入到隔离范围之前对其进行扩充   MyDirectiveController的一个实例,其值只有在   运行时在上面代码的执行上下文中。

错了。 $inject只不过是注释,只有在代码缩小时才会有所作为。

在链接指令之前,你不能将任何东西“注入”隔离范围。一些丑陋的猴子修补可以解决这个问题:

  var _new = scope.$new;
  scope.$new = function () {
    return angular.extend(_new.apply(this, arguments), {
      myProperty: 'foo'
    })
  };
  $compile(angular.element('<my-directive></my-directive>'))(scope);
  scope.$new = _new;

但即使可能,它也适合编写测试而不适用于生产代码。

这里唯一直截了当的方式(以及使用隔离范围的原因)是

function MyDirective() {
    return {
        scope: {
            myProperty: '='
        },
        ...
    };
}

$compile(angular.element('<my-directive my-property="myProperty"></my-directive>'))(scope);

其中scope.myProperty等于'foo'。

答案 1 :(得分:1)

UPDATE2 :如果您需要隔离范围,请创建new scope

 var myparentscope = outerElement.scope()
 var myscope = myparentscope.$new(true) // or $rootScope.$new(true, myparentscope), see true here, it isolates scope from parent.
 myscope.prop = 'new prop' // define on child scope.
 renderedElement = link(myscope);
 element.append(renderedElement);

<强>更新: 代码中的最后四行:

getTheIsolateScopeForMyDirectiveInstance().myProperty = 'foo'; 
link = $compile(angular.element('<my-directive></my-directive>'));
renderedElement = link(outerElement.scope());
element.append(renderedElement);

应该是:

var myscope = outerElement.scope()
scope.myProperty = 'foo'
renderedElement = link(myscope);

原始回答

 .directive('myDirective',['$compile', function($compile) {
      return {
         link:link,
         scope: {
         }
      }

      function link(scope, element) {
         scope.prop = 'new value'  // new property on scope           
         var renderedElement = $compile('... html ...')(scope);
         element.append(renderedElement);
      }
 })

另外

  

$ compile = $ injector.get(&#39; $ compile&#39;); //我认为这是实例化的   幕后与myDirective相关的控制器?

$inject.get('$compile')是获得$compile服务的复杂方式。如果编译服务不是(并且它不是)依赖于您的服务,您可以像通常那样使用依赖注入来指定它。

此外,我认为您需要阅读本部分关于指令生命周期中的编译和链接步骤。

编译步骤不是$compile服务。编译步骤在应用程序的每个生命周期执行一次,将其视为使用指令的所有实例的准备。

链接步骤(前后链接)正在执行您准备好的指令,并实际将其实例化为您应用中的特定位置/范围等。

由于您需要更新范围 - 这是您要使用的链接步骤。

有关该主题的精彩视频 - https://egghead.io/lessons/angularjs-compile-pre-and-post-link