Search code examples
jqueryangularjstwitter-bootstrappopover

popover with ng-repeat data not showing after ng-click


I have a button to show a popover with loaded data from the server:

<button ng-click="main.getFieldDescriptions()" data-placement="bottom"
        data-toggle="popover" data-container="body"/>

This is an element I want to show as the popover content:

<div id="field-descriptions" class="hide" style="width:500px">
    <div class="row" ng-repeat="f in main.fieldDescriptions">
        <input class="form-control" readonly="true" value="{{f.fieldName}}" />
    </div>
</div>

The data is coming from the server with a get rest request(here is what I have in the controller)

angular.element("#show-fields-description").popover({
    html: true,
    content: function () {
        return angular.element("#field-descriptions").html();
    }
});

this.getFieldDescriptions = function getFieldDescriptions() {
    if (self.report.sysparm_table) {
        return server.get(url)
            .then(function getData(response) {
                self.fieldDescriptions = response.result;
            });
    }
    return null;
};

When the button is clicked popover shows empty content, by the second click it shows the popover with data. It seems popover shows first, then the server values load.


Solution

  • You are mixing plane bootstrap popover with angularjs...so $apply/digest cycle of angularjs does not know it.

    There are many ways.

    1. Call $apply when modal loaded

    2. Instead of data-toggle on html, call .popover('show') in ng-click callback

    3. use angular ui bootstrap popover

    For the first one:

    $('#show-fields-description').on('shown.bs.popover', function () {
      main.getFieldDescriptions();
    
      //Need to call $scope.$apply() after data is there
    })
    

    For the second one:

    Please see this https://getbootstrap.com/docs/4.3/components/popovers/#options

    remove all other attributes from html:

    <button ng-click="main.getFieldDescriptions()"></button>
    
    angular.element("#show-fields-description").popover({
        html: true,
        content: function () {
            return angular.element("#field-descriptions").html();
        },
        container: 'body',
        trigger: 'manual',
        placement: 'bottom'
    });
    

    and then call show/toggle here:

    this.getFieldDescriptions = function getFieldDescriptions() {
        if (self.report.sysparm_table) {
            return server.get(url)
            .then(function getData(response) {
                self.fieldDescriptions = response.result;
                angular.element("#show-fields-description").popover('show');
            });
        }
        return null;
    };