デフォルトオプションを使用したAngularJSディレクティブ


145

私はangularjsから始めて、いくつかの古いJQueryプラグインをAngularディレクティブに変換する作業をしています。(要素)ディレクティブのデフォルトオプションのセットを定義したいのですが、属性にオプション値を指定することでオーバーライドできます。

私は他の人がこれを行った方法を見回してきました、angular-uiライブラリではui.bootstrap.paginationが同様のことをしているようです。

最初に、すべてのデフォルトオプションが定数オブジェクトで定義されます。

.constant('paginationConfig', {
  itemsPerPage: 10,
  boundaryLinks: false,
  ...
})

次に、getAttributeValueユーティリティ関数がディレクティブコントローラにアタッチされます。

this.getAttributeValue = function(attribute, defaultValue, interpolate) {
    return (angular.isDefined(attribute) ?
            (interpolate ? $interpolate(attribute)($scope.$parent) :
                           $scope.$parent.$eval(attribute)) : defaultValue);
};

最後に、これはリンク関数で属性を読み込むために使用されます。

.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) {
    ...
    controller: 'PaginationController',
    link: function(scope, element, attrs, paginationCtrl) {
        var boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks,  config.boundaryLinks);
        var firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true);
        ...
    }
});

これは、デフォルト値のセットを置き換える必要があるため、標準としてはかなり複雑な設定のようです。これを行う一般的な方法は他にありますか?または、常にgetAttributeValueこのようなユーティリティ関数や解析オプションを定義するのは正常ですか?この共通のタスクに対して人々がどのような戦略を持っているかを知りたいです。

また、おまけとして、なぜこのinterpolateパラメーターが必要なのかはわかりません。

回答:


108

compile関数を使用できます-設定されていない場合は属性を読み取ります-デフォルト値を入力します。

.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) {
    ...
    controller: 'PaginationController',
    compile: function(element, attrs){
       if (!attrs.attrOne) { attrs.attrOne = 'default value'; }
       if (!attrs.attrTwo) { attrs.attrTwo = 42; }
    },
        ...
  }
});

1
ありがとう!では、なぜui.bootstrap.pagination物事がより複雑な方法で行われるのかについての考えはありますか?コンパイル機能を使用する場合、後で行われた属性の変更は反映されないだろうと考えていましたが、この段階ではデフォルトのみが設定されているため、これは正しくないようです。ここでいくつかのトレードオフが行われているはずだと思います。
ケンチャットフィールド

3
@KenChatfieldのcompile属性を読み取ることができません。属性を補間して、値(式を含む)を取得する必要があります。ただし、属性が空であるかどうかのみを確認する場合は、トレードオフなしで機能します(補間属性に式を含む文字列が含まれる前)。
OZ_ 2013

1
素晴らしい!明確な説明をありがとうございました。将来の読者のために、元の質問に接していますが、このui.bootstrap.pagination例での「補間」パラメーターの機能の説明について、この非常に有用な例を見つけました:jsfiddle.net/EGfgH
Ken Chatfield

その解決策をたくさんありがとう。linkオプションが必要な場合でも、オプションで関数を返すことができcompileます。ここにドキュメント
2015年

4
テンプレートから渡されるのと同じように、属性には値が必要です。配列feを渡す場合は、attributes.foo = '["one", "two", "three"]'代わりにattributes.foo = ["one", "two", "three"]
Dominik Ehrenberg

263

=?ディレクティブのスコープブロックでプロパティのフラグを使用します。

angular.module('myApp',[])
  .directive('myDirective', function(){
    return {
      template: 'hello {{name}}',
      scope: {
        // use the =? to denote the property as optional
        name: '=?'
      },
      controller: function($scope){
        // check if it was defined.  If not - set a default
        $scope.name = angular.isDefined($scope.name) ? $scope.name : 'default name';
      }
    }
  });

4
=?1.1.x以降で利用可能
Michael Radionov

34
あなたの属性が値としてtrueまたはfalse値として受け入れることができるなら、あなたは(私は思う)例えば$scope.hasName = angular.isDefined($scope.hasName) ? $scope.hasName : false;代わりに使いたいと思うでしょう。
ポールD.ウェイト2014

22
注:双方向のバインディングでのみ機能します。たとえば=?、一方向のバインディングでは機能しません@?
Justus Romijn 14

20
テンプレートでのみ実行することもできます:template: 'hello {{name || \ 'デフォルト名\'}} '
Vil

4
デフォルト値はコントローラまたはlink関数のどちらに設定する必要がありますか?私の理解に基づいて、の間に割り当てるlinkことは$scope.$apply()サイクルを回避する必要がありますね?
オーガスティンリーディンガー2015年

1

私はAngularJS v1.5.10を使用していpreLinkますが、コンパイル機能がデフォルトの属性値を設定するのに適していることがわかりました。

ただのリマインダー:

  • attrs常にまたは文字列のいずれかである生の DOM属性値を保持しundefinedます。
  • scope(とりわけ)を保持するDOMの属性値が解析さ設け単離スコープ仕様(に応じて=/ </ @/など)。

要約スニペット:

.directive('myCustomToggle', function () {
  return {
    restrict: 'E',
    replace: true,
    require: 'ngModel',
    transclude: true,
    scope: {
      ngModel: '=',
      ngModelOptions: '<?',
      ngTrueValue: '<?',
      ngFalseValue: '<?',
    },
    link: {
      pre: function preLink(scope, element, attrs, ctrl) {
        // defaults for optional attributes
        scope.ngTrueValue = attrs.ngTrueValue !== undefined
          ? scope.ngTrueValue
          : true;
        scope.ngFalseValue = attrs.ngFalseValue !== undefined
          ? scope.ngFalseValue
          : false;
        scope.ngModelOptions = attrs.ngModelOptions !== undefined
          ? scope.ngModelOptions
          : {};
      },
      post: function postLink(scope, element, attrs, ctrl) {
        ...
        function updateModel(disable) {
          // flip model value
          var newValue = disable
            ? scope.ngFalseValue
            : scope.ngTrueValue;
          // assign it to the view
          ctrl.$setViewValue(newValue);
          ctrl.$render();
        }
        ...
    },
    template: ...
  }
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.