Angular Wrapper Directive #538

Closed
campbeln opened this Issue Mar 17, 2016 · 3 comments

Projects

None yet

2 participants

@campbeln

In order to use Tooltipster I had to roll an Angular directive and I thought it might be worthwhile to share the code back to the community!

Exclusive scoping is not required and everything is 100% overrideable. I have added a single option setting that is consumed by the directive - selector. This specifies a DOM object that is selected via jQuery(_selector_) to act as the content of the tooltip. This value can either be set as a string specifying the selector or as true (which specifies that the value of [title] is to be used as the selector).

ngApp.directive('title', ["$timeout", function ($timeout) {
    function isStr(s, bDisallowNullString) {
        return (
            (typeof s == 'string' || s instanceof String) &&
            (!bDisallowNullString || s !== '')
        ) ? true : false;
    }

    function isFn(f) {
        return (Object.prototype.toString.call(f) === '[object Function]') ? true : false;
    }

    function makeObj(o) {
        return (o && o === Object(o) && !isFn(o) ? o : {});
    }

    return {
        restrict: 'A',
        link: function ($scope, $element, $attrs) {
            var oOptions = makeObj($scope.$eval($attrs.titleOptions)),
                bTitleIsSelector = (oOptions.selector === true),
                b$evalTitle = true
            ;

            //# Configure the .tooltipster for the $element
            $element.tooltipster(jQuery.extend({
                //# Hook the .functionBefore to reset the .content based on the latest data from Angular
                functionBefore: function(origin, continueTooltip) {
                    var sContent = $attrs.title;

                    //# If a .selector was passed (either in the .title or in .selector), set the sContent to its .html 
                    if (bTitleIsSelector || isStr(oOptions.selector, true)) {
                        sContent = jQuery(bTitleIsSelector ? sContent : oOptions.selector).html();
                    }
                    //# Else if we can b$evalTitle
                    else if (b$evalTitle) {
                        try {
                            sContent = $scope.$eval(sContent);
                        } catch (e) {
                            b$evalTitle = false;
                            //console.log("$eval Error: ", $element, sContent, e);
                        }
                    }

                    //# Clear the [title] so the browser doesn't pop up the element
                    $timeout(function() {
                        $element.attr("title", "");
                    });

                    //# Update the sContent, .continueTooltip'ing if there is sContent to display
                    origin.tooltipster('content', (oOptions.contentAsHTML ? jQuery(sContent) : sContent));
                    sContent && continueTooltip();
                }
            }, oOptions));
        }
    };
}]);

Usage:

<div title="My Title!" title-options="{ position: 'bottom-left', offsetX: -10 }">blah</div>
<div title="This will be ignored" title-options="{ selector: '#MyContent', contentAsHTML: true }">blah</div>
<div title="#MyContent" title-options="{ selector: true, contentAsHTML: true }">blah</div>
<div id="MyContent">
    <b>HTML</b> Content here!
</div>
@louisameline
Collaborator
louisameline commented Mar 18, 2016 edited

Thank you ! I lack experience on Angular to fully appreciate the results of this snippet but I'll probably end up trying at some point and hint at this in the documentation. Thanks again !

@louisameline
Collaborator
louisameline commented Jul 15, 2016 edited

A small update would be required for this to work with Tooltipster v4 since the signature of functionBefore has changed.

functionBefore: function(origin, continueTooltip) {
becomes
functionBefore: function(instance, helper) {

origin.tooltipster('content', (oOptions.contentAsHTML ? jQuery(sContent) : sContent));
becomes
instance.content(oOptions.contentAsHTML ? jQuery(sContent) : sContent);
but actually could be
instance.content(sContent);
since Tooltipster itself appends the content as an HTML node if contentAsHTML is true.

The sContent && continueTooltip(); line can be removed, Tooltipster continues when you don't return false but then stops by itself if sContent is null.

And a selector for HTML content can now be passed in a data-tooltip-content attribute, so I think you don't need to do that yourself anymore.

...and I think it should work.

@louisameline
Collaborator

I have listed this page in the documentation, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment