22

シンプルな ui-datetime ディレクティブを作成しています。JavaScript の Date オブジェクトを _date、_hours、および _minutes の部分に分割します。_date は jquery ui datepicker、_hours および _minutes - 数値入力を使用します。

angular.module("ExperimentsModule", [])
    .directive("uiDatetime", function () {
    return {
        restrict: 'EA',
        replace: true,
        template: '<div class="ui-datetime">' +
            '<input type="text" ng-model="_date" class="date">' +
            '<input type="number" ng-model="_hours" min="0" max="23" class="hours">' +
            '<input type="number" ng-model="_minutes" min="0" max="59" class="minutes">' +
            '<br />Child datetime1: {{datetime1}}' +
            '</div>',
        require: 'ngModel',
        scope: true,
        link: function (scope, element, attrs, ngModelCtrl) {
            var elDate = element.find('input.date');

            ngModelCtrl.$render = function () {
                var date = new Date(ngModelCtrl.$viewValue);
                var fillNull = function (num) {
                    if (num < 10) return '0' + num;
                    return num;
                };
                scope._date = fillNull(date.getDate()) + '.' + fillNull(date.getMonth() + 1) + '.' + date.getFullYear();
                scope._hours = date.getHours();
                scope._minutes = date.getMinutes();
            };

            elDate.datepicker({
                dateFormat: 'dd.mm.yy',
                onSelect: function (value, picker) {
                    scope._date = value;
                    scope.$apply();
                }
            });

            var watchExpr = function () {
                var res = scope.$eval('_date').split('.');
                if (res.length == 3) return new Date(res[2], res[1] - 1, res[0], scope.$eval('_hours'), scope.$eval('_minutes'));
                return 0;
            };
            scope.$watch(watchExpr, function (newValue) {
                ngModelCtrl.$setViewValue(newValue);
            }, true);
        }
    };
});

function TestController($scope) {
    $scope.datetime1 = new Date();
}

jsfiddle

github: https://github.com/andreev-artem/angular_experiments/tree/master/ui-datetime

私の知る限り、新しいコンポーネントを作成するときのベスト プラクティスは、分離スコープを使用することです。

分離スコープを使用しようとすると、何も機能しません。ngModel.$viewValue === 未定義。

新しいスコープを使用しようとしたとき (私の例では、あまり良いバリアントではありません) - ngModel は、新しく作成されたスコープの値を使用します。

もちろん、分離されたスコープでディレクティブを作成し、「=式」( example ) を介して ngModel 値を操作できます。しかし、ngModelController を使用する方が良い方法だと思います。

私の質問:

  1. 分離スコープで ngModelController を使用できますか?
  2. 不可能な場合、そのようなコンポーネントを作成するのに適したソリューションはどれですか?
4

4 に答える 4

2

ディレクティブを ngModel よりも高い優先度で実行し、分離されたスコープのモデル バインディングを修正します。ngRepeat のような優先度の高いテンプレート操作の後、ngModel が使用するデフォルトの 0 の前に、入力ディレクティブと同じレベルである「100」の優先度を選択しました。

コード例は次のとおりです。

myDirective = function() {
  return {
    compile: function(tElement, tAttrs, transclude) {
      // Correct ngModel for isolate scope
      if (tAttrs.ngModel) {
        tAttrs.$set('model', tAttrs.ngModel, false);
        tAttrs.$set('ngModel', 'model', false);
      }

      return {
        post: function(scope, iElement, iAttrs, controller) {
          // Optionally hook up formatters and parsers
          controller.$formatters.push(function(value) {
             // ...
          })

          // Render
          return controller.$render = function() {
            if (!controller.$viewValue) {
              return;
            }
            angular.extend(scope, controller.$viewValue);
          };
        }
      };
    },
    priority: 100,
    require: '^ngModel',
    scope: {
      model: '='
    },
  };
}

コンパイル中に、ディレクティブは ngModel 属性が存在するかどうかをチェックします。このチェックは、Angular のAttributesを使用して正規化された値に対して機能します。属性が存在する場合、「モデル」(「ngModel」ではなく) に置き換えられます。これは、Isolate にデータ バインドされた名前です。ただし、Angular がデータ バインディングを実行できるように、属性も作成する必要があります。どちらの属性も (オプションで) falseDOM を変更しないパラメータで変更できます。

于 2012-12-12T09:12:01.133 に答える
0

これのバージョンを試してください:

.directive('myDir', function() {
    return {
        restrict: 'EA',
        scope:    {
                    YYY: '=ngModel'
                  },
        require:  'ngModel',
        replace:  true,
        template: function render(element, attrs) {
            var type = attrs.type || 'text';
            var required = attrs.hasOwnProperty('required') ? " required='required'" : "";
            return "<input ng-model='YYY' type="' + type + '" + required + ' />';
                  }
    };
});
于 2013-07-01T21:39:49.823 に答える