JQuery Tooltips with MVC3 and CSS 3.0 (Part 2)

by Admin 25. March 2012 02:56

So in my previous post I explained all of the steps required to create a simple but effective CSS 3 JQuery tooltip implementation.  This was a good start, I had all I needed to fulfill my requirement of a consistent tooltip in my application.  But I needed it to be a little easier to use throughout the application.  A custom Html Helper Extension to the rescue. Creating an HTML Helper is a pretty straight forward task this one, however, needed a bit of special sauce to make it work the way I wanted.

First I wanted to make sure I could bind it to my model, in case in the future I wanted to default it to the [Display] property on the model.  Second I wanted to be able to use the @<text></text> syntax for the contents of the tooltip.  It made sense to work backwards I wanted the control to work like this: 

@Html.InfoTooltipFor(model => model.ToolTipTitle,
	@<text>
	<h4>@Model.ToolTipTitle</h4>
	<ul>
   		<li>
			<b>Scott Guthrie</b> – 
			<a href="http://weblogs.asp.net/scottgu/">
				ScottGu's Blog
			</a> One of the best resources for all things Microsoft Web
                </li>
		<li>
			<b>Scott Hanselman</b> – 
				<a href="http://www.hanselman.com/blog/">
					Scott Hanselman's Computer Zen
				</a> Another great resource very current and very informative.
		</li>
		<li>
			<b>ASP.NET</b> – 
				<a href="http://www.asp.net/mvc">
					ASP.NET MVC
				</a> The mother of all things ASP.NET MVC
		</li>
     </ul>
</text>)

 

Seemed simple enough so at first I create the Helper as follows:

 

public static MvcHtmlString InfoTooltipFor<TModel, TValue>(
    this HtmlHelper<TModel> html, 
    Expression<Func<TModel, TValue>> expression, 
    string tooltip)
{
...
}

 

Nope that won't work... 

 

And once I thought about it makes sense that a string won't work.  It isn't anything remotely like a string it contains functions, delegates and properties. I know this type of implementation exists I have seen it in other controls.  So how is it done?  After an exhaustive google search I found this article by Phil Haack.  It was close to what I needed, so, after some trial and error I came up with this:

public static MvcHtmlString InfoTooltipFor<TModel, TValue>(this HtmlHelper<TModel> html, 
		Expression<Func<TModel, TValue>> expression, 
		Func<object, HelperResult> tooltip)
{
	//Get the Model metadata
	ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
	string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
	string tooltipId = metadata.PropertyName ? ? htmlFieldName.Split('.').Last();

	if (String.IsNullOrEmpty(tooltipId))
	{
		return MvcHtmlString.Empty;
	}
	//creates the span tag for the image
	TagBuilder spanTag = new TagBuilder("span");
	spanTag.MergeAttribute("class", "tooltipItem");
	spanTag.MergeAttribute("id", tooltipId);
	spanTag.MergeAttribute("data-tooltip", "tt" + tooltipId);

	TagBuilder imgTag = new TagBuilder("img");
	imgTag.MergeAttributes(new RouteValueDictionary(
		new
		{
			@class = "infoimage",
			src = UrlHelper.GenerateContentUrl("~/Content/info.png", html.ViewContext.HttpContext),
			alt = "info"
		}
		));
	spanTag.InnerHtml = imgTag.ToString(TagRenderMode.Normal);

	//creates the tooltip contents
	TagBuilder tooltipTag = new TagBuilder("div");
	tooltipTag.MergeAttribute("class", "hidden");
	tooltipTag.MergeAttribute("id", "tt" + tooltipId);
	tooltipTag.MergeAttribute("name", "tt" + tooltipId);
	tooltipTag.MergeAttribute("data-tooltip", "tt" + tooltipId);
	tooltipTag.InnerHtml = tooltip(null).ToString();

	return MvcHtmlString.Create(spanTag.ToString(TagRenderMode.Normal) + tooltipTag.ToString(TagRenderMode.Normal));
}

The key is Func<object, HelperResult> this allows templated items to be passed into helper method.  This was exactly what I needed and poof like magic it worked.  MVC is awesome, creating a control like that in standard ASP.NET would have been a major pain. 

The entire solution is in the attached zip...

EasyTooltips.zip (2.46 mb)

Tags: , , , ,

AJAX | css | jquery | MVC3

JQuery Tooltips with MVC3 and CSS 3.0 (Part 1)

by Admin 24. March 2012 17:58

I am a developer and no graphic artist by any strech of the imagination, but I am often thrown into that roll.   Seriously, how many small projects have the budget for a Graphic artist and a developer, not to mention the fact management rarely knows the difference.  

Regardless, I needed to create some tooltips to be used throughout an internal web application I was creating.  There are about 30 trillion jquery tooltip plugins on the internet, and most of them are good, I felt a little plugin overloaded, so I decide to roll my own.  The CSS 3.0 implementation was pretty simple (only 2 classes):

.tooltipwindow
{
   border-bottom-left-radius: 15px;
   border-top-left-radius: 0px;
   border-bottom-right-radius: 15px;
   border-top-right-radius: 15px;
   border: 1px solid #0099FF;
   position:absolute;
   padding:5px;
   background-color:#fff;
   z-index: 20000;
   box-shadow: 3px 3px 2px #808080;
   font-size:smaller;
}
 
.hidden
{
   display:none;
}

Only a few CSS 3.0 items to mention box-shadow (for the drop shadow effect) and border-radius (for the rounded corners on all but the top right) other than that pretty standard.  The JavaScript was pretty simple as well:

A few global variables:

//A 1/2 Second fade-in/out
var toolTipHideDelay = 500;
//A 1/4 second before the tooltip begins to fade
var toolTipMouseoutDelay = 250;
//The timer to determine when the fade should start
var toolTipHideTimer = null;
//The variable containing the tool tip contents
var tooltipWindow = null;
//The current Id of the tool tip
var tooltipCurrentId = null;

Then the actual tool event handlers:

//standard doc ready event
$(document).ready(function () {
 
    initializeTooltips();
})
 
function initializeTooltips() {
    //there is only one window for all tooltips on the page.
    tooltipWindow = $("#tooltipWindow");
    //all tooltips implement the following class
    var tooltipItem = $(".tooltipItem");
 
    //tooltip mouse events (not using hover because I want the tooltip to follow the cursor
    tooltipItem.mousemove(function (e) {
        //check to see if the tooltip is already opened
        if (toolTipHideTimer) {
            //clear the timeout since the user is hovering over the item again
            clearTimeout(toolTipHideTimer);
            //retrieve the tooltip data item from the current element
            if (tooltipCurrentId != $(this).data("tooltip")) {
                setToolTipPosition(this, e);
                //set the tooltip inner content
                tooltipWindow.html($("#" + $(this).data("tooltip")).html());
            }
        } else {
            //show the tooltip
            setToolTipPosition(this, e);
            //the tooltip is hidden do fade it in
            tooltipWindow.fadeIn(toolTipHideDelay);
            //set the tooltip inner content
            tooltipWindow.html($("#" + $(this).data("tooltip")).html());
        }
    });
    tooltipItem.mouseout(function (e) {
        //get ready to hide the tooltip
        toolTipHideTimer = setTimeout(function () {
            toolTipHideTimer = null;
            tooltipWindow.fadeOut();
        }, toolTipMouseoutDelay);
    });
 
    //tooltip window mouse events
    tooltipWindow.mouseover(function () {
        //keep the tooltip open if the user is over the tooltip window
        if (toolTipHideTimer) {
            clearTimeout(toolTipHideTimer);
        }
    });
    tooltipWindow.mouseout(function () {
        //get ready to hide the tooltip
        toolTipHideTimer = setTimeout(function () {
            toolTipHideTimer = null;
            tooltipWindow.fadeOut();
        }, toolTipMouseoutDelay);
    });
}

Then just a simple postion helper:

function setToolTipPosition(item, mouseevent) {
    var tooltipitem = $("#tooltipWindow");
    //set the tool tip to the current mouse position the 
    //2+ is so the user can still click the element under the 
    //tooltip
    tooltipitem.css({
        left: 2+(mouseevent.pageX) + "px",
        top: 2+(mouseevent.pageY) + "px"
    });
}

So now we have all of the client pieces we need, infact the following html will generate a tooltip:

<h3 style="display:inline-block">For More info hover over the icon</h3>
<span class="tooltipItem" data-tooltip="ttToolTipTitle" id="ToolTipTitle">
  <img alt="info" class="infoimage" src="/Content/info.png" />
</span>
 
<div class="hidden" data-tooltip="ttToolTipTitle" id="ttToolTipTitle" name="ttToolTipTitle">        
            <h4>Learn More from these sites</h4>
            <ul>
                <li><b>Scott Guthrie</b> – <a href="http://weblogs.asp.net/scottgu/">ScottGu's Blog</a> One of the best resources for all things Microsoft Web</li>
                <li><b>Scott Hanselman</b> – <a href="http://www.hanselman.com/blog/">Scott Hanselman's Computer Zen</a> Another great resource very current and very informative.</li>
                <li><b>ASP.NET</b> – <a href="http://www.asp.net/mvc">ASP.NET MVC</a> The mother of all things ASP.NET MVC</li>
            </ul>
        </div>
</div>
 
<div id="tooltipWindow" class="hidden tooltipwindow">
</div>

 

That looks like this:

 

So we are good to go, I just didnt want to have to copy all of this HTML for every tooltip I created in the system.  In Part 2 I will talk about how to integrate this with an MVC Html Helper.

 

Tags: , , ,

css | jquery

Calendar

<<  June 2017  >>
MoTuWeThFrSaSu
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

View posts in large calendar

Page List

RecentComments

None