How to create a angular input directive that works

2019-07-20 08:11发布

How do I create an angular directive that adds a input in a form but also works with form validation.

For instance the following directive creates a text input:

    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
        };
    }])

;

However the input is not added to the form variable ($scope.formName). I've been able to work around that by using the dynamicName directive from the following stackoverflow question Angularjs: form validation and input directive but ng-class will still not work.


Update

It now seems to be working but it feels like a hack. I thought I needed the scope to grab the form and field names however I can read that directly from the attributes. Doing this shows the field in the controllers scope form variable. However the ng-class attribute does not apply. The only way around this is to add the html element a second time once the scope is available.

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条回答
淡お忘
2楼-- · 2019-07-20 08:46

when I do something like this, I use the directive compile function to build my html prior to it being processed. For example:

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
            };
        }
    };
}]);
查看更多
登录 后发表回答