0

I need to display a small popover which should open on click and goaway on clicking anywhere on the page.

I found a plunker (http://plnkr.co/edit/K7cYQSDEBS3cHvDfJNLI?p=preview) which matches this requirement however, unable to get it to work inside ng-repeat.

I saw several answers and Plunker examples but not able to get this to work.

Here is my html

<div ng-controller="TestController">
<div class="row" style="background-color: #ebebeb !Important; ">
    <div style="text-align:center">
    <table style="width:100% !important;">
        <tr ng-repeat="member in TeamMembers" style="font-size:18px !important; height: 108px;">
        <td style="display:block;margin-top:30px;text-align:left;">&nbsp;{{member.FirstName}} {{member.LastName}} <i class="fa fa-info-circle" aria-hidden="true" ng-show="member.Description != null" popover-template="dynamicPopover.templateUrl"  popover-placement="bottom" popover-elem descr="{{member.Description}}"></i></td>
        </tr>
    </table>
    </div>
</div>

...

<script type="text/ng-template" id="descriptionModal.html">
    <div class="adp-info-dialog">
        <div class="modal-body">
        <div class="row">
            <div class="col-md-8 col-md-offset-1">
            <div class="form-group">
                <label class="fieldset-label">Test {{ dynamicPopover.descr }}</label>
            </div>
            </div>
        </div>
        </div>
    </div>
</script>

Here is the JS

testApp.controller('TestController', function ($scope, $rootScope, $log, $modal, SiebelAccountTeamService, $filter, $element) {
$scope.dynamicPopover = {
    templateUrl: 'descriptionModal.html',
    descr: null
};
var result = TestService.GetTeamMembers();
result.then(function (data) {
    $scope.TeamMembers = data.data;
}, function (e) {
    console.log(e);
}).finally(function () {
    $scope.CompleteLoading();
});   

});

testApp.directive('popoverClose', function ($timeout) {
return {
    scope: {
        excludeClass: '@'
    },
    link: function (scope, element, attrs) {
        var trigger = document.getElementsByClassName('trigger');

        function closeTrigger(i) {
            $timeout(function () {
                angular.element(trigger[0]).triggerHandler('click').removeClass('trigger');
            });
        }

        element.on('click', function (event) {
            var etarget = angular.element(event.target);
            var tlength = trigger.length;
            if (!etarget.hasClass('trigger') && !etarget.hasClass(scope.excludeClass)) {
                for (var i = 0; i < tlength; i++) {
                    closeTrigger(i)
                }
            }
        });
    }
};

});

testApp.directive('popoverElem', function () {
return {
    scope: {
        descr: '@'
    },
    link: function (scope, element, attrs) {            
        $scope.dynamicPopover.descr = scope.descr,
        alert($scope.dynamicPopover.descr),
        element.on('click', function () {
            element.addClass('trigger');
        });            
    }            
};

});

Appreciate your help.

SK-USA
  • 91
  • 1
  • 8

1 Answers1

0

Update:

To show the data of the ng-repeat inside the popover content, we need to access the individual objects through the $index of the ng-repeat. Refer the below example.

Plunkr Demo

The problem here is that you are using ng-repeat which creates a new scope read more here.

Since replicating the issue with your code is tedious, I tried replicating the issue with the plunkr!

Solution:

Plunkr Demo

You can simply define a new controller inside the descriptionModal.html like so

HTML:

<script type="text/ng-template" id="myPopoverTemplate.html">
      <div class="adp-info-dialog" ng-controller="tester">
        <div class="modal-body">
        <div class="row">
            <div class="col-md-8 col-md-offset-1">
            <div class="form-group">
                <label class="fieldset-label">Test {{ $parent.$parent.dynamicPopover.content }}</label>
            </div>
            </div>
        </div>
        </div>
    </div>
    </script>

JS:

app.controller('tester', function ($rootScope, $scope) {
  console.log($scope.$parent.$parent.dynamicPopover.title);
});  

Then, we will be able to access the parent scope, using $parent, the html inside the above script uses the $parent to get the variable!

Please note: It took me two $parent to reach the required $scope to access the scope variable. In your scenario it will also require two, the way to check how many is needed is use console.log($scope), then open the console(F12), then traverse through the objects $parent property till you find the correct $scope. Then count the number of $parent traversed, that will be your required number of $parent to traverse!

P.S:

There is another method you can do this, since this method will require a significant rewrite of your code, I will provide the GIST, you can use the controller as syntax and access the correct scope.

Here is the SO Answer giving the method to do it

SO Answer

I hope this fixes you issue.

Naren Murali
  • 19,250
  • 3
  • 27
  • 54
  • My apologies for not providing a Plunker. I was able to make this work by adding this to the directive: scope.$parent.dynamicPopover.descr = scope.descr; However, while this does display the content - the content is not changing with the change based on data. It picks up the last content and keeps displaying that. – SK-USA Sep 05 '17 at 19:45
  • No - unfortunately - the content is not changing based on the data in ng-repeat. The value of the last item is what is displayed in the popup. – SK-USA Sep 05 '17 at 20:01
  • @codelearner Sorry I did not think from that perspective, updated my answer to the new requirement! – Naren Murali Sep 05 '17 at 20:13