it-roy-ru.com

AngularJS - Использовать директиву атрибута условно

Я использую "перетаскиваемую" директиву для поддержки перетаскивания изображения. Однако, согласно роли пользователя, мне нужно отключить перетаскивание изображений для определенных групп пользователей. Я использовал следующий код.

<!--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> 

Метод dragSupported находится в области действия шаблона и возвращает true или false. Я не хочу создавать два больших дублирующих элемента <li>, используя ng-if для каждого значения, возвращаемого функцией dragSupported(). Другими словами, я не ищу следующий подход для решения этой проблемы.

<!--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>

Есть ли другой подход, чтобы избежать дублирования кода?

53
joy

ng-attr-<attrName>

Поддержка условного объявления атрибута HTML включена в Angular как директива с динамическим названием ng-attr-<attrName>.

Официальные документы для ng-attr

Пример

В вашем случае код может выглядеть так:

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

Демонстрация

JSFiddle

Здесь приведены примеры использования следующих значений: true, false, undefined, null, 1, 0 и "". Обратите внимание, как обычно-ложные значения могут привести к неожиданным результатам.

55
Walter Roman

Спасибо Джейсон за ваше предложение. Я взял немного другой подход здесь. Так как я не хочу изменять переменную "scope", поэтому я использовал "attrs", чтобы проверить, разрешено ли перетаскивание. Ниже приведен подход I, который пока кажется хорошим. 

Код директивы:

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

        }
    }
});

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>

Контроллер имеет реализацию userHasPrivilege ().

Не уверен, что это правильно или нет. Ищу мысли. 

4
joy

Невозможно напрямую добавить или удалить атрибут из элемента. Однако вы можете создать директиву, которая просто добавляет атрибут к элементу при выполнении условия. Я соединил что-то, что иллюстрирует подход.

Демо: http://jsfiddle.net/VQfcP/31/

Директива

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>

Контроллер

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

Я использовал другой подход, так как предыдущие примеры не работали для меня. Возможно, это связано с использованием пользовательских директив? Возможно, кто-то может это прояснить.

В моем конкретном примере я использую UI-Grid, но не все UI-Grid должны использовать нумерацию страниц. Я передаю атрибут paginated и затем $ compile директиву, основанную на true/false. Кажется довольно грубым, но, надеюсь, это может подтолкнуть людей в позитивном направлении.

HTML

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

Директива

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