问题
I have a button directive as follows (Plunker is here):
<button type="button"
data-confirm-popup-btntext="Reject"
data-confirm-popup-text="Do you want to reject"
data-confirm-popup-header="Reject"
data-confirm-popup-click="reject(obj)"
class="btn btn-danger btn-xs"
data-ng-class="{disabled : disable}"
data-ng-if="show"></button>
I have data-confirm-popup-btntext
for button text. Which I do not want. I also do not want data-confirm-popup-click
. Rather I want to use ng-click
.
My concept is, there will be any button on any view. If I need to display a confirm dialog before processing I will add one attribute(directive) to that button and that directive will take care everything.
Also I am not able to add <span class'bootstrap-icon'></span> Reject
in current implementation.
So my desired outcome of the directive is as follows :
<button type="button"
data-confirm-popup-header="Reject"
data-confirm-popup-text="Do you want to reject"
<!--Above line two line will add confirm dialog functionality -->
data-ng-click="reject(obj)"
class="btn btn-danger btn-xs"
data-ng-class="{disabled : disable}"
data-ng-if="show"><span>Any HTML</span>Reject</button>
I tried trnsculation with replace false and true but not able to achieve this functionality.
回答1:
I used your plunker and changed app.js, removing from line 14 to the end and replacing this directive should get you to the point you want;
app.directive("confirmPopupText",confirmPopupText);
confirmPopupText.$inject = ['$uibModal', '$compile', '$parse'];
function confirmPopupText ( $modal, $compile, $parse){
var directive = {};
directive.restrict = 'A';
directive.link= function(scope, elem, attrs) {
// get reference of ngClick func
var model = $parse(attrs.ngClick);
// remove ngClick and handler func
elem.prop('ng-click', null).off('click');
elem.bind('click' , function(e) {
e.stopImmediatePropagation();
console.log('Clicked');
$modal.open({
template: '<div class="modal-header">'+attrs.confirmPopupHeader+'</div>'+'<div class="modal-body">'+attrs.confirmPopupText+'</div>'+'<div class="modal-footer">'+'<button class="btn btn-primary" data-ng-click="ok()">Yes</button>'+'<button class="btn btn-warning" data-ng-click="cancel()">No</button>'+'</div>',
controller: function($scope, $uibModalInstance) {
$scope.ok = function () {
$uibModalInstance.close();
// this line will invoke ngClick func from outer scope
model(scope);
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
}
});
});
};
return directive;
}
So that you can use the html like that;
<button type="button"
data-confirm-popup-header="Reject"
data-confirm-popup-text="Do you want to reject"
<!--confirmPopupText directive will add confirm dialog functionality -->
data-ng-click="reject(obj)"
class="btn btn-danger btn-xs"
data-ng-class="{disabled : disable}"
data-ng-if="show"><span>Any HTML</span>Reject</button>
Updated plunker link : https://plnkr.co/edit/Bmcqqe32Px25pFCf0Mus?p=preview
回答2:
Based on Erik Chen's answer, you can override or modify any service in AngularJS, including directive:
app.config(function($provide){
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
//$delegate is array of all ng-click directive
//in this case frist one is angular buildin ng-click
//so we remove it.
$delegate.shift();
return $delegate;
}]);
});
app.directive('ngClick', function($rootScope) {
return {
restrict: 'A',
priority: 100,
link: function($scope, element, attr) {
element.bind('click', function($event) {
// emit event to manage modal if 'popup' attr is exist
if (attr.hasOwnProperty('popup')) {
// and pass arguments
$scope.$emit('popup-click', { $scope, element, attr });
} else {
// else just execute default 'ng-click' handler
$scope.$apply(attr.ngClick)
}
})
}
}
})
And manage popups in a factory:
app.factory('popupService', function($rootScope) {
$rootScope.$on('popup-click', function(e, args) {
// click with popup attr observer
// there needs to be your code to manage modal
// you can pass any params for example as 'popup-title="i am a title"' and get it there with 'args.attr'
if (confirm(args.attr.popupText || 'Default text')) {
args.$scope.$apply(args.attr.ngClick)
} else {
// nothing to do
}
});
return {};
});
I've created JSFiddle to show full example.
Hope, it will help you.
回答3:
In the link
function you can un-/register event handlers and perform any DOM manipulation. So you can add the confirm functionality and the button contents and classes here. To reuse the ng-click handler unbind the 'click' event before you bind your own handler.
return {
priority: 1,
compile: function(elem, attr) {
var text = attr.confirmPopupText;
var callback = $parse(attr.ngClick);
elem.html('<span>Any HTML</span>Reject');
elem.addClass('btn btn-danger btn-xs');
return function(scope, elem, attr) {
elem.unbind('click').bind('click', function(event) {
var result = $window.confirm(text); // use $modal here instead
callback(scope, {result: result, $event : event});
scope.$apply(scope.ngClick);
});
}
}
}
You can use this directive as
<div ng-app="app" ng-controller="Main as view">
<button data-confirm-popup-text="Do you want to reject"
confirm-button ng-click="view.onConfirm($event, result)">
</button>
</div>
https://jsfiddle.net/9huoL1wL/4/
来源:https://stackoverflow.com/questions/34759384/custom-directive-button-with-confirm-popup