web-dev-qa-db-fra.com

Infobulle Angular-ui avec HTML

J'ajoute actuellement des info-bulles bootstrap dans mon application.

Toutes les info-bulles "normales" sont correctes, mais quand je veux utiliser tooltip-html-unsafe, je n'ai obtenu qu'une info-bulle vide.

Mon info-bulle:

<a><span tooltip-placement="right" tooltip-html-safe="{{myHTMLText}}"> Help </span></a>

Dans le DOM, j'ai:

<div class="tooltip-inner" ng-bind-html-unsafe="content"></div>

Le contenu de la div semble vide, il n'y a donc rien à afficher dans l'info-bulle. J'ai essayé de mettre directement dans le DOM du texte HTML comme:

<div class="tooltip-inner" ng-bind-html-unsafe="content"><b>test</b></div> et il fonctionne.

Avez-vous une idée?

12
Mencls

La directive html-unsafe est conçue pour pointer son contenu. Et ça:

<div data-ng-controller="SomeCtrl">
    <span data-tooltip-html-unsafe="{{yourContent}}" data-tooltip-placement="right">
        Help
    </span>
</div>

Ensuite, dans SomeCtrl, créez une variable pour contenir le html:

$scope.yourContent = "<b>my html, yay</b>

SI vous souhaitez modifier bootstrap pour prendre le contenu d'un élément, cela peut être fait comme ceci. Tout d'abord, vous devez changer le modèle d'info-bulle pour qu'il appelle une fonction pour obtenir le html:

angular.module("template/tooltip/tooltip-html-unsafe-popup.html", []).run(["$templateCache", function($templateCache) {
  $templateCache.put("template/tooltip/tooltip-html-unsafe-popup.html",
    "<div class=\"tooltip {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
    "  <div class=\"tooltip-arrow\"></div>\n" +
    "  <div class=\"tooltip-inner\" ng-bind-html-unsafe=\"getToolTipHtml()\"></div>\n" +
    "</div>\n" +
    "");
}]);

Ensuite, créez une fonction de lien pour l'info-bulleHtmlUnsafePopup:

.directive( 'tooltipHtmlUnsafePopup', function () {
  return {
    restrict: 'E',
    replace: true,
    scope: { content: '@', placement: '@', animation: '&', isOpen: '&' },
    templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html',
    link: function(scope, element, attrs) {
        scope.getTooltipHtml = function() {
            var elemId = '#' + scope.content;
            var htmlContent = $rootElement.find(elemId).html();
            return htmlContent;
        };
    }
  };
})

EDIT: Plus tard, j'ai extrait le code personnalisé de ui-bootstrap, ce qui est bien car vous n'avez pas à modifier ui-bootstrap pour l'utiliser maintenant. Voici le code extrait, dans un module appelé "bootstrapx". C'est juste pour les popovers (car je n'utilisais pas vraiment les info-bulles) mais je pense que cela devrait également être facilement adaptable pour les info-bulles.

angular.module("bootstrapx", ["bootstrapx.tpls","bootstrapx.popover","bootstrapx.popover.dismisser"]);
angular.module("bootstrapx.tpls", ["template/popover/popover-html.html","template/popover/popover-html-unsafe.html","template/popover/popover-template.html"]);


angular.module( 'bootstrapx.popover', [ 'ui.bootstrap.tooltip' ] )
    .directive('popover', [ function() {
        return {
            restrict: 'EA',
            priority: -1000,
            link: function(scope, element) {
                element.addClass('popover-link');
            }
        };
    }])
    .directive('popoverHtml', [ function() {
        return {
            restrict: 'EA',
            priority: -1000,
            link: function(scope, element) {
                element.addClass('popover-link');
            }
        };
    }])
    .directive('popoverHtmlUnsafe', [ function() {
        return {
            restrict: 'EA',
            priority: -1000,
            link: function(scope, element) {
                element.addClass('popover-link');
            }
        };
    }])
    .directive('popoverTemplate', [ function() {
        return {
            restrict: 'EA',
            priority: -1000,
            link: function(scope, element) {
                element.addClass('popover-link');
            }
        };
    }])

    .directive( 'popoverHtmlPopup', [ function() {
        return {
            restrict: 'EA',
            replace: true,
            scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' },
            templateUrl: 'template/popover/popover-html.html'
        };
    }])
    .directive( 'popoverHtml', [ '$compile', '$timeout', '$parse', '$window', '$tooltip', function ( $compile, $timeout, $parse, $window, $tooltip ) {
        return $tooltip( 'popoverHtml', 'popover', 'click' );
    }])

    .directive( 'popoverHtmlUnsafePopup', [ '$rootElement', function ( $rootElement ) {
        return {
            restrict: 'EA',
            replace: true,
            scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' },
            templateUrl: 'template/popover/popover-html-unsafe.html',
            link: function(scope, element) {
                var htmlContent = '';
                scope.$watch('content', function(value) {
                    if (!value) {
                        return;
                    }
                    var elemId = '#' + value;
                    htmlContent = $rootElement.find(elemId).html();
                });

                scope.getPopoverHtml = function() {
                    return htmlContent;
                };
            }
        };
    }])
    .directive( 'popoverHtmlUnsafe', [ '$compile', '$timeout', '$parse', '$window', '$tooltip', function ( $compile, $timeout, $parse, $window, $tooltip ) {
        return $tooltip( 'popoverHtmlUnsafe', 'popover', 'click' );
    }])

    .directive( 'popoverTemplatePopup', [ '$http', '$templateCache', '$compile', '$parse', function ( $http, $templateCache, $compile, $parse) {
        return {
            restrict: 'EA',
            replace: true,
            scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' },
            templateUrl: 'template/popover/popover-template.html',
            link: function(scope, element, attrs) {
                scope.getPopoverTemplate = function() {
                    var templateName = scope.content + '.html';
                    return templateName;
                };
            }
        };
    }])
    .directive( 'popoverTemplate', [ '$compile', '$timeout', '$parse', '$window', '$tooltip', function ( $compile, $timeout, $parse, $window, $tooltip ) {
        return $tooltip( 'popoverTemplate', 'popover', 'click' );
    }]);

    angular.module("template/popover/popover-html.html", []).run(["$templateCache", function($templateCache) {
        $templateCache.put("template/popover/popover-html.html",
            "<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
            "  <div class=\"arrow\"></div>\n" +
            "\n" +
            "  <div class=\"popover-inner\">\n" +
            "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-show=\"title\"></h3>\n" +
            "      <div class=\"popover-content\" ng-bind-html=\"content\"></div>\n" +
            "  </div>\n" +
            "</div>\n" +
            "");
        }]);

    angular.module("template/popover/popover-html-unsafe.html", []).run(["$templateCache", function($templateCache) {
        $templateCache.put("template/popover/popover-html-unsafe.html",
            "<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
            "  <div class=\"arrow\"></div>\n" +
            "\n" +
            "  <div class=\"popover-inner\">\n" +
            "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-show=\"title\"></h3>\n" +
            "      <div class=\"popover-content\" ng-bind-html-unsafe=\"{{getPopoverHtml()}}\"></div>\n" +
            "  </div>\n" +
            "</div>\n" +
            "");
    }]);

    angular.module("template/popover/popover-template.html", []).run(["$templateCache", function($templateCache) {
    $templateCache.put("template/popover/popover-template.html",
            "<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
            "  <div class=\"arrow\"></div>\n" +
            "\n" +
            "  <div class=\"popover-inner\">\n" +
            "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-show=\"title\"></h3>\n" +
            "      <div class=\"popover-content\" ng-include=\"getPopoverTemplate()\"></div>\n" +
            "  </div>\n" +
            "</div>\n" +
            "");
    }]);


    angular.module('bootstrapx.popover.dismisser', [])
        .directive( 'dismissPopovers', [ '$http', '$templateCache', '$compile', '$parse', function ( $http, $templateCache, $compile, $parse) {
            return {
                restrict: 'A',
                link: function(scope, element, attrs) {
                    element.bind('mouseup', function(e) {
                        var clickedOutside = true;
                        $('.popover-link').each(function() {
                            if ($(this).is(e.target) || $(this).has(e.target).length) {
                                clickedOutside = false;
                                return false;
                            }
                        });
                        if ($('.popover').has(e.target).length) {
                            clickedOutside = false;
                        }
                        if (clickedOutside) {
                            $('.popover').prev().click();
                        }
                    });   
                }
            };
        }]);

J'ai la directive de rejetagePopovers sur la balise body (cela s'applique probablement aussi aux info-bulles, il vous suffira de la modifier en fonction de vos besoins):

<body data-ng-controller="AppController" data-dismiss-popovers>
23
aet

J'ai créé une directive personnalisée qui permet des info-bulles html pour bootsrap de manière très simple. Pas besoin de remplacer les modèles:

angular.module('vermouthApp.htmlTooltip', [
])
.directive('vaTooltip', ['$http', '$templateCache', '$compile', '$parse', '$timeout', function ($http, $templateCache, $compile, $parse, $timeout)
{
    //va-tooltip = path to template or pure tooltip string
    //tooltip-updater = scope item to watch for changes when template has to be reloaded [optional (only if template is dynamic)]
    //All other attributes can be added for standart boostrap tooltip behavior (ex. tooltip-placement)
    return {
        restrict: 'A',
        scope: true,
        compile: function (tElem, tAttrs)
        {
            //Add bootstrap directive
            if (!tElem.attr('tooltip-html-unsafe'))
            {
                tElem.attr('tooltip-html-unsafe', '{{tooltip}}');
            }
            return function (scope, element, attrs)
            {
                scope.tooltip = attrs.vaTooltip;
                var tplUrl = $parse(scope.tooltip)(scope);
                function loadTemplate()
                {
                    $http.get(tplUrl, { cache: $templateCache }).success(function (tplContent)
                    {
                        var container = $('<div/>');
                        container.html($compile(tplContent.trim())(scope));
                        $timeout(function ()
                        {
                            scope.tooltip = container.html();
                        });
                    });
                }
                //remove our direcive to avoid infinite loop
                element.removeAttr('va-tooltip');
                //compile element to attach tooltip binding
                $compile(element)(scope);

                if (angular.isDefined(attrs.tooltipUpdater))
                {
                    scope.$watch(attrs.tooltipUpdater, function ()
                    {
                        loadTemplate();
                    });
                } else
                {
                    loadTemplate();
                }
            };
        }
    };
}]);

Voilà comment vous l'appelez

 <a va-tooltip="'tooltipContent.html'" tooltip-updater="item" tooltip-placement="bottom">
                <b><i>{{item.properties.length - propertyShowLimit + ' properties more...'}}</i></b>
            </a>

Et le modèle peut être comme ceci:

<script id="tooltipContent.html" type="text/ng-template">
    <span ng-repeat="prop in item.properties>
        <b>{{prop.name}}</b>:
        <span ng-repeat="val in prop.values">{{val.value}}&nbsp;</span>
        <br />
    </span>
</script>
6
Adomas.NET

Il existe maintenant une fonctionnalité de modèle intégré: https://angular-ui.github.io/bootstrap/#tooltip

<a href="#" uib-tooltip-template="'myTooltipTemplate.html'">Custom template</a>

<script type="text/ng-template" id="myTooltipTemplate.html">
  <span>Special Tooltip with <strong>markup</strong> and {{ dynamicTooltipText }}</span>
</script>
4
Parris Varney