2

For my project, i'm currently developping custom form / inputs directive.

For example, I have the following directive :

angular.module('myApp').directive("textField", function() {
    return {
        restrict: 'E',
        replace: true,
        templateUrl : "/common/tpl/form/text-field.html",
        scope : {
            label   : "@",
            model   : "="
        }
    };
});

with the associated template :

<div class="form-group">
    <label for="{{fieldId}}" class="col-lg-2 control-label">{{label |translate}}</label>
    <div class="col-lg-10">
        <input type="text" class="form-control" id="{{fieldId}}" ng-model="model" placeholder="{{label|translate}}">
    </div>
</div>

I have many more custom fields ( date, select, double select, and so on... )

The usage is simple :

<text-field label="app.myLabel" model="myObj.myAttribute"></text-field>

The idea is to cleanup the main template by avoiding to verbosely add labels on every fields. Very common need i believe.

Now the problem :

Now I need to add custom validation to my input models.

I did a naive approach which was to create a validation directive :

directive('myValidation', function (){
    return {
        require: 'ngModel',
        link: function(scope, elem, attr, ngModel) {
            ngModel.$parsers.unshift(function (value) {
                // do some validation
                return value;
            });
        }
    };
});

and then to use it like this :

<text-field label="app.myLabel" model="myObj.myAttribute" myValidation="validationOptions"></text-field>

But of course this doesnt work, simple because the text-field directive which is replace=true "erases" the validation directive on it's element.

Can someone tell one what is the correct approach to do "custom input with presentation" directive, while allowing the validation part to be declared on the directive ( here text-field ) and used on the directive's input ?

Per example, is there a way to say "attributes on my element directive will be 'copied' to inside my directive ?"

aka :

<text-field label="app.myLabel" model="myObj.myAttribute" **myValidation="validationOptions"**></text-field>

would result in :

<div class="form-group">
        <label for="{{fieldId}}" class="col-lg-2 control-label">{{label |translate}}</label>
        <div class="col-lg-10">
            <input type="text" class="form-control" id="{{fieldId}}" ng-model="model" **myValidation="validationOptions"** placeholder="{{label|translate}}">
        </div>
    </div>

Or am I simply missing something ?

I would like to avoid using transclusion to resolve this issue, because this would oblige the form template to look like this :

<field label="myLabel">
     <input type="text" class="form-control" id="{{fieldId}}" ng-model="model" placeholder= {{label|translate}}">    
</field>

which is just uselessly verbose in my opinion. But i'm starting to ask myself if there really is another option ?

Maybe the trick can be done in the pre (or post ?) directve link function, where I would copy attributes/ directive from the text-field tag to it's child (input) tag ?

Could someone just light the way for me there ?

4

1 回答 1

3

你能试试这个:

  • 写一个validate指令。这将有一个控制器公开一个addValidationFunction(fn)和一个getValidationFunction()方法。

  • myValidation指令需要validate控制器并调用ctrl.addValidationFunction(myValidationImplementation)wheremyValidationImplementation是实现此特定指令的验证逻辑的函数。

  • 编写另一个指令,validateInner. 这将需要可选地validate来自其父级的控制器。该指令还需要ngModel控制器。如果它找到validate控制器,它会调用并使用iectrl.getValidationFunction()注册该函数:ngModel

    require: ["^?validate", "ngModel"],
    link: function(scope,el,attrs,ctrls) {
        if( ctrls[0] != null ) {
            var validationFn = ctrls[0].getValidationFunction();
            // register validationFn with ngModel = ctrls[1]
        }
        ...
    }
    
  • 在您的模板中textField

    <input validate-inner type="text" class="form-control" id="{{fieldId}}" ng-model="model" placeholder="{{label|translate}}">
    

用法:

<text-field label="app.myLabel" model="myObj.myAttribute"
    validate my-validation="validationOptions"></text-field>

注意 1:我不确定一个replace:true指令是否会擦除其他指令。如果是这样,这不是一致的行为。

注意 2:该myValidation指令被称为<xxx my-validation>(注意 camelCase → dash-case)。如果您上面的代码不是错字,那么这就是<text-field> 似乎擦除的原因myValidation

于 2013-10-10T09:34:00.850 回答