Search code examples
javascriptjqueryangularjspopover

AngularJS popover not showing content: Rendered Too Early


In my AngularJS controller, I call my data service method, which makes a $http call to fetch the data needed for page display.

appDataService.getById()
  .success(function(document) {
      vm.document = document;
  }
  .error(function(e)){});

Everything is displaying fine and most of my popovers are displaying their contents correctly when toggled / clicked on. However, I am having an issue with one of them.

    <button popover-directive
            popover-placement="auto"
            popover-content="{{ vm.document.content }}"
            popover-label="Click to View Text "
            class="btn btn-info btn-xs">
    </button>

I checked the HTML and can confirm that the popover-content is given the correct string value. However, when I click on it, the expected triggered-popover behavior did not occur,

i.e. a new <div class="popover fade right in"> did not appear.

If the popover-content is given a direct value such as popover-content="testing", the popover works properly and shows the content when clicked.

It is my strong suspicion that this is due to the asynchronous behavior of my data fetch; my data is not being returned in time for my popover to be properly initialized.

Clearly, my popover directive is functioning as it should and I don't think the problem lies with it, but for the sake of a complete picture, I supply my popover directive as follows:

function popoverDirective ($document) {
    return {
      restrict: 'A',
      template: '<span>{{label}}</span>',
      link: function (scope, element, attrs) {
        scope.label = attrs.popoverLabel;
        $(element).popover({
          trigger: 'click',
          html: true,
          content: attrs.popoverContent,
          placement: attrs.popoverPlacement
        });
      }
    };
  }

Any solutions? Thank you!


Solution

  • Since the directive attributes are interpolated, consider changing it as:

    <button popover-directive
            popover-placement="auto"
            popover-content="{{vm.document.content}}"  <!-- Change at this line -->
            popover-label="Click to View Text "
            class="btn btn-info btn-xs">
    </button>
    

    Also, you need to register an observer since vm.document.content is resolved via a promise:

    function popoverDirective ($document) {
        return {
          restrict: 'A',
          template: '<span>{{label}}</span>',
          link: function (scope, element, attrs) {
            function initPopover() {
                scope.label = attrs.popoverLabel;
    
                // Make sure to remove any popover before hand (please confirm the method)
                $(element).popover("destroy");
    
                $(element).popover({
                  trigger: 'click',
                  html: true,
                  content: attrs.popoverContent,
                  placement: attrs.popoverPlacement
                });
            }
    
            attrs.$observe("popoverContent", initPopover);
          }
        };
      }
    

    Note Please remove bootstrap.min.js if you are using Bootstrap and you can also remove jQuery. Angular UI team has ported the Bootstrap Javascript to support Angular. Check this out http://angular-ui.github.io/bootstrap