Javascript 具有可选属性的角度指令

Javascript 具有可选属性的角度指令,javascript,angularjs,angularjs-directive,Javascript,Angularjs,Angularjs Directive,我有一个自定义的下拉指令,它具有诸如class和ng model等公共属性 我已经决定扩展此控件以支持验证,现在需要包括可选属性,这些属性只有在由程序员设置时才应包含在输出模板中 样本 'use strict'; angular.module(APP) .directive('wkKeyLabelSelect', ["$compile", function($compile) { return { restrict: 'EA', repl

我有一个自定义的下拉指令,它具有诸如classng model等公共属性

我已经决定扩展此控件以支持验证,现在需要包括可选属性,这些属性只有在由程序员设置时才应包含在输出模板中

样本

'use strict';

angular.module(APP)
  .directive('wkKeyLabelSelect', ["$compile",
    function($compile) {
      return {
        restrict: 'EA',
        replace: true,
        scope: {
          'class': '@',              // Permanent - One Way Attribute
          ngModel: '=',              // Permanent - Two Way Attribute (Angular)
          items: '=',                // Permanent - Two Way Attribute (Custom)
          id: '@',                   // Dynamic - One Way Attribute
          name: '@',                 // Dynamic - One Way Attribute
          ngRequired: '=',           // Dynamic - Two Way Attribute (Angular) 
      },
        //templateUrl: COMPONENTS_PATH + '/keyLabelSelect/keyLabelSelect.html',
        controller: 'KeyLabelSelectController',
        link: function (scope, element, attrs) {
          //$compile(element)(scope);
        },
        compile: function (element, attrs) {

          // name & ngRequired are not available in the compile scope
          //element.replaceWith($compile(html)(scope));

          return {
            pre: function preLink(scope, iElement, iAttrs, controller) {

            },
            post: function postLink(scope, iElement, iAttrs, controller) {

              // Template goes here
              var html =
                '<select ' +
                  ' class="{{class}}"' +
                  (scope.id ? ' id="{{id}}"' : "") +
                  (scope.name ? ' name="{{name}}"' : "") +
                  (scope.ngRequired ? ' ng-required="true"' : "") +
                  ' ng-model="ngModel"' +
                  ' ng-options="item.key as item.label for item in items"' +
                  '>' +
                '</select>';

              iElement.replaceWith($compile(html)(scope));
            }
          }
        }
      };
    }
  ]);
<div class="form-group" ng-class="{ 'has-error': editForm.state.$touched && editForm.name.$invalid }">
    <label class="col-md-3 control-label">State</label>
    <div class="col-md-9">
        <wk-key-label-select id="state" name="state"
                                ng-required="true"
                                ng-model="model.entity.state"
                                class="form-control input-sm"
                                items="model.lookups.job_state">
        </wk-key-label-select>

        <div class="help-block" ng-messages="editForm.state.$error">
            <p ng-message="required">Job State is required.</p>
        </div>
    </div>

</div>

我有一个部分工作的系统,在这个系统中,我将代码从模板URL移到了字符串连接中,我在编译指令的post:函数中调用了该字符串连接

我本希望将指令HTML保留在模板中,但无法使其工作,因此我有了此解决方案

问题:

  • 这是编写具有动态属性的模板的最佳方法吗
  • 在将HTML保留在模板URL中时,是否可以使其工作
  • 我应该使用compile=>post函数,还是应该在link函数中使用
  • 指令代码

    'use strict';
    
    angular.module(APP)
      .directive('wkKeyLabelSelect', ["$compile",
        function($compile) {
          return {
            restrict: 'EA',
            replace: true,
            scope: {
              'class': '@',              // Permanent - One Way Attribute
              ngModel: '=',              // Permanent - Two Way Attribute (Angular)
              items: '=',                // Permanent - Two Way Attribute (Custom)
              id: '@',                   // Dynamic - One Way Attribute
              name: '@',                 // Dynamic - One Way Attribute
              ngRequired: '=',           // Dynamic - Two Way Attribute (Angular) 
          },
            //templateUrl: COMPONENTS_PATH + '/keyLabelSelect/keyLabelSelect.html',
            controller: 'KeyLabelSelectController',
            link: function (scope, element, attrs) {
              //$compile(element)(scope);
            },
            compile: function (element, attrs) {
    
              // name & ngRequired are not available in the compile scope
              //element.replaceWith($compile(html)(scope));
    
              return {
                pre: function preLink(scope, iElement, iAttrs, controller) {
    
                },
                post: function postLink(scope, iElement, iAttrs, controller) {
    
                  // Template goes here
                  var html =
                    '<select ' +
                      ' class="{{class}}"' +
                      (scope.id ? ' id="{{id}}"' : "") +
                      (scope.name ? ' name="{{name}}"' : "") +
                      (scope.ngRequired ? ' ng-required="true"' : "") +
                      ' ng-model="ngModel"' +
                      ' ng-options="item.key as item.label for item in items"' +
                      '>' +
                    '</select>';
    
                  iElement.replaceWith($compile(html)(scope));
                }
              }
            }
          };
        }
      ]);
    
    <div class="form-group" ng-class="{ 'has-error': editForm.state.$touched && editForm.name.$invalid }">
        <label class="col-md-3 control-label">State</label>
        <div class="col-md-9">
            <wk-key-label-select id="state" name="state"
                                    ng-required="true"
                                    ng-model="model.entity.state"
                                    class="form-control input-sm"
                                    items="model.lookups.job_state">
            </wk-key-label-select>
    
            <div class="help-block" ng-messages="editForm.state.$error">
                <p ng-message="required">Job State is required.</p>
            </div>
        </div>
    
    </div>
    
    用于运行指令的HTML

    'use strict';
    
    angular.module(APP)
      .directive('wkKeyLabelSelect', ["$compile",
        function($compile) {
          return {
            restrict: 'EA',
            replace: true,
            scope: {
              'class': '@',              // Permanent - One Way Attribute
              ngModel: '=',              // Permanent - Two Way Attribute (Angular)
              items: '=',                // Permanent - Two Way Attribute (Custom)
              id: '@',                   // Dynamic - One Way Attribute
              name: '@',                 // Dynamic - One Way Attribute
              ngRequired: '=',           // Dynamic - Two Way Attribute (Angular) 
          },
            //templateUrl: COMPONENTS_PATH + '/keyLabelSelect/keyLabelSelect.html',
            controller: 'KeyLabelSelectController',
            link: function (scope, element, attrs) {
              //$compile(element)(scope);
            },
            compile: function (element, attrs) {
    
              // name & ngRequired are not available in the compile scope
              //element.replaceWith($compile(html)(scope));
    
              return {
                pre: function preLink(scope, iElement, iAttrs, controller) {
    
                },
                post: function postLink(scope, iElement, iAttrs, controller) {
    
                  // Template goes here
                  var html =
                    '<select ' +
                      ' class="{{class}}"' +
                      (scope.id ? ' id="{{id}}"' : "") +
                      (scope.name ? ' name="{{name}}"' : "") +
                      (scope.ngRequired ? ' ng-required="true"' : "") +
                      ' ng-model="ngModel"' +
                      ' ng-options="item.key as item.label for item in items"' +
                      '>' +
                    '</select>';
    
                  iElement.replaceWith($compile(html)(scope));
                }
              }
            }
          };
        }
      ]);
    
    <div class="form-group" ng-class="{ 'has-error': editForm.state.$touched && editForm.name.$invalid }">
        <label class="col-md-3 control-label">State</label>
        <div class="col-md-9">
            <wk-key-label-select id="state" name="state"
                                    ng-required="true"
                                    ng-model="model.entity.state"
                                    class="form-control input-sm"
                                    items="model.lookups.job_state">
            </wk-key-label-select>
    
            <div class="help-block" ng-messages="editForm.state.$error">
                <p ng-message="required">Job State is required.</p>
            </div>
        </div>
    
    </div>
    
    
    陈述
    作业状态是必需的

    我的原始模板URL内容,当前未使用

    <!-- This is now deprecated in place of inline string -->
    <!-- How could I use a in place of string concatenation  -->
    
    <select class="{{klass}}"
            name="{{name}}"
            ng-model="ngModel"
            ng-options="item.key as item.label for item in items"></select>
    
    
    
    引入自定义输入控制器的“正确”方法是支持。这使您的自定义控件能够与支持
    ngModel
    的其他指令集成,如自定义验证器、解析器等。这有点棘手,但使您的控件与框架的内置控件无法区分:

    .directive("customSelect", function() {
      return {
        require: "?ngModel",
        scope: {
          itemsExp: "&items" // avoids the extra $watcher of "="
        },
        template: '<select ng-model="inner" \
                           ng-options="item.key as item.label for item in itemsExp()"\
                           ng-change="onChange()"></select>',
        link: function(scope, element, attrs, ngModel) {
          if (!ngModel) return;
    
          // invoked when model changes
          ngModel.$render = function() {
            scope.inner = ngModel.$modelValue;
          };
    
          scope.onChange = function() {
            ngModel.$setViewValue(scope.inner);
          };
        }
      };
    });
    

    这似乎不是你所问问题的答案,但那只是因为你的问题有点像XY问题。通过实现自定义输入控件,您可以实现您开始要做的事情—将
    name
    属性分配给指令(如果提供了表单指令,则该指令会将自身注册到表单指令中),并且
    ng required
    本机工作。但是,如果必须将
    name
    /
    id
    分配给基础
    (出于CSS原因或诸如此类的原因),则可以使用
    ng attr-
    有条件地应用属性。模板将更改为:

    <select ng-attr-name="attrs.name || undefined"
            ng-attr-id  ="attrs.id   || undefined"
            ng-model="inner" ...
    

    为什么您的代码截图与粘贴的代码完全相同?另外,您似乎正在实现一个,但是您应该正确地使用
    ngModelController
    ——执行
    范围:{ngModel:=“}
    是错误的方法。图像用特定的问题注释,指向有问题的代码。这就是为什么它看起来像是重复的,我有代码和带注释的图像。我不知道ngModelController,现在正在对此进行研究。作为对“应该Peropely使用ngModelController”的回应,我做了一些研究,因为我没有做自定义验证或复杂属性,无需引入使用ngModelController的复杂性。我的观点来源是:您正在引入一个自定义输入控件。当然,它在模板中使用了现有的输入控件,但是如果您希望它支持
    ngModel
    模型(即支持其他验证器、自定义解析器、与
    集成等),那么最好使用
    ngModelController
    。你不必,但那是最有棱角的方式。总的来说,你问的是一个XY问题——相反,请解释一下你试图通过自定义下拉菜单实现什么,普通的
    无法提供。ng attr上的第二秒是一个真正的帮助,我在这里读到了:大多数情况下,我在可选属性方面遇到了问题(@DavidCruwys,可选属性有什么问题?