簡體   English   中英

具有可選屬性的角度指令

[英]Angular Directive with Optional Attributes

我有一個自定義下拉指令,它具有常見的屬性,如classng-model

我已決定擴展此控件以支持驗證,現在需要包含可選屬性,如果它們由程序員設置,則只應包含在輸出模板中。

樣品

指令調用示例

我有一個部分工作的系統,我將代碼從模板URL中移出並轉換為字符串連接,我在post:函數中指令編譯。

我本來希望將我的指令HTML留在模板中,但是無法使其工作,所以我有這個解決方案。

問題:

  1. 這是使用動態屬性編寫模板的最佳方法嗎?
  2. 將HTML保留在模板URL中可以使其工作
  3. 我應該使用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));
            }
          }
        }
      };
    }
  ]);

指令控制器代碼

angular.module(APP)

.controller('KeyLabelSelectController', ['$scope', function ($scope) {

  $scope.klass = typeof $scope.klass === 'undefined' ? 'form-control' : $scope.klass;

  console.log($scope.ngModel);
  console.log($scope.items);

}]);

用於運行指令的HTML

<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>

問題

引入自定義輸入控制器的“正確”方法是支持ngModelController 這使您的自定義控件能夠與支持ngModel其他指令集成,如自定義驗證器,解析器, <form> 這有點棘手,但是使您的控件與框架的內置控件無法區分:

.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);
      };
    }
  };
});

然后,它可以與其他控件整齊地集成,並利用本機ng-required驗證器:

<custom-select name="c1" ng-model="c1" items="items" ng-required="true">
</custom-select>

演示

這似乎不是你提出的問題的答案,但這只是因為你的問題是一個XY問題。 通過實現自定義輸入控件,你實現自己為自己設定的事-指定name屬性的指令(其本身注冊形式的指令,如果提供的話)和ng-required作品本身。 但是,如果必須name / id分配給基礎<select> (出於CSS原因或諸如此類),則可以使用ng-attr-有條件地應用屬性。 模板將更改為:

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

當然,您需要在鏈接函數中的范圍上公開attrs

link: function(scope, element, attrs, ngModel){
  scope.attrs = attrs;

  // etc...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM