2015-05-07 5 views
16

Gibt es eine geradlinige, einfache Art und Weise das zu tun folgende -Bedingtes Attribut Winkel Richtlinie zu einem Element hinzufügen

<div class="my-class" my-custom-directive="{{evaluate expression}}"></div> 

Damit Winkel wird nicht hinzufügen, die Richtlinie, wenn der Ausdruck true ausgewertet wird ?

Edit:

Die Richtlinie ein Attribut sein muss, so bitte keine Lösungen wie ng-if mit restrict: 'E',
ng-class mit restrict: 'C' oder ng-attr - die nicht mit benutzerdefinierten Richtlinien nicht funktioniert.

Antwort

4

Dies ist möglich, indem Sie eine Direktive mit einer hohen Priorität und terminal: true erstellen. Dann können Sie mit den Elementattributen herumspielen (hinzufügen oder entfernen) und dann das Element neu kompilieren, um die Anweisungen laufen zu lassen. Hier

ist das Beispiel als zupfen: http://plnkr.co/edit/DemVGr?p=info

Ändern Sie den Ausdruck in der „Richtlinie-if“ zu halten Attribut/entfernen „Logger“ Richtlinie.

Wenn der Ausdruck für ein Attribut false ergibt, wird es entfernt.

<div directive-if="{'logger': 'myValue == 1'}" 
    logger="testValue"> 
    <p>"logger" directive exists? <strong>{{logger}}</strong></p> 
</div> 

Hier ist die Umsetzung der Richtlinie.

Mit ein paar kleineren Feinabstimmungen können Sie dies umtauschen zu hinzufügen Direktiven, anstatt sie zu entfernen, wenn das ist, was Sie bevorzugen würden.

/** 
* The "directiveIf" directive allows other directives 
* to be dynamically removed from this element. 
* 
* Any number of directives can be controlled with the object 
* passed in the "directive-if" attribute on this element: 
* 
* {'attributeName': 'expression'[, 'attribute': 'expression']} 
* 
* If `expression` evaluates to `false` then `attributeName` 
* will be removed from this element. 
* 
* Usage: 
* 
*   <any directive-if="{'myDirective': 'expression'}" 
*     my-directive> 
*   </any> 
* 
*/ 
directive('directiveIf', ['$compile', function($compile) { 

    // Error handling. 
    var compileGuard = 0; 
    // End of error handling. 

    return { 

     // Set a high priority so we run before other directives. 
     priority: 100, 
     // Set terminal to true to stop other directives from running. 
     terminal: true, 

     compile: function() { 
      return { 
       pre: function(scope, element, attr) { 

        // Error handling. 
        // 
        // Make sure we don't go into an infinite 
        // compile loop if something goes wrong. 
        compileGuard++; 
        if (compileGuard >= 10) { 
         console.log('directiveIf: infinite compile loop!'); 
         return; 
        } 
        // End of error handling. 


        // Get the set of directives to apply. 
        var directives = scope.$eval(attr.directiveIf); 
        angular.forEach(directives, function(expr, directive) { 
         // Evaluate each directive expression and remove 
         // the directive attribute if the expression evaluates 
         // to `false`. 
         var result = scope.$eval(expr); 
         if (result === false) { 
          // Set the attribute to `null` to remove the attribute. 
          // 
          // See: https://docs.angularjs.org/api/ng/type/$compile.directive.Attributes#$set 
          attr.$set('logger', null) 
         } 
        }); 


        // Remove our own directive before compiling 
        // to avoid infinite compile loops. 
        attr.$set('directiveIf', null); 

        // Recompile the element so the remaining directives 
        // can be invoked. 
        var result = $compile(element)(scope); 


        // Error handling. 
        // 
        // Reset the compileGuard after compilation 
        // (otherwise we can't use this directive multiple times). 
        // 
        // It should be safe to reset here because we will 
        // only reach this code *after* the `$compile()` 
        // call above has returned. 
        compileGuard = 0; 

       } 
      }; 

     } 
    }; 
}]); 
+0

Wenn Sie das konfigurieren, wenn Sie die Direktive mit Ausdruckswerten anstelle von Strings wie diesem konfigurieren "directive-if =" {'logger': myValue == 1} "' (beachte, dass 'myValue == 1' ein Ausdruck ist und keine Zeichenfolge dort), dann brauchen Sie nicht das zweite 'scope. $ eval (expr)' innerhalb der Schleife. –

2

@Sly_cardinal richtig ist, nutzte seinen Code, musste aber ein paar Anpassungen vornehmen:

(function() { 

angular.module('MyModule').directive('directiveIf', function ($compile) { 

    // Error handling. 
    var compileGuard = 0; 
    // End of error handling. 

    return { 

     // Set a high priority so we run before other directives. 
     priority: 100, 
     // Set terminal to true to stop other directives from running. 
     terminal: true, 

     compile: function() { 
      return { 
       pre: function(scope, element, attr) { 

        // Error handling. 
        // Make sure we don't go into an infinite 
        // compile loop if something goes wrong. 
        compileGuard++; 
        if (compileGuard >= 10) { 
         console.log('directiveIf: infinite compile loop!'); 
         return; 
        } 


        // Get the set of directives to apply. 
        var directives = scope.$eval(attr.directiveIf); 

        for (var key in directives) { 
         if (directives.hasOwnProperty(key)) { 

          // if the direcitve expression is truthy 
          if (directives[key]) { 
           attr.$set(key, true); 
          } else { 
           attr.$set(key, null); 
          } 
         } 
        } 

        // Remove our own directive before compiling 
        // to avoid infinite compile loops. 
        attr.$set('directiveIf', null); 

        // Recompile the element so the remaining directives 
        // can be invoked. 
        var result = $compile(element)(scope); 


        // Error handling. 
        // 
        // Reset the compileGuard after compilation 
        // (otherwise we can't use this directive multiple times). 
        // 
        // It should be safe to reset here because we will 
        // only reach this code *after* the `$compile()` 
        // call above has returned. 
        compileGuard = 0; 

       } 
      }; 

     } 
    }; 
}); 

})(); 
+0

Danke, Während dieser Code funktionieren könnte (weiß nicht, nicht überprüft), würde ich kaum das "einfach" oder "einfach" nennen. Es sieht sehr riskant und fehleranfällig aus (Schau dir nur die Anzahl der 'Error handlind' Kommentare an) und ich bin kein kantiger Experte genug, um die Konsequenzen zu kennen, die es auf meiner App haben wird. – Daniel

0

Ein weiterer Ansatz ist in zwei Versionen Code erstellen - eine Verabschiedung der Richtlinie erforderlich ist, und eine andere, wenn es ist nicht. Und zeige mit ng-if/ng-show den einen oder anderen an. Doppelter Code kann in Vorlagen verschoben werden, und diese können eingeschlossen werden.

Verwandte Themen