具有隔离范围和附加属性的指令,不适用于内部指令

时间:2014-06-03 13:47:26

标签: angularjs

我想要一个带有隔离范围的指令,并在指令中设置该范围的属性。那就是创建一些环境变量,这些变量将由其中的其他指令显示,如下所示:

HTML:

<div environment>          <!-- this directive set properties to the scope it creates-->
  {{ env.value }}                  <!-- which would be available -->
  <div display1 data="env"></div>  <!-- to be displayed by other directives (graphs, -->
  <div display2 data="env"></div>  <!-- charts...) -->
</div>

JS:

angular.module("test", [])
  .directive("environment", function() {
    return {
      restrict: 'A',
      scope: {},
      link: function(scope) {
        scope.env = {
          value: "property set from inside the directive"
        };
      }
    };
  })
  .directive("display1", function() {
    return  {
      restrict: 'A',
      require: '^environment'
      scope: {
        data: '='
      },
      link: function(scope, elt, attr, envController) {

        scope.$watch('data', function(oldV, newV) {
          console.log("display data");
        });

      }
    };
  })
  .directive("display2", function() {
    return {/* ... */};
  });

但它不起作用。这是a Plunker。 如果我删除隔离,它可以正常工作。我做错了什么?这是一个跨性别问题吗?如果我在'environment'指令中使用模板似乎有效,但这不是我想要的。

感谢您的帮助。

修改:我看到同样的问题已解答here。建议的解决方案是使用控制器而不是指令。我想使用指令的原因是可以在内部指令中使用'require',这是我认为无法用ngController完成的事情。

2 个答案:

答案 0 :(得分:0)

通过引入外部模板,我设法找到了解决问题的可行方案。 我很确定你设置它的方式在某些方面有效,但我无法确定何时。我最后一次构建了一个依赖于外部标记文件的指令而不是,我甚至都不知道。

在任何情况下,如果您愿意为指令引入单独的模板,则以下内容应该有效:

app.directive('environment', function () {
    return {
        restrict: 'A',
        templateUrl: 'env.html',
        replace: true,
        scope: {},
        link: function (scope, el, attrs) {
            scope.env = {
              value: "property set from inside the directive"
            };
        }
    };
});

app.directive('display1', function () {
    return {
        restrict: 'A',
        scope: {
            data: '='
        },
        templateUrl: 'display1.html',
        replace: false,
        link: function(scope) {
            // console.log(scope.data);
        }
    };
});

然后对于你的标记(这些标记不会真实地放在<script>标签中,你很可能会有一个外部模板,但这只是从我设置的小提琴中获取的)。

<script type="text/ng-template" id="display1.html">
    <span>Display1 is: {{data}}</span>
</script>

<script type="text/ng-template" id="env.html">
    <div>
        <h1>env.value is: {{env.value}}</h1>
        <span display1 data="env.value"></span>        
    </div>
</script>

<div>
    <div environment></div>
</div>

小提琴链接:http://jsfiddle.net/ADukg/5421/

编辑:看完之后想要使用模板(应该先完成..),这是另一个让它运行的解决方案。不幸的是,你可以选择的唯一一个(除了一些其他的,链接来自下面),在我看来,它不是一个好看的...

app.directive('environment', function () {
    return {
        restrict: 'A',
        template: function (element, attrs) {
          return element.html();
        },
        scope: {},
        link: function (scope, el, attrs) {
          scope.env = {
            value: "property set from inside the directive"
          };
        }
    };
});

标记:

<div environment> {{env.value}} </div>

小提琴:http://jsfiddle.net/7K6KK/1/

说出你对它的看法,但确实可以解决问题。

Here's a thread off of the Angular Github Repo,概述了您的问题以及为什么'支持'。

答案 1 :(得分:-1)

我对你的Plunker做了一个小编辑 当你在指令范围内创建变量时,其他指令可以直接或通过双向数据绑定以两种方式(在plunker中显示)访问它

HTML:

<body ng-app="test">
  <div environment>
    {{ env.value }}
    <div display1 data="env"></div>
    <div display2 data="env"></div>
  </div>
</body>
  <input type="text" ng-model="env.value"> #added to show two-way data binding work
  <div display1 info="env"></div> #changed name of attribute where variable is passed, it's then displayed inside directive template
  <div display2>{{env.value}}</div> #env.value comes from environment directive not from display2
</div>

JS

angular.module("test", [])
  .directive("environment", function() {
    return {
      restrict: 'A',
      scope: true, #changed from {} to true, each environment directive will have isolated scope
      link: function(scope) {
        scope.env = {
          value: "property set from inside the directive"
        };
      }
    };
  })
  .directive("display1", function() {
    return  {
      restrict: 'A',
      template: '<span ng-bind="info.value"></span>', #added template for directive which uses passed variable, NOTE: dot in ng-bind, if you try a two-way databinding and you don't have a dot you are doing something wrong (Misko Hevry words)
      scope: {
        info: '=' #set two-way data binding for variable from environment directive passed in 'info' attribute
      }, #removed unnecessary watch for variable
    };
  })
  .directive("display2", function() {
    return {/* ... */};
  });