如何创建一个与表单验证一起使用的角度输入指令

时间:2014-09-10 02:20:37

标签: angularjs angularjs-directive

如何创建一个角度指令,在表单中添加输入,但也可以使用表单验证。

例如,以下指令创建了一个文本输入:

    var template = '\
<div class="control-group" ng-class="{ \'error\': {{formName}}[\'{{fieldName}}\'].$invalid}">\
    <label for="{{formName}}-{{fieldName}} class="control-label">{{label}}</label>\
    <div class="controls">\
        <input id="{{formName}}-{{fieldName}}" name="{{fieldName}}" type="text" ng-model="model" />\
    </div>\
</div>\
';

angular

    .module('common')

    .directive('formTextField', ['$compile', function ($compile) {
        return {
            replace: true,
            restrict: 'E',
            scope: {
                model: '=iwModel',
                formName: '@iwFormName',
                fieldName: '@iwFieldName',
                label: '@iwLabel'
            },
            transclude: false,
            template: template
        };
    }])

;

但是输入未添加到表单变量($ scope.formName)。我已经能够通过使用以下stackoverflow问题Angularjs: form validation and input directive中的dynamicName指令来解决这个问题,但是ng-class仍然无法工作。


更新

它现在似乎正在工作,但感觉就像一个黑客。我认为我需要范围来获取表单和字段名称,但是我可以直接从属性中读取它。这样做会在控制器范围形式变量中显示该字段。但是ng-class属性不适用。解决这个问题的唯一方法是在范围可用后再次添加html元素。

jsFiddle here

    var template = '\
<div class="control-group">\
    <label class="control-label"></label>\
    <div class="controls">\
        <input class="input-xlarge" type="text" />\
    </div>\
</div>\
';

angular

    .module('common')

    .directive('formTextField', ['$compile', function ($compile) {
        return {
            replace: true,
            restrict: 'E',
            scope: false,
            compile: function compile(tElement, tAttrs, transclude) {
                var elem = $(template);
                var formName = tAttrs.iwFormName;
                var fieldName = tAttrs.iwFieldName;
                var label = tAttrs.iwLabel;
                var model = tAttrs.iwModel;
                elem.attr('ng-class', '{ \'error\': ' + formName + '[\'' + fieldName + '\'].$invalid }');
                elem.find('label').attr('for', formName + '-' + fieldName);
                elem.find('label').html(label);
                elem.find('input').attr('id', formName + '-' + fieldName);
                elem.find('input').attr('name', fieldName);
                elem.find('input').attr('ng-model', model);

                // This one is required so that angular adds the input to the controllers form scope variable
                tElement.replaceWith(elem);

                return {
                    pre: function preLink(scope, iElement, iAttrs, controller) {
                        // This one is required for ng-class to apply correctly
                        elem.replaceWith($compile(elem)(scope));
                    }
                };

            }
        };
    }])

;

1 个答案:

答案 0 :(得分:1)

当我做这样的事情时,我使用指令compile函数来构建我的html,然后再进行处理。例如:

myApp.directive('specialInput', ['$compile', function($compile){
    return {
        // create child scope for control
        scope: true,
        compile: function(elem, attrs) {
            // use this area to build your desired dom object tree using angular.element (eg:)
            var input = angular.element('<input/>');

            // Once you have built and setup your html, replace the provided directive element
            elem.replaceWith(input);

            // Also note, that if you need the regular link function, 
            // you can return one from here like so (although optional)
            return function(scope, elem, attrs) {
                // do link function stuff here
            };
        }
    };
}]);