简体   繁体   中英

Variable directive name in angular

I'm sure this has been asked before, but it's kind of hard to put into a question and, therefore, is also hard to search for...

A piece of my app uses one of several third-party directives. The directives I'm messing with, at the moment, are those in the xeditable lib, but this question isn't just about that lib, as I've come across this need before.

My code, currently, looks something like the following:

<div ng-switch on="editTypeNeeded">
    <div ng-switch-when="textarea" editable-textarea="myVar" onbeforesave="doBeforeSaveStuff($data)" class="whatever" ng-class="whatever2()" ng-mouseover="doStuff()" some-other-directive="doMoreStuff()">
        {{myvar}}
        ...
        and other stuff
    </div>
    <div ng-switch-when="textfield" editable-text="myVar" onbeforesave="doBeforeSaveStuff($data)" class="whatever" ng-class="whatever2()" ng-mouseover="doStuff()" some-other-directive="doMoreStuff()">
        {{myvar}}
        ...
        and other stuff
    </div>
    <div ng-switch-when="checkbox" editable-checkbox="myVar" onbeforesave="doBeforeSaveStuff($data)" class="whatever" ng-class="whatever2()" ng-mouseover="doStuff()" some-other-directive="doMoreStuff()">
        {{myvar}}
        ...
        and other stuff
    </div>
    <div ng-switch-when="date" editable-bsdate="myVar" onbeforesave="doBeforeSaveStuff($data)" class="whatever" ng-class="whatever2()" ng-mouseover="doStuff()" some-other-directive="doMoreStuff()">
        {{myvar}}
        ...
        and other stuff
    </div>
    ...
    etc...
</div>

That's a TON of code duplication when the only thing that changes between each switch option is "editable-textarea", "editable-text", etc.

What I would like is to replace all of the above with something like this:

<div {{directiveName}}="myVar" onbeforesave="doBeforeSaveStuff($data)" class="whatever" ng-class="whatever2()" ng-mouseover="doStuff()" some-other-directive="doMoreStuff()">
    {{myvar}}
    ...
    and other stuff
</div>

which, obviously, doesn't work, but there's got to be a way to do something like that...


Update:

I ended up using the selected answer, but with a slight modification to allow for both a variable directive name AND a directive value. Like so:

.directive('useDirective', function ($compile) {
    return {
        restrict: 'A',
        link: function (scope, elem, attrs) {
            attrs.$observe('useDirective', function(directiveNameAndValue) {
                if (directiveNameAndValue) {
                    var nameAndValue = directiveNameAndValue.split('='),
                        dirName = nameAndValue[0],
                        value = nameAndValue[1] || '';
                    elem.attr(dirName, value);
                    elem.removeAttr('use-directive');
                    $compile(elem)(scope);
                }
            });
        }
    };
});

And I use it like this:

<div use-directive="{{getDirectiveType(value)}}=value" class="pointer" onbeforesave="notifyOfChange($data)">{{value}}</div>

Plunker example: http://plnkr.co/edit/JK5TkFKA2HutGJOrMo8a?p=preview


Update 2:
I've found that the above technique doesn't seem to play nicely with the angular-animate.js lib. It causes that lib to kick up the following error a bunch of times:

 TypeError: Cannot read property 'parentNode' of undefined
     at angular-animate.js:1203
     at angular-animate.js:539
     at n.$digest (angular.js:14358)
     at n.$apply (angular.js:14571)
     at angular.js:16308
     at e (angular.js:4924)
     at angular.js:5312

though, the page still seems to work fine.

You can create a directive to-rule-them-all:

<div lord-of-the-directives="{{directiveName}}">

Which would be like

module.directive('lordOfTheDirectives', function ($compile) {
  return {
    restrict: 'A',
    link: function (scope, elem, attrs) {
      attrs.$observe('lordOfTheDirectives', function(dirName) {
        if (dirName) {
          elem.append('<div ' + dirName + '>');
          $compile(elem)(scope);
        }
      });
    }
  };
});

(not tested but that's the idea)

Update by request in comment, to keep the element as is (with its classes and stuff):

module.directive('lordOfTheDirectives', function ($compile) {
  return {
    restrict: 'A',
    link: function (scope, elem, attrs) {
      attrs.$observe('lordOfTheDirectives', function (dirName) {
        if (dirName) {
          elem.attr(dirName, '');
          elem.removeAttr('lord-of-the-directives');
          $compile(elem)(scope);
        }
      });
    }
  };
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM