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>
Есть ли другой способ избежать дублирования кода?
4 ответа
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>
демонстрация
Здесь приведены примеры использования следующих значений: true
, false
, undefined
, null
, 1
, 0
, а также ""
, Обратите внимание на то, как обычно-ложные значения могут привести к неожиданным результатам.
Спасибо Джейсон за ваше предложение. Я взял немного другой подход здесь. Так как я не хочу изменять переменную "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().
Не уверен, что это правильно или нет. Ищу мысли.
Невозможно напрямую добавить или удалить атрибут из элемента. Однако вы можете создать директиву, которая просто добавляет атрибут к элементу при выполнении условия. Я соединил что-то, что иллюстрирует подход.
Демо: 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
}
}
Я использовал другой подход, так как предыдущие примеры не работали для меня. Возможно, это связано с использованием пользовательских директив? Возможно, кто-то может это прояснить.
В моем конкретном примере я использую 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
// ...
}
}