将属性从自定义指令复制到输入



我有一个自定义的driactive,它用div包装输入并添加一个标签。

<my-input label="My Label" name="myname" ng-model="mymodel" ng-pattern="/^[a-z]+$/">

我想选择性地使用所有可能的角度指令进行输入,如ng模式、ng最小长度等。现在看起来是这样的:

app.directive('myInput',[function () {
    return {
        restrict: "E",
        replace: true,
        scope: {
            ngModel: '=',
            name: '@',
            ngMinlength: '=',
            ngMaxlength: '=',
            ngPattern: '@',                
            label: '@'                
        },
        compile: function(element, attrs){
            if(!_.isUndefined(attrs['ngMinlength'])) {
                element.find('input').attr('ng-minlength', 'ngMinlength');
            }
            if(!_.isUndefined(attrs['ngMaxlength'])) {
                element.find('input').attr('ng-maxlength', 'ngMaxlength');
            }                
            if(!_.isUndefined(attrs['ngPattern'])) {
                element.find('input').attr('ng-pattern', attrs['ngPattern']);
            }               

        },
        template: '<div class="form-group">'
        + '<label>{{ label | translate }}</label>'
        + '<div>'
        + '<input type="text" class="form-control input-sm" name="{{ name }}" ng-model="ngModel">'           
        + '</div></div>'
    };
}]);

问题是,我希望使用与输入中的ng模式完全相同的ng模式,所以我希望在ng模式中使用regexp,并使用模式($scope.mypattern = /^[a-z]+$/; ... ng-pattern="mypattern")的范围变量。如何管理?

我想两者都工作:

1.

<my-input label="My Label" name="myname" ng-model="mymodel" ng-pattern="/^[a-z]+$/">

2.

$scope.myPattern = /^[a-z]+$/
...
<my-input label="My Label" name="myname" ng-model="mymodel" ng-pattern="myPattern">

我有三个答案。

  1. 通常,不建议同时支持模型属性和直接支持String。这种情况由指令作用域中的=声明来处理,如果要传递String,可以使用简单的引号。例如,ngBind的工作方式如下:ng-bind="someModel"ng-bind="'some string'"

  2. 如果真的想要,可以尝试解析表达式。如果它是可解析的,就意味着它是一个范围模型。否则,它很可能是一个字符串。请参阅下面代码片段中的工作示例:

angular.module('test', [])
.controller('test', function($scope) {
  $scope.model = "string from scope model";
})
.directive('turlututu', function($parse) {
 return {
   restrict: 'E',
   scope: {},
   template: '<div class="tu">{{content}}</div>',
   link: function(scope, elem, attrs) {
     try {
       scope.content = $parse(attrs.text)(scope.$parent);
     } catch(err) {
     } finally {
       if (!scope.content) {
         scope.content = attrs.text;
       }
     }
   }
 };
});
body { font-family: monospace; }
.tu { padding: 10px; margin: 10px; background: #f5f5f5; border-bottom: 2px solid #e5e5e5; }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="test">
  
  <turlututu text="hardcoded string"></turlututu>
  <turlututu text="model"></turlututu>
  
</div>

  1. 在ngPattern的情况下,因为代码中的好奇心总是会帮助你,你可以在Angular的源代码中看到他们测试属性的第一个字符:如果是/,它被认为是regexp,否则就是范围模型(见下面的例子)

angular.module('test', [])
.controller('test', function($scope) {
  $scope.model = /[a-z]*/;
})
.directive('turlututu', function($parse) {
 return {
   restrict: 'E',
   scope: {},
   template: '<div class="tu">{{content}}</div>',
   link: function(scope, elem, attrs) {
     if (attrs.regexp.charAt(0) === '/') {
       scope.reg = new RegExp( attrs.regexp.substring(1, attrs.regexp.length-1) );
     } else {     
       scope.reg = new RegExp( $parse(attrs.regexp)(scope.$parent) );
     }
     
     scope.content = scope.reg.toString()
   }
 };
});
body { font-family: monospace; }
.tu { padding: 10px; margin: 10px; background: #f5f5f5; border-bottom: 2px solid #e5e5e5; }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="test">
  
  <turlututu regexp="/[0-9]*/"></turlututu>
  <turlututu regexp="model"></turlututu>
  
</div>

我也面临着同样的问题——需要将我的自定义装饰输入视为常规输入元素。我也从孤立的范围开始,但最终认为它不够灵活。必须添加我可能需要的每一个属性会很快变老。所以我想出了下面的解决方案。不确定它是否是正确的/规范的角度方式,但对我有效。

其想法是根据指令的属性构建一个"视图模型"对象,并将其提供给$interpole。视图模型中未使用的任何属性被插入到实际<input/>元素。它不创建任何新的作用域,只是将其放在当前作用域中。此指令使用的是使用lodash-kebabCase:https://lodash.com/docs/4.17.4#kebabCase

如果你不想包含lodash,你可以使用Angular本身的snake_case函数,但它不是通过他们的API公开的,所以你需要将它复制到代码中的某个地方。

controlsModule.directive('myTextbox', ['$interpolate',function ($interpolate) {
    var tmpl =
    '<div class="form-group" title="{{hint}}"> 
                    <label class="{{labelClass}} control-label">{{label}}</label> 
                    <input type="{{type}}" class="form-control input-group-sm" {{attributesToCopy}} /> 
            </div>';
    var interpolate = $interpolate(tmpl);
    function buildModel(attrs) {
        if (!attrs.placeholder) attrs.placeholder = attrs.label;
        if (!attrs.labelClass) attrs.labelClass = "col-sm-3";
        if (!attrs.type) attrs.type = "text";
        return {
            label: attrs.label,
            labelClass: attrs.labelClass,
            type: attrs.type
        };
    }
    function template(tElement, tAttrs) {
        var model = buildModel(tAttrs);
        var atc = "";
        for (var attr in tAttrs) {
            if (!(attr.lastIndexOf('$', 0) === 0) && tAttrs.hasOwnProperty(attr) && !model[attr]) {
                    atc += ' ' + _.kebabCase(attr); //converts to snake_case , uses lodash/uderscore
                    if (tAttrs[attr] !== attr) {
                        atc += '="' + tAttrs[attr] + '" ';
                }
            }
        }
        model.attributesToCopy = atc;
        return interpolate(model);
    }
    return {
        restrict: 'EA',
        template: template
    };
}]);

用法:

    <my-textbox type="number" ng-model="foo" ng-min="0" ng-max="5" required></my-textbox>

最新更新