【问题标题】:Pass through applicable directives to custom directive将适用指令传递给自定义指令
【发布时间】:2016-08-16 07:45:19
【问题描述】:

我了解如何通过我的自定义指令传递指令,如下所示:

页面.html

<my-directive read-only-attr="myVariable" label-style-attr="anotherVariable"></my-directive>

指令

myApp.directive("myDirective", function () {
  return {
    restrict: "E",
    templateUrl: "myTemplate.html",
    scope: {
      readOnlyScopeVar: "=readOnlyAttr",
      styleScopeVar: "=labelStyleAttr"
    },
    link: function (scope, element, attrs) {

    }
  };
});

模板

<div>
  <label ng-style="styleScopeVar" />
  <input type="text" ng-readonly="readOnlyScopeVar" />
</div>

我的模板比这复杂得多,但我为问题简化了它。

我的问题是:如果用户没有在我的指令上指定“只读属性”或“标签样式属性”,我如何防止 ngReadonly 和 ngStyle 运行?我希望允许人们将大量常见的角度指令应用于我的模板中的输入和其他元素(ngClass、ngDisabled、ngChange、ngPattern、ngIf 等),但如果人没有在我的指令中指定它们。就好像我需要一个模板来构建模板一样。

另外,请注意,我已经阅读了关于嵌入的内容,但我不喜欢允许用户直接编辑输入元素的想法,并且在这个示例中我可能想要应用多个元素,我可以如果只读属性引用为真,则更改标签颜色。

【问题讨论】:

    标签: angularjs angularjs-directive


    【解决方案1】:

    一种方法是使用 $compile。这是一个有效的plnkr: https://plnkr.co/edit/S8pUSH?p=preview 请注意,有很多方法可以做到这一点,这只是一个简单的演示示例:

    var app = angular.module('app', []); //define the module
    
    //setup the template
    app.run(['$templateCache', function($templateCache){
      $templateCache.put('someDirectiveTmpl','<div>\
      <label $$%%ngStylePlaceholder$$%% />My Label:</label>\
      <input type="text" $$%%ngReadonlyPlaceholder$$%% />\
    </div>');
    }])
    
    /**
     * @description someDirective gets a config object that holds dynamic directives' names and values. e.g.:
     * {
     *  'ngStyle': '{background: red;}',
     *  'ngReadonly': true
     * }
     * 
     */ 
    app.directive('someDirective', ['$log', '$compile', '$templateCache', function($log, $compile, $templateCache){
      return {
        restrict: 'AE',
        controllerAs: 'someDirectiveCtrl',
        scope: {},
        bindToController: {
          directiveConfig: '='
        },
        controller: function($scope, $element){
          // a method to convert camelcase to dash
          function camelCaseToDash( myStr ) {
            return myStr.replace( /([a-z])([A-Z])/g, '$1-$2' ).toLowerCase();
          }
    // get the template
          var template = $templateCache.get('someDirectiveTmpl');
          var placeHolderRegExp = /\$\$%%(.*)\$\$%%/g; 
          // place the binding per existing property
          angular.forEach(this.directiveConfig, function(varName, key){
            template = template.replace('$$%%' + key + 'Placeholder$$%%', camelCaseToDash(key) + '="someDirectiveCtrl.directiveConfig.' + key + '"');
          });
    
          // remove unneeded properties placeholders
          template.replace(placeHolderRegExp, '');
    
          //compile the directive
          var templateElement = angular.element(template);
          $compile(templateElement)($scope);
    // append to element
          $element.append(templateElement);
    
        }
      }
    }]);
    

    注意模板中的$$%%ngAnythingPlaceholder$$%%。我从父指令获取配置(在 plnkr 中,为了简单起见,我使用了控制器)。我在示例中使用了配置对象(您可以使用单独的变量来执行此操作,但我喜欢设置配置对象 API)。 然后我根据配置中的内容替换占位符并删除我不需要的内容。然后我编译模板。 在父指令的控制器中,您可以执行类似于我在控制器中所做的操作:

    $scope.config = {
        ngReadonly: true
      }
    

    再次,我注意到您不应该使用控制器,当然也不应该使用 使用 $scope 本身,但指令的控制器使用 this。我用 $scope 和控制器在这里只是为了便于演示。

    您可以在此配置中添加任何您想要的内容(当然,在模板中的各种参数中添加占位符)。 现在只需将指令添加到您的模板:

    <some-directive directive-config="config"></some-directive>
    

    【讨论】: