Kendo UI: Conditionally preventing a Tooltip from being displayed on a Grid cell

19,596

Solution 1

The tooltip is implemented in a way that makes this difficult. You could call this.hide() wrapped in a setTimeout, but it will have a flicker effect. So you'll probably have to roll your own solution for this. Here's an idea to get you started:

Create a beforeShow pseudo-event which is triggered before the tooltip is shown (this could all be done in a more sophisticated fashion):

// customize the _show method to call options.beforeShow 
// to allow preventing the tooltip from being shown..
kendo.ui.Tooltip.fn._show = function (show) {
    return function (target) {
        var e = {
            sender: this,
            target: target,
            preventDefault: function () {
                this.isDefaultPrevented = true;
            }
        };

        if (typeof this.options.beforeShow === "function") {
            this.options.beforeShow.call(this, e);
        }
        if (!e.isDefaultPrevented) {
            // only show the tooltip if preventDefault() wasn't called..
            show.call(this, target);
        }
    };
}(kendo.ui.Tooltip.fn._show);

Use it like this to conditionally prevent showing the tooltip:

var toolTip = $('#grid').kendoTooltip({
    filter: ".tooltip",
    beforeShow: function (e) {
        if ($(e.target).data("name") === null) {
            // don't show the tooltip if the name attribute contains null
            e.preventDefault();
        }
    },
    content: function (e) {
        var row = $(e.target).closest("tr");
        var dataItem = grid.dataItem(row);

        return "<div>Hi, this is a tool tip for id " + dataItem.Id + "! </div>";
    }
}).data("kendoTooltip");

(demo)

Solution 2

I just came across this and found a solution that works very well. The content event can work like a beforeShow event, because it is actually called before the show event is fired. If we treat it like a beforeShow event we can do this

var grid = $("#myGrid").data("kendoGrid");

grid.table.kendoTooltip({
    width: 300,
    height: 200,
    opacity: 0,
    callout: true,
    position: 'right',
    animation:
    {
        close: {
            effects: "fade:out"
        },
        open: {
            effects: "fade:in",
            duration: 1000
        }
    },
    contentTemplateId: "tooltipTemplate",
    filter: "td",
    show: function (e) {

    },
    content: function (e) {
        var target = e.target,
        currentTarget = target;

        // hide popup as default action
        e.sender.popup.element.css("visibility", "hidden");

        if ($(currentTarget[0]).attr("name") !== undefined) {

           e.sender.popup.element.css("visibility", "visible");

           //Do ajax call, show tool tip
           $.getJSON("SomeUrl").then(function(response) {

               $(target).text(response);

           });

           return "Loading...";
        }

        return "";
    }
});

Solution 3

I hope my post is not too late, but will help few of us. This can be achieved with show and hide events where we can validate the Tooltip text and show or hide the Tooltip as below and works for me.

  show: function(e){
        if(this.content.text() !=""){
            $('[role="tooltip"]').css("visibility", "visible");
        }
    },
    hide: function(){
        $('[role="tooltip"]').css("visibility", "hidden");
    },

Full code :

 $("#GridId").kendoTooltip({
    filter: "td:nth-child(1)", //this filter selects the second column's cells
    position: "right",
    autoHide: false,
    show: function(e){
        if(this.content.text() !=""){
            $('[role="tooltip"]').css("visibility", "visible");
        }
    },
    hide: function(){
        $('[role="tooltip"]').css("visibility", "hidden");
    },

    content: function(e){
        var dataItem = $("#GridId").data("kendoTreeList").dataItem(e.target.closest("tr"));
        var content = dataItem.ToolTip;
        if (content!=null) {
            return content;
        }
        else {

            return "";
        }

    }
}).data("kendoTooltip");

Solution 4

If you throw an error in the content method, this will prevent the tooltip ever showing.

var grid = $('#myGrid').data('kendoGrid');
grid.table.kendoTooltip({
    width: 300,
    height: 200,
    opacity: 0,
    callout: true,
    position: 'right',
    animation: {
        close: {
            effects: 'fade:out'
        },
        open: {
            effects: 'fade:in',
            duration: 1000
        }
    },
    contentTemplateId: 'tooltipTemplate',
    filter: 'td',
    show: function (e) { },
    content: function (e) {
        var message = 'Loading...';
        if (!$(e.target).attr('name')) {
           throw 'No name yet, don\'t show tooltip!';
        }
        //Do ajax call, show tool tip
    }
});

If you're waiting for an ajax response though, then just create the tooltip when the call is completed.

Share:
19,596
loxdog
Author by

loxdog

Updated on June 14, 2022

Comments

  • loxdog
    loxdog about 2 years

    I'm working on trying to display a Kendo tool tip on a grid cell, getting the content from an ajax call. My tooltip declaration looks like the below:

        var grid = $("#myGrid").data("kendoGrid");
    
        grid.table.kendoTooltip({
            width: 300,
            height: 200,
            opacity: 0,
            callout: true,
            position: 'right',
            animation:
            {
                close: {
                    effects: "fade:out"
                },
                open: {
                    effects: "fade:in",
                    duration: 1000
                }
            },
            contentTemplateId: "tooltipTemplate",
            filter: "td",
            show: function (e) {
    
            },
            content: function (e) {
                var target = e.target;
                currentTarget = target;
    
                var message = "Loading...";
                if ($(currentTarget[0]).attr("name") !== undefined) {
                   //Do ajax call, show tool tip
                }
                else {
                    //CLOSE THE TOOTLIP
                    return false;
                }
            }
        });
    

    In that bottom "else", I want to close or hide the tooltip since I don't have the attribute "name", which is passed into my ajax call to show the content. I've tried all of the following:

    $("#myGrid").data("kendoGrid").table.kendoTooltip.hide();
    $("#myGrid").data("kendoTooltip").hide();
    e.sender.popup.destroy();
    e.sender.popup.hide();
    e.sender.popup.close();
    

    None of these work! Destroy is the closest, but I can't recreate the tool tip when I need it again. Any advice?

  • loxdog
    loxdog about 10 years
    Once again, you've nailed it Lars. Little disappointed there isn't a more elegant solution to this problem but yours works perfectly fine
  • snuggles
    snuggles about 10 years
    This answer is great, but I have a question: would there be an issue if you forgot specify a 'beforeShow' function in your kendoTooltip config? You seem to be replacing the _show function with a new one that does nothing if 'beforeShow' is not provided... ie wouldn't you want to just call show.call(this, target) if typeof this.options.beforeShow === "function" was false?
  • Lars Höppner
    Lars Höppner about 10 years
    @snuggles You're right, of course - thanks for the hint. I updated the code.
  • RMorrisey
    RMorrisey about 8 years
    Lars, you can add one more line of code to make Kendo recognize this new event: kendo.ui.Tooltip.fn.events.push('beforeShow'); This enables angular integration (<div kendo-tooltip k-on-before-show="myController.handle(kendoEvent)">)
  • KthProg
    KthProg almost 8 years
    It's killing me that this is accepted when my answer is so much simpler
  • yourpublicdisplayname
    yourpublicdisplayname almost 8 years
    This both breaks into the javascript debugger if the developer console is open, and spams the log with errors. Lar's solution isn't ideal, but these things aren't an option for some of us.
  • KthProg
    KthProg almost 8 years
    I have a better solution that involved setting some css rule beforehand which you remove if it has content, but unless someone asks for it I don't see the point taking the time.
  • chiapa
    chiapa over 7 years
    Great answer - gets the job done, without the unwanted flickering, and not overcomplicated
  • Agrejus
    Agrejus over 7 years
    Your answer contains errors. You need to either escape your quote in don\'t or surround the error string with double quotes
  • KthProg
    KthProg over 7 years
    Thanks you're correct! I like to use single quotes and didn't think about it
  • KthProg
    KthProg over 7 years
    Lol this is similar to the solution I wanted to post but there didn't seem to be any interest.
  • Agrejus
    Agrejus over 7 years
    You're welcome, don't want you to get down voted for it :)
  • Aaron Smith
    Aaron Smith over 2 years
    I tried this, and the this context was just the window for me.