我可以使用具有隔离范围的ng模型吗?

Art*_*eev 22 angularjs

我正在创建简单的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();
}
Run Code Online (Sandbox Code Playgroud)

jsfiddle

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

据我所知 - 创建新组件时的最佳做法是使用隔离范围.

当我尝试使用隔离范围时 - 没有任何作用.ngModel.$ viewValue === undefined.

当我尝试使用新范围时(我的例子,不是那么好的变体imho) - ngModel在新创建的范围上使用值.

当然,我可以使用隔离范围创建指令,并通过"= expression"(示例)使用ngModel值.但我认为使用ngModelController是一种更好的做法.

我的问题:

  1. 我可以使用具有隔离范围的ngModelController吗?
  2. 如果不可能哪种解决方案更适合创建这样的组件?

Mar*_*cok 18

scope: truescope: { datetime1: '=ngModel'}你的第一个小提琴替换似乎工作得很好 - 小提琴.不幸的是,你的"示例"小提琴的链接被打破了,所以我不确定你在那里尝试了什么.

因此,似乎ngModelController可以与隔离范围一起使用.

这是一个较小的小提琴,它使用HTML /视图中的ng-model,一个隔离范围,以及链接函数中的$ setViewValue: 小提琴.

更新:我刚刚发现了一些相当有趣的东西:如果隔离范围属性被赋予了不同的名称 - 例如,说dt1而不是datetime1 scope: { dt1: '=ngModel'}- 它就不再有用了!我猜测,当我们require: 'ngModel',ngModelController使用HTML /视图中的名称(即ng-model属性值)在隔离范围上创建属性.因此,如果我们在对象哈希中指定相同的名称,那么一切都很好.但是如果我们指定一个不同的名称,那么新的scope属性(例如,dt1)就不会与我们需要的ngModelController相关联.

这是一个更新的小提琴.


til*_*ovi 2

使您的指令以比 ngModel 更高的优先级运行,并更正隔离范围的模型绑定。我选择了优先级“100”,它与输入指令的级别相同,在像 ngRepeat 这样的高优先级模板操作之后,但在默认值 0 之前,这是 ngModel 使用的。

这是示例代码:

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: '='
    },
  };
}
Run Code Online (Sandbox Code Playgroud)

在编译期间,该指令检查 ngModel 属性是否存在。此检查使用 Angular 的Attributes对标准化值进行检查。如果该属性存在,它将被替换为“model”(而不是“ngModel”),这是数据绑定到隔离中的名称。然而,我们还必须创建一个属性,以便 Angular 可以为我们执行数据绑定。这两个属性都可以(根据您的选择)使用false参数进行修改,从而使 DOM 保持不变。

  • 似乎是解决方法。但对于解决方法,我更喜欢 `scope: true` 和 `ng-model="someObj.someProp"` (2认同)