1

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.

Partha Sarathi Ghosh
  • 10,936
  • 20
  • 59
  • 84
  • you can use **ng-click="dialogFun()"** and write a function **dialogFun** in which you add the confirmation pop-up class or change its css from hidden to block. – AndreaM16 Jan 13 '16 at 08:32
  • No. I have lots of button. Every button has some functionality with `ng-click`. I want to build this directive for easy integration. Because some of the buttons need this functionality and some do not. – Partha Sarathi Ghosh Jan 13 '16 at 09:16
  • Oh I see, then you should define an Attribute Directive which makes what I written before and just include it when you need it. I'll try to implement it when I'll be at home. – AndreaM16 Jan 13 '16 at 09:28
  • That is what I am trying. But not able to do. Please look at my plunker here https://plnkr.co/edit/GxNIq8jO6S7l2UkSyr3S?p=preview – Partha Sarathi Ghosh Jan 13 '16 at 09:31
  • what is the problem with your plnkr? – hansmaad Jan 18 '16 at 08:09
  • Firstly my event attribute is not ng click. So if i want to convert any other button I need to change ngclick to my popup click.. secondly it is not supporting inner html as button text. Like span inside the button. – Partha Sarathi Ghosh Jan 18 '16 at 08:18
  • I updated my answer to reuse the ngClick handelr and pass the confirm result to it. – hansmaad Jan 18 '16 at 09:02

3 Answers3

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

ibrahimb
  • 170
  • 1
  • 10
  • Nice. Superb. Exactly what I was looking for. Let me try on my workspace. You used $parse here. That is the magic. :) Thanks for the answer. – Partha Sarathi Ghosh Jan 18 '16 at 09:54
  • You can get a function from $parse service for any javascript sentence in string form. Then you can use this function to evaluate this sentence in any given scope and yes it is magical :) – ibrahimb Jan 19 '16 at 08:13
0

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/

hansmaad
  • 18,417
  • 9
  • 53
  • 94
0

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.

Community
  • 1
  • 1
valverde93
  • 1,698
  • 1
  • 11
  • 17