Search code examples
javascriptjqueryhtmlangularjsmouseover

Event listener disappears inside ng-repeat


My HTML form has many questions I create using ng-repeat. I want to create a pop-over for some questions. When I put the button that triggers the pop-over outside the ng-repeat, it works. Inside the ng-repeat it does not.

This works (button before ng-repeat):

enter image description here

    <div class="row">
        <div class="col-md-12">                         
            <button title="" data-toggle="popover" data-placement="top" data-trigger="hover" data-title="Popover on hover" data-content="And here's some amazing content. It's very engaging. Right?" class="btn btn-primary btn-wide">
                                    hover
            </button>
        <div ng-repeat="q in config.questionnaire.questions">

Producing this:

enter image description here

This does not work (button after ng-repeat):

enter image description here

    <div class="row">
        <div class="col-md-12">                         
            <div ng-repeat="q in config.questionnaire.questions">
                <button title="" data-toggle="popover" data-placement="top" data-trigger="hover" data-title="Popover on hover" data-content="And here's some amazing content. It's very engaging. Right?" class="btn btn-primary btn-wide">
                                    hover
                </button>

Inspecting the button element on google chrome, I found that some event listeners were removed:

These are the event listeners for the button before the ng-repeat:

enter image description here

These are the event listeners for the button after the ng-repeat:

enter image description here

As you can see, mouseover and mouse out listeners disappeared.

Why?

What can I do?


Solution

  • If you are using Bootstrap with your Angular project, think of using Angular UI library.

    https://angular-ui.github.io/bootstrap/#/popover

    It provides many directives which make it easier to connect Bootstrap with Angular. I tested the uib-popover directive with ng-repeat and it works properly this way. The code is pretty simple:

    //...
    
    <div ng-repeat="t in main.testArray">
        <button uib-popover="My popover content" popover-title="Popover title" popover-trigger="mouseenter">{{t.text}}</button>
    </div>
    
    //...
    

    I will try to investigate your problem further, but the library seems to be an easy workaround.


    Edit

    I think I also managed to figure out a solution without using external library. What I did was creating a directive which initializes Boostrap popover on specified element. This way you make sure that the popover function will be fired when elements are rendered. I guess this was the reason why it didn't work with your method. You probably invoked the popover function before elements were really rendered as ng-repeat does this with a delay.

    And here is the code:

    angular.module('moduleName')
        .directive('bootstrapPopover', function() {
            return {
                 restrict: 'A',
                 link: function (scope, element, attrs) { 
                      element.popover();
                 }
            };
        });
    

    And then use directive on element:

    <div ng-repeat="t in main.test">
        <button data-toggle="popover" data-placement="top" data-trigger="hover" data-title="Test" data-content="Test" 
                class="btn btn-primary btn-wide" bootstrap-popover>hover {{t.text}</button>
    </div>
    

    However, I would still recommend trying the Angular UI out. I used it in the last Angular project and it was really helpful.