2

I am creating a directive that is basically used as an <input> but has some special functionality:

   app.directive('skInput', function(){
        return {
            restrict: 'A',
            replace:true,
            template: '<div style="display:inline-block">\
                        <span ng-show="disabled">{{model}}</span>\
                        <input ng-hide="disabled" placeholder="{{placeholder}}" type="text" class="sk-input" ng-model="model" stop-event ng-required="isRequired"/>\
                       </div>',
            require: ['ngModel'],
            scope:{
                'width':'@',
                disabled: '=ngDisabled',
                model: '=ngModel',
                placeholder: '@'
            },
            link: function(scope, elem, attrs){
                if(angular.isDefined(scope.width)){
                    elem.find('input').css('width', scope.width);
                }

                if(angular.isDefined(attrs.required)){
                    scope.isRequired = true;
                }else{
                    scope.isRequired = false;
                }
            }
        }
    });

The problem is that I want to treat this directive like an input which may include a number of directives or HTML5 attributes like placeholder, ng-pattern, required, etc on them. However, I have to wire up the directives' attributes to the underlying input manually like you see.

Is there a way to tell Angular to put the attributes on the directive onto the <input> element rather than the <div> element? That way I can do something like <span sk-input ng-pattern="\regex\"></span> and it would automatically produce

<div>
    <span ng-show="disabled"></span>
    <input ng-pattern="\regex\" />
</div>

Instead of

<div ng-pattern="\regex\">
    <span ng-show="disabled"></span>
    <input />
</div>
codeepic
  • 3,723
  • 7
  • 36
  • 57
Matt Hintzke
  • 7,744
  • 16
  • 55
  • 113

1 Answers1

0

I think you are stuck doing it by hand, although there may be easier ways to do it (you might look at using a template function instead of a string).

How angular merges attributes using replace: true is internal and actually something they are deprecating. Here is a related question.

The template function gets passed the original element and attributes.

template: function(elem, attr) {
    var input = angular.element('<div><input></input></div>');
    for(var a in attr) {
        //optional if statement for whitelist/blacklist, etc.
        input.children().attr(a, attr[a]);
    }
    return '<div style="display:inline-block">\
                <span ng-show="disabled">{{model}}</span>' +
                input.innerHTML +
           '</div>'
    //build up your template here 
}

Doing it this way may even allow you to get away without using an isolated scope (which would make your directive more inline with the other ng- directives).

Community
  • 1
  • 1
Joe Enzminger
  • 11,110
  • 3
  • 50
  • 75