I am using jquery ui 1.9 in an ajax based website.
I have the following code:
This is a <span title="Some warning" class="warning">warning</span> message<br />
This is a <span title="Some info" class="info">info</span> message
Using jquery ui tooltip would work, even for dynamic content:
$(function() {
$( document ).tooltip();
});
But I want different tooltip styles for each of this message-types. For example red color for warning and blue for info and it should work for dynamic content too.
Any ideas?
You need to use the toolTipClass property to specify the css class
$(document).ready(function() {
$( ".warning" ).tooltip({
tooltipClass: "warning-tooltip"
});
$( ".info" ).tooltip({
tooltipClass: "info-tooltip"
});
});
First, here is the code that works:
$(function() {
$('#warning-binder-element').tooltip({
items: '.warning',
tooltipClass: 'warning-tooltip',
content: function () {
return $(this).prev('.warning-toast').html();
},
position: {
my: "right bottom",
at: "right top-10"
}
});
$('#info-binder-element').tooltip({
items: '.info',
tooltipClass: 'info-tooltip',
content: function () {
return $(this).closest('.doo-hicky').next('.info-toast').html();
},
position: {
my: "left bottom",
at: "left+10 top-10"
}
});
});
A few notes on the above:
The selector for .tooltip() is not the item you want to have a tooltip pop up on, it is an element on the page that the tooltip object and its associated events are bound to.
If you attempt to bind two tooltips to the same object, only the last one will persist so binding both to $(document) will not work (which is why I have bound the two different tooltip objects to two different elements on the page).
you can bind the tooltip object to the item that will get the tooltip, but if you use a class selector, this may lead to ill effects.
Related
I would like to show a tooltip on a text input that has a ui-state-disabled class.
I took a peek to the tooltip source code and I couldn't find something that checks against that particular class. So I don't know why it won't show.
As far as I can tell, the elements aren't disabled per se, they just have a class applied to them.
So, how can I show a tooltip on elements that have that class? I don't want to use a wrapper or anything like that. Maybe extending through widget factory...
Here's a sample code
HTML
<input name="#1" class="text" data-tooltip="message A">
<input name="#2" class="text" data-tooltip="message B">
<br>
<button id="disable">disable input #2</button>
<button id="enable">enable input #2</button>
JS
$(".text").each(function()
{
$(this).tooltip({
content: $(this).data("tooltip"),
items: ".text"
});
});
$("#disable").click(function()
{
$("input[name='#2']").addClass("ui-state-disabled");
});
$("#enable").click(function()
{
$("input[name='#2']").removeClass("ui-state-disabled");
});
FIDDLE: https://jsfiddle.net/hn1o4qs2/
See the doc (http://api.jqueryui.com/tooltip/):
In general, disabled elements do not trigger any DOM events.
Therefore, it is not possible to properly control tooltips for
disabled elements, since we need to listen to events to determine when
to show and hide the tooltip. As a result, jQuery UI does not
guarantee any level of support for tooltips attached to disabled
elements. Unfortunately, this means that if you require tooltips on
disabled elements, you may end up with a mixture of native tooltips
and jQuery UI tooltips.
Solution with wrapper
Your HTML:
<span class="input-container" data-tooltip="message A">
<input name="#1" class="text">
</span>
<span class="input-container" data-tooltip="message B">
<input name="#2" class="text">
</span>
<br>
<button id="disable">
disable input #2
</button>
<button id="enable">
enable input #2
</button>
Your Javascript
$(".input-container").each(function()
{
$(this).tooltip({
content: $(this).data("tooltip"),
items: ".input-container"
});
});
// ... The rest is the same
Solution with fake disabled-property
Here you can use a readonly attribute and a custom class for disabled input.
Playground: https://jsfiddle.net/5gkx8qec/
As I've stated in my question, I needed to get this working without adding a container or anything like that. And I was willing to extend the widget somehow...
So I read the source code more carefully and searched throught the whole repository for ui-state-disabled, and found that in widget.js there is an _on() method that at some point performs a check against that class and a flag called suppressDisabledCheck
A comment in code says
// Allow widgets to customize the disabled handling
// - disabled as an array instead of boolean
// - disabled class as method for disabling individual parts
This was very important, it gave me the clue that this check could be overriden. So a quick search in google and the widget factory had the answer:
Automatically handles disabled widgets: If the widget is disabled or
the event occurs on an element with the ui-state-disabled class, the
event handler is not invoked. Can be overridden with the
suppressDisabledCheck parameter.
So basically I did this:
$.widget("ui.tooltip", $.ui.tooltip,
{
options: {
allowOnDisabled: false
},
_on: function()
{
var instance = this;
this._super(instance.options.allowOnDisabled, {
mouseover: "open",
focusin: "open",
mouseleave: "close",
focusout: "close"
});
}
});
And then used it like this:
$(".text").each(function()
{
$(this).tooltip({
allowOnDisabled: true,
content: $(this).data("tooltip"),
items: ".text"
});
});
EDIT 2022-09-15
I was having some trouble with this implementation, so I've changed it a little bit
$.widget("ui.tooltip", $.ui.tooltip,
{
options: {
allowOnDisabled: false
},
_create: function()
{
this._super();
var instance = this;
this._on(instance.options.allowOnDisabled, {
mouseover: "open",
focusin: "open",
mouseleave: "close",
focusout: "close"
});
}
});
Context
I have a small Ember app, which, amongst other things, displays a number of connected users and, when hovering an element of the page, their names as a list.
All in all, it works quite well. The applications pulls data from a REST endpoint every two minutes, as the backend didn't allow for pushing data.
The contents of the tooltip are computed in the Controller, with a function that basically concatenate strings in various ways according to the context. Then it's bound to a data attribute of the <img> the tooltip is created on. When the View is ready and didInsertElement is fired, the tooltip is generated (if needs be) based on this data-bindattr value.
Question
When new data is pulled from the backend, everything is updated accordingly, except the tooltip content. (When browsing the page's DOM, the data-bindattr value is updated too.)
What could cause the tooltip to not refresh? Is it a case of JQuery-UI not calculating it again?
Some code
Refreshing code in the app's controller:
Monitor.ApplicationController = Ember.ArrayController.extend({
itemController: 'process',
sortProperties: ['name'],
sortAscending: true,
intervalId: undefined,
startRefreshing: function() {
var self = this;
if (self.get('intervalId')) {
return;
}
self.set( 'intervalId', setInterval(function() {
self.store.find('process');
}, 120000 ));
}
});
View: Process.hbs
<div {{bind-attr class=":inline inactive:inactive"}}>
<img {{bind-attr src=icon}} {{bind-attr data-caption=contentText}} class="caption" />
<div class="counter">{{nbUsers}}</div>
</div>
View: ProcessView
Monitor.ProcessView = Ember.View.extend({
// (...) Various stuff.
didInsertElement: function() {
this.updateTooltip();
},
updateTooltip: function() {
console.log('Inside updateTooltip!');
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
this.$().tooltip({
items: '.caption',
tooltipClass: 'tooltip',
content: function() {
return $(this).data('caption');
},
position: {
my: 'left+15px center',
at: 'right center',
collision: 'flip'
},
show: false,
hide: false
});
}.observes('controller.inactive', 'controller.contentText')
});
Controller: ProcessController
Monitor.ProcessController = Ember.ObjectController.extend({
contentText: function() {
var tooltipContent = '';
this.get('containers').forEach(function(container) {
// Do a lot of things to tooltipContent involving:
// container.get('name')
// container.get('text')
// container.get('size')
// container.get('nbUsers')
// The data-bindattr value refreshes correctly so I cut this out for readability.
return tooltipContent;
}.property('name', 'containers.#each')
});
Edit 1:
Replaced 'containers.#each' by 'contentText' in the observer and added logging.
Here's what I think is happening:
Your tooltip library isn't observing the data-caption attribute. Meaning, when you update the attribute, you have to explicitly tell the library to update the tooltip as well. So although your attribute is updating just fine, the tooltip library isn't actually watching for those updates.
This can be remedied by calling updateTooltip, which you do, in didInsertElement. However, didInsertElement only fires once, when the element is first inserted. It's not called when the content changes.
Those two things combined are, I think, causing your problem. I think that all you need to do is have updateTooltip also observe the controller.contextText property. Then it should be called when the text updates.
So it turns out my codes declares and initialize a tooltip, but once it's done, you can't change the content the same way. Plus it adds unneeded computing anyway.
Thanks to #GJK's answer and that question, I found out what was happening. Turns out you need to set the content of the tooltip to refresh it, not recreate it.
Here is the working code for Ember integration:
Monitor.ProcessView = Ember.View.extend({
// Other stuff
didInsertElement: function() {
this.initTooltip();
},
initTooltip: function() {
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
this.$().tooltip({
items: '.caption',
tooltipClass: 'tooltip',
content: function() {
return $(this).data('caption');
},
position: {
my: 'left+15px center',
at: 'right center',
collision: 'flip'
},
show: false,
hide: false
});
},
updateTooltip: function() {
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
content = this.get('controller').get('contentText');
this.$().tooltip("option", "content", content);
}.observes('controller.contentText')
});
As an added bonus, you can avoid using the data attribute as a buffer now, although I'm not sure why.
$("#source li").draggable({
appendTo: "#destination",
helper: "clone",
connectToSortable: "#destination",
containment: "document"
});
$("#destination").sortable({
items: "li:not(.placeholder)",
connectWith: "li",
placeholder: "dragging-placeholder",
sort: function() {
$(this).removeClass("ui-state-default");
},
over: function() {
$(".placeholder").hide();
},
out: function() {
if ($(this).children(":not(.placeholder)").length === 0) {
$(".placeholder").show();
}
}
});
JSFiddle: http://jsfiddle.net/j9FK5/7/
When I drag a few boxes from the source UL to the target, they become very hard to sort, especially when trying to move to the beginning. Regular sorting works with the same CSS.
I know it's a common problem, but none of the solutions worked in this particular case.
You can change your tolerance option and set it to pointer.
Specifies which mode to use for testing whether the item being moved
is hovering over another item. Possible values:
"intersect": The item overlaps the other item by at least 50%.
"pointer": The mouse pointer overlaps the other item.
Demo: http://jsfiddle.net/Fs772/
I am using JQuery UI's drag and drop for a web application.
I have the following HTML structure:
<div id="list">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
and Javscript:
$('#list').sortable({containment: 'parent'});
When I drag, move, and drop an item, all items are aligned nicely verticially, which I like it.
Now I hope that when I drag and hover an item over another item, the item below can show some visual effects similar to the hoverClass available in JQuery UI's Droppable.
How can I do it?
Thanks and regards!
For the hoverClass you can do something simiar with the over and out methods. The start and stop could also help you.
$('.sortable').sortable({
over : function(){
$(this).addClass('valid');
},
out : function(){
$(this).removeClass('valid');
}
});
As stated before, $(this) points to the current sortable you are hovering on a over typed event.
The most reliable way of implementing sortable hovering with jQuery is as follow:
$('#some-element').sortable({
start: {
ui.item.parent().addClass('sortable-hover');
},
over: {
$('.sortable-hover').removeClass('sortable-hover');
$(this).addClass('sortable-hover');
},
stop: {
ui.item.parent().removeClass('sortable-hover');
}
});
You can add more logic as required.
Hope it helps,
-- José
I hope that's what you are looking for
$('#list').sortable({
containment: 'parent',
start: function() {
$(this).addClass('sortable-hover');
},
over: function() {
$('#list').removeClass('sortable-hover');
$(this).addClass('sortable-hover');
},
stop: function) {
$('#list').removeClass('sortable-hover');
},
});
How the new jQueryUI's tooltip widget can be modified to open the tooltip on click event on certain element's on document, while the others are still showing their tootip on mouseover event. In click-open case the tooltip should be closed by clicking somewhere else on the document.
Is this possible at all?
Using jqueryui:
HTML:
<div id="tt" >Test</div>
JS:
$('#tt').on({
"click": function() {
$(this).tooltip({ items: "#tt", content: "Displaying on click"});
$(this).tooltip("open");
},
"mouseout": function() {
$(this).tooltip("disable");
}
});
You can check it using
http://jsfiddle.net/adamovic/A44EB/
Thanks Piradian for helping improve the code.
This code creates a tooltip that stays open until you click outside the tooltip. It works even after you dismiss the tooltip. It's an elaboration of Mladen Adamovic's answer.
Fiddle: http://jsfiddle.net/c6wa4un8/57/
Code:
var id = "#tt";
var $elem = $(id);
$elem.on("mouseenter", function (e) {
e.stopImmediatePropagation();
});
$elem.tooltip({ items: id, content: "Displaying on click"});
$elem.on("click", function (e) {
$elem.tooltip("open");
});
$elem.on("mouseleave", function (e) {
e.stopImmediatePropagation();
});
$(document).mouseup(function (e) {
var container = $(".ui-tooltip");
if (! container.is(e.target) &&
container.has(e.target).length === 0)
{
$elem.tooltip("close");
}
});
This answer is based on working with different classes. When the click event takes place on an element with class 'trigger' the class is changed to 'trigger on' and the mouseenter event is triggered in order to pass it on to jquery ui.
The Mouseout is cancelled in this example to make everything based on click events.
HTML
<p>
<input id="input_box1" />
<button id="trigger1" class="trigger" data-tooltip-id="1" title="bla bla 1">
?</button>
</p>
<p>
<input id="input_box2" />
<button id="trigger2" class="trigger" data-tooltip-id="2" title="bla bla 2">
?</button>
</p>
jQuery
$(document).ready(function(){
$(function () {
//show
$(document).on('click', '.trigger', function () {
$(this).addClass("on");
$(this).tooltip({
items: '.trigger.on',
position: {
my: "left+15 center",
at: "right center",
collision: "flip"
}
});
$(this).trigger('mouseenter');
});
//hide
$(document).on('click', '.trigger.on', function () {
$(this).tooltip('close');
$(this).removeClass("on")
});
//prevent mouseout and other related events from firing their handlers
$(".trigger").on('mouseout', function (e) {
e.stopImmediatePropagation();
});
})
})
http://jsfiddle.net/AK7pv/111/
I have been playing with this issue today, I figured I would share my results...
Using the example from jQueryUI tooltip, custom styling and custom content
I wanted to have a hybrid of these two. I wanted to be able to have a popover and not a tooltip, and the content needed to be custom HTML. So no hover state, but instead a click state.
My JS is like this:
$(function() {
$( document ).tooltip({
items: "input",
content: function() {
return $('.myPopover').html();
},
position: {
my: "center bottom-20",
at: "center top",
using: function( position, feedback ) {
$( this ).css( position );
$( "<div>" )
.addClass( "arrow" )
.addClass( feedback.vertical )
.addClass( feedback.horizontal )
.appendTo( this );
}
}
});
$('.fireTip').click(function () {
if(!$(this).hasClass('open')) {
$('#age').trigger('mouseover');
$(this).addClass('open');
} else {
$('#age').trigger('mouseout');
$(this).removeClass('open');
}
})
});
The first part is more or less a direct copy of the code example from UI site with the addition of items and content in the tooltip block.
My HTML:
<p>
<input class='hidden' id="age" />
Click me ya bastard
</p>
<div class="myPopover hidden">
<h3>Hi Sten this is the div</h3>
</div>
Bacially we trick the hover state when we click the anchor tag (fireTip class), the input tag that holds the tooltip has a mouseover state invoked, thus firing the tooltip and keeping it up as long as we wish... The CSS is on the fiddle...
Anyways, here is a fiddle to see the interaction a bit better:
http://jsfiddle.net/AK7pv/
This version ensures the tooltip stays visible long enough for user to move mouse over tooltip and stays visible until mouseout. Handy for allowing the user to select some text from tooltip.
$(document).on("click", ".tooltip", function() {
$(this).tooltip(
{
items: ".tooltip",
content: function(){
return $(this).data('description');
},
close: function( event, ui ) {
var me = this;
ui.tooltip.hover(
function () {
$(this).stop(true).fadeTo(400, 1);
},
function () {
$(this).fadeOut("400", function(){
$(this).remove();
});
}
);
ui.tooltip.on("remove", function(){
$(me).tooltip("destroy");
});
},
}
);
$(this).tooltip("open");
});
HTML
Test
Sample: http://jsfiddle.net/A44EB/123/
Update Mladen Adamovic answer has one drawback. It work only once. Then tooltip is disabled. To make it work each time the code should be supplement with enabling tool tip on click.
$('#tt').on({
"click": function() {
$(this).tooltip({ items: "#tt", content: "Displaying on click"});
$(this).tooltip("enable"); // this line added
$(this).tooltip("open");
},
"mouseout": function() {
$(this).tooltip("disable");
}
});
jsfiddle
http://jsfiddle.net/bh4ctmuj/225/
This may help.
<!-- HTML -->
Click me to see Tooltip
<!-- Jquery code-->
$('a').tooltip({
disabled: true,
close: function( event, ui ) { $(this).tooltip('disable'); }
});
$('a').on('click', function () {
$(this).tooltip('enable').tooltip('open');
});