AngularJS:无法将属性从第一个指令插入到第二个指令。 (带有plunker示例)

时间:2015-06-15 20:25:53

标签: angularjs angularjs-directive angularjs-controller angularjs-compile

参考

参考plunker:http://plnkr.co/edit/otv5mVVQ36iPi3Mp0FYw?p=preview

问题说明

假设我们有两个指令first-directivesecond-directive。现在假设我们只能访问first-directive,我们希望将second-directive包裹起来并传递给我们自己的操纵属性。

app.directive('firstDirective', function() {
  return {
    scope: true,
    priority: 1000,
    transclude: true,

    template: function(element,attributes){
      console.log('template')
      return '<second-directive two="{{one}}"></second-directive>'
    },

    compile: function(element,attributes) {
      console.log('compile')
      return {
        pre: function(scope){
          scope.one = 'foo'
            console.log('cpre')
        },
        post: function(scope){
          scope.one = 'foo'
            console.log('cpost')
        },
      }
    },

    controller: ['$scope','$attrs',function($scope,$attrs){
      console.log('controller');
      $scope.one = 'foo';
    }],
  }
})

app.directive('secondDirective',function(){
  return {
    template: function (element,attributes){
      console.log(attributes.two) //{{one}} not 'foo' or 'test'
      return 'Hello {{two}}'
    }
  }
});    

first-directive的调用如下:

<first-directive one='test'></first-directive>

console.log输出如下:

template
compile
{{one}}
controller
cpre
cpost

因此我从中了解到在编译之前调用了模板。这是我新手眼中的特殊情况,因为无论如何都无法通过编译,控制器,前置或后置链接来操纵模板函数传回的值!

问题是:

如何使用我想要的动态属性值调用second-directive?请注意,second-directive完全独立,我们无法在那里添加代码。

PS - 我有一个可能的想法是按如下方式调用第二个指令:

template: function(element,attributes){
  console.log('template')
  var explicit = ???? /* how to access scope? */
  return '<second-directive two="'+ explicit +'"></second-directive>'
},

或者

template: function(element,attributes){
  console.log('template')
  return $interpolate('<second-directive two="{{one}}"></second-directive>')(scopeObj) /* how does one access scopeObj with current scope values here? */
},

然而,再次,我不确定如何在调用任何其他函数之前将值传递给first-directive。 Controller可以访问$ scope,它被称为AFTER模板。

您的建议非常感谢。

5 个答案:

答案 0 :(得分:0)

您是否写过第二条指令?

<second-directive two="'+ explicit +'"></second-directive>

要使上述代码正常工作,您需要在第二个指令中设置隔离范围对象,请查看下面的插件。

http://plnkr.co/edit/YP2h3MOhsrjN5sLUNQs6?p=preview

答案 1 :(得分:0)

我正在使用你的问题来学习,但我能找到这个,这对你有用:

app.directive("tryThis", function($compile){
    return{
        scope: {
          one: '@',
        },
        link: function(scope, element){
            var template = '<second-directive two="'+scope.one+'"></second-directive>';
            var linkFn = $compile(template);
            var content = linkFn(scope);
            element.append(content);
        }
    }
});

Plunkr为here,请注意,控制台现在会记录test而不是{{one}}。如果secondDirective被赋予隔离范围,则test将显示在屏幕上。

这个link也帮助我从概念上理解了你所面临的问题,给出了“编译期间没有范围”这一问题的一些背景 - 我不确定是否有办法解决这个问题。

答案 2 :(得分:0)

如果您只想将第一个指令中的数据传递给第二个指令模板,那么您可以使用
在第一个指令控制器中添加动力学属性 this.fromFirstDir =“你可以从这里传递”

第一个指令控制器:

controller: ['$scope','$attrs',function($scope,$attrs){
      console.log('controller');
      $scope.one = 'foo';

      this.fromFirstDir = "you can pass from here"
    }],
  }

然后使用 secondDirective 中的 require 属性作为第一个指令控制器,您可以从 secondDirective 指令的链接功能访问此动态属性使用控制器传递给链接功能。最后将这些属性分配给传递给链接函数的本地范围。

app.directive('secondDirective',function(){
  return { 
    scope: {twoData : '@twoData'},
    require : '^firstDirective',
    template: function (element,attributes){
      console.log(attributes.two) //{{one}} not 'foo' or 'test'
      return 'Hello <b>{{fromFirstDir}}</b>'
    },
    link : function(scope,element,attr,firstDirCtrl){
      console.log("===",firstDirCtrl.fromFirstDir) 
      scope.fromFirstDir = firstDirCtrl.fromFirstDir;
    }
  }
});

通过这种方式,您的第二个指令可以使用这些动态属性。

这是最后的fiddle

希望这会对你有所帮助。

答案 3 :(得分:0)

您不能(不能)访问模板内的范围(因为此时没有范围)。该模板用于创建一个或多个元素,然后将它们链接到一个范围(在实例化其控制器之后 - 如果有的话)。

有很多方法可以在指令之间传递值,每种方法最适合特定用途。最简单的(但不一定是最好的,取决于你的用例细节)是在wrapper指令的作用域上赋值,让内部指令从作用域读取它:

<!-- HTML -->
<one for-two="{{test}}"></one>

// JS
angular.
  module('myApp', []).
  directive('one', oneDirective).
  directive('two', twoDirective);

function oneDirective() {
  return {
    restrict: 'E',
    scope: true,
    link: function onePostLink(scope, elem, attrs) {
      scope.two = attrs.forTwo;
    },
    template: '<two></two>'
  };
}

function twoDirective() {
  return {
    restrict: 'E',
    template: 'Hello, {{two}} !'
  };
}

答案 4 :(得分:0)

您有transclude: true但未在模板中使用它。你不能只使用这个标记并使用第一个指令的模板<ng-transclude>吗?你有scope: true所以你可以从父/控制器中操作属性,并且更改将传播到两个指令。

标记

<first-directive one="test">
    <second-directive two="test"></second-directive>        
</first-directive>

第一指令的模板

template: `<div>
               my first directive content
               <ng-transclude></ng-transclude>
           </div>`;

https://docs.angularjs.org/api/ng/directive/ngTransclude