web-dev-qa-db-fra.com

AngularJS - Utilise la directive attribut conditionnellement

J'utilise la directive "draggable" pour prendre en charge le glissement des images. Cependant, en fonction du rôle de l'utilisateur, je dois désactiver le glissement des images pour certains groupes d'utilisateurs. J'ai utilisé le code suivant.

<!--draggable attribute is used as handle to make it draggable using jquery event-->           
<li  ng-repeat="template in templates" draggable id="{{template._id}}" type="template" class="template-box">            
<!-- Images and other fields are child of "li" tag which can be dragged.-->                    
</li> 

La méthode dragSupported est dans la portée du modèle et renvoie true ou false. Je ne veux pas créer deux gros éléments <li> en double en utilisant ng-if pour chaque valeur renvoyée par dragSupported(). En d'autres termes, je ne cherche pas l'approche suivante pour résoudre ce problème. 

<!--draggable attribute is used as handle to make it draggable using jquery event-->           
<li ng-if="dragSupported() ==true"  ng-repeat="template in templates" draggable id="{{template._id}}" type="template" class="template-box">            
<!-- Images and other fields are child of "li" tag which can be dragged.-->                    
</li>
<!--remove "draggable" directive as user doesn't have permission to drag file -->
<li ng-if="dragSupported() !=true"  ng-repeat="template in templates"  id="{{template._id}}" type="template" class="template-box">            
<!-- Images and other fields are child of "li" tag which can be dragged.-->                    
</li>

Existe-t-il une autre approche pour éviter la duplicité de code? 

53
joy

ng-attr-<attrName>

La prise en charge de la déclaration conditionnelle d'un attribut HTML est incluse dans Angular en tant que directive ng-attr-<attrName> portant un nom dynamique.

Documents officiels pour ng-attr

Exemple

Dans votre cas, le code pourrait ressembler à ceci:

<li
    id="{{template._id}}"
    class="template-box"
    type="template"
    ng-repeat="template in templates"
    ng-attr-draggable="dragSupported() === true"
></li>

Démo

JSFiddle

Cela contient des exemples d'utilisation des valeurs suivantes: true, false, undefined, null, 1, 0 et "". Notez à quel point les valeurs de falsey peuvent donner des résultats inattendus.

55
Walter Roman

Merci Jason pour votre suggestion. J'ai pris une approche peu différente ici. Puisque je ne veux pas changer la variable "scope", j'ai donc utilisé "attrs" pour vérifier si le glissement est autorisé ou non. Ce qui suit est une approche qui semble bonne jusqu'à présent. 

Code de la directive:

app.directive('draggable', function () {
    return {
        // A = attribute, E = Element, C = Class and M = HTML Comment
        restrict: 'A',
        replace:true,
        link: function (scope, element, attrs) {

            if(attrs.allowdrag =="true")
            {
                element.draggable({
                cursor: 'move',
                helper: 'clone',
                class:'drag-file'
                });
            }

        }
    }
});

Code HTML:

<ul> 
         <!--draggable attribute is used as handle to make it draggable using jquery event-->           
        <li  ng-repeat="template in templates" draggable allowdrag="{{userHasPrivilege()}}" >            
                <!--Ohter code part of li tag-->                   

        </li> 

</ul>

Le contrôleur exécute userHasPrivilege ().

Je ne sais pas si c'est correct ou pas. À la recherche de pensées. 

4
joy

Il n'y a aucun moyen d'ajouter ou de supprimer directement un attribut d'un élément. Cependant, vous pouvez créer une directive qui ajoute simplement l'attribut à l'élément lorsque la condition est remplie. J'ai mis en place quelque chose qui illustre l'approche.

Démo: http://jsfiddle.net/VQfcP/31/

Directive

myApp.directive('myDirective', function () {
  return {
    restrict: 'A',
    scope: {
        canDrag: '&'
    },
    link: function (scope, el, attrs, controller) {
        /*
$parent.$index is ugly, and it's due to the fact that the ng-repeat is being evaluated 
first, and then the directive is being applied to the result of the current iteration      
of the repeater.  You may be able to clean this by transcluding the repeat into the 
directive, but that may be an inappropriate separation of concerns. 
You will need to figure out the best way to handle this, if you want to use this approach.  
  */
        if (scope.canDrag&& scope.canDrag({idx: scope.$parent.$index})) {
            angular.element(el).attr("draggable", "draggable");
        }
    }
  };
});

HTML

<ul>
    <!-- same deal with $parent -->
    <li ng-repeat="x in [1, 2, 3, 4, 5]" my-directive="true" can-drag="checkPermissions(idx)">{{$parent.x}}</li>
</ul>

Manette

function Ctl($scope) {
   $scope.checkPermissions = function(idx) {
     // do whatever you need to check permissions
     // return true to add the attribute
   }
}
3
Jason

J'ai utilisé une approche différente, car les exemples précédents ne fonctionnaient pas pour moi. Peut-être que cela a à voir avec l'utilisation de directives personnalisées? Peut-être que quelqu'un peut clarifier cela.

Dans mon exemple particulier, j'utilise ui-grid, mais tous les ui-grids ne doivent pas utiliser la pagination. Je passe un attribut "paginated" puis $ compile la directive basée sur true/false. Cela semble assez brutal, mais j'espère que cela pourra pousser les gens dans une direction positive.

HTML

<sync-grid service="demand" paginated="true"></sync-grid>

Directif

angular
    .module('app.directives')
    .directive('syncGrid', ['$compile', SyncGrid]);

function SyncGrid($compile){
    var nonPaginatedTemplate = '' +
        '<div>' +
        '   <div ui-grid="gridOptions" class="grid"></div>' +
        '</div>';

    var paginatedTemplate = '' +
        '<div>' +
        '   <div ui-grid="gridOptions" class="grid" ui-grid-pagination></div>' +
        '</div>';


    return {
        link: link,
        restrict: 'E',
        replace: true
    };

    function link(scope, element, attrs) {

        var isPaginated = attrs['paginated'];

        var template = isPaginated ? paginatedTemplate : nonPaginatedTemplate;
        var linkFn = $compile(template);
        var content = linkFn(scope);
        element.append(content);

        // Continue with ui-grid initialization code
        // ...

    }
}
0
Will Lovett