10

I have created a directive using bootstrap custom popover. That works taking an input from a user for a group name and it has two buttons for apply that value to model and show that value on tooltip and a button to close the popover. I am using popover java script events , Problem is that single popover works perfectly but when I open another one this popover not closing itself. Need help in closing other popovers while one is open. Here is the plnk showing the directive.

Here is the code

var app = angular.module('myApp',[]);
app.directive('customEditPopover', function () {
        return {
            restrict: 'A',
            template: '<span><i class="fa fa-tags" aria-hidden="true"></i></span>',
            scope: {
                'myModel': '=',
            },
            link: function (scope, el, attrs) {
                scope.label = attrs.popoverLabel;
                var btnsave = '#' + attrs.popoverSave;
                var btncancel = '#' + attrs.popoverCancel;
                var index = attrs.index;
                $(el).tooltip({
                    title: '' + (scope.myModel == undefined) ? "" : scope.myModel,
                    container: 'body',
                    placement: 'top'
                });
                $(el).popover({
                    trigger: 'click',
                    html: true,
                    content: attrs.popoverHtml,
                    placement: attrs.popoverPlacement,
                    container: 'body'
                })
                .on('inserted.bs.popover', function (e) {
                    bindevents();
                    $('#popovertext' + index).val(scope.myModel);
                }).on('hidden.bs.popover', function () {
                    Unbindevents();
                });
                function bindevents() {
                    $(btnsave).bind('click', function () {
                        var text = $('#popovertext' + index).val();
                        scope.myModel = text;
                        $(el).tooltip('hide')
                       .attr('data-original-title', text)
                       .tooltip('fixTitle')
                        toggle();
                    });
                    $(btncancel).bind('click', function () {
                        toggle();
                    });
                }
                function Unbindevents() {
                    $(btnsave).unbind('click');
                    $(btncancel).unbind('click');
                }
                function toggle() {
                    $(el).popover('hide');
                    $(el).click();
                }

            }
        };
    });
app.controller('MyController',['$scope',function($scope){
  $scope.list=[
    {
      name:'ABC'
    },
     {
      name:'DEF'
    },
     {
      name:'GHI'
    },
     {
      name:'KLM'
    }
    ];

}]);

Need help closing other popover while opening next one.

3
  • 1
    I can see in the plunk nothing seems to work! Commented Dec 28, 2016 at 17:29
  • There is bootstrap for angular directives readily available. I would recommend using that over wiring up your own jquery functionality .angular-ui.github.io/bootstrap Commented Dec 28, 2016 at 17:56
  • If @suzo answered your question you should award the bounty to him/her Commented Jan 4, 2017 at 15:58

2 Answers 2

5
+50

You can close the other popovers when show.bs.popover is triggered as shown below : Updated Plunkr

$(el).popover({
                trigger: 'click',
                html: true,
                content: attrs.popoverHtml,
                placement: attrs.popoverPlacement,
                container: 'body'
            })
             .on('show.bs.popover', function () {
              var siblings = $(el).parent().parent().siblings();
              siblings.each(function (each){
                $(siblings[each]).find('span').popover('hide');
              });
            });
Sign up to request clarification or add additional context in comments.

2 Comments

I think this is a bad way of doing it. Because it relies on the directive having knowledge of the calling code. Meaning, our directive now needs to know how the parent page/view/whatever has its html structured. This gets the job done, but it now makes the directive "know" how it is supposed to be called, leaving it not as modular.
Yeah, this solution can be used only for this case. If the html structure changes, this doesn't work. I'm still trying to come up with a better solution.
4

IMO, the most modular way would be to use a service to track all opened PopUps.

This gives multiple benefits.

  1. You can extend the service to track different types of popups, allowing you to close all or open all or do whatever you need

  2. It removes the logic from the controls and directives on keeping track of popups. Thus they can focus on 1 specific thing. You can also run multiple controllers and popups on a page allowing each controller/popup to be a discrete unit of work and not needing to worry about other controllers/popups stomping on their items.

The cons of doing this

  1. As I commented earlier you can use the angular bootstrap directives for this. Making your code "cleaner", because all this is done for you. What is not done for you is closing all active popups. You can take the same service approach I have used and just plug it into the ng-bootstrap directives.
  2. Binding/Unbinding the JQUERY events seems to become unresponsive when you click 8+ times. I do not have an answer for why that is, but the overall idea of using a service to keep track is still a valid one.

You shoudl be able to cut and paste this code into the plnkr or your dev box and it will work.

// Code goes here
var app = angular.module('myApp',[]);

app.factory('popUpService', function() {
  var activePopups = [];
  // factory function body that constructs shinyNewServiceInstance

  return {
  AddPopup : function(el)
  {
  activePopups.push(el);
  },
  CloseAllPopups : function(closeFunction){
  for (var i = 0; i < activePopups.length; i++)
  { 
           closeFunction(activePopups[i])

  }
  }
  }

});
app.directive('customEditPopover',['popUpService', function (popUpService) {
        return {
            restrict: 'A',
            template: '<span><i class="fa fa-tags" aria-hidden="true"></i></span>',
            scope: {
                'myModel': '=',
            },
            link: function (scope, el, attrs) {
                scope.label = attrs.popoverLabel;
                var btnsave = '#' + attrs.popoverSave;
                var btncancel = '#' + attrs.popoverCancel;
                var index = attrs.index;
                $(el).tooltip({
                    title: '' + (scope.myModel == undefined) ? "" : scope.myModel,
                    container: 'body',
                    placement: 'top'
                });
                $(el).popover({
                    trigger: 'click',
                    html: true,
                    content: attrs.popoverHtml,
                    placement: attrs.popoverPlacement,
                    container: 'body'
                })
                .on('inserted.bs.popover', function (e) {
                    bindevents();
                    $('#popovertext' + index).val(scope.myModel);
                }).on('hidden.bs.popover', function () {
                    Unbindevents();
                });
                function bindevents() {

                CloseAll();

                popUpService.AddPopup($(el));

                    $(btnsave).bind('click', function () {
                        var text = $('#popovertext' + index).val();
                        scope.myModel = text;
                        $(el).tooltip('hide')
                       .attr('data-original-title', text)
                       .tooltip('fixTitle')
                    closeCurrent();
                    });
                    $(btncancel).bind('click', function () {
                    closeCurrent();
                    });
                }
                function Unbindevents() {
                    $(btnsave).unbind('click');
                    $(btncancel).unbind('click');
                }
                function closeCurrent(){
                   $(el).popover('hide');
                 //   $(el).click();
                }
                function CloseAll() {

                popUpService.CloseAllPopups(function(popup){ 

                   popup.popover('hide');
                //    popup.click();
              });

            }
        }
        }
    }]);
app.controller('MyController',['$scope',function($scope){
  $scope.list=[
    {
      name:'ABC'
    },
     {
      name:'DEF'
    },
     {
      name:'GHI'
    },
     {
      name:'KLM'
    }
    ];

}]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.