I have two button + and - . When I click on + button I am adding one div in parent div and want to show tooltip on that div when I click again on + button then I am adding again one div and want to show tooltip on second div only. It's same for upto 7 div.
Currently I am doing same but when I add more than one div tooltip will not hide for previous button and will still there. So at end I am seeing all 7 tooltip but I supposed to see last div tooltip only.
I tried to hide it after some delay but even it's not working.
Here is my code.
function init(){
for(var divCount = 1; divCount <= fanSpeed; divCount++){
$('#temperature_bar').append('<div style="float:left" data-tooltip-id="'+divCount+'" id="speed_"'+divCount +'" class="trigger climate-fan-bar" onclick="\buttonTempraturePressed(this.id)\" title="<div class="row row-thumbnail" id="box-search"><div class="thumbnail text-center"><img width="50" height="50" src="images/fan_speed_bg_center_popup.png" class="img-responsive"><div class="caption"><span class="tooltip-text-size">' + divCount + '</span></div></div></div></div>' );
showTooltips("speed_"+divCount);
}
}
function showTooltips(clicked_id){
//show
$(clicked_id).on('click', '.trigger', function () {
$(this).addClass("on");
$(this).tooltip({
hide: { effect: "flip", duration: 1000 },
items: '.trigger.on',
position: {
my: "top",
at: "top",
collision: "flip"
}
});
$(this).trigger('mouseenter');
});
/*$(clicked_id).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();
});
}
Here is an possible solution. Making use of the items and content options, you can adjust the content instead of trying to pass it via title attribute.
Working Example: https://jsfiddle.net/Twisty/cfd6z8db/
HTML
<div style="padding:20px; display: block;">
<div id="temperature_bar">
</div>
</div>
<div style="padding:20px; display: block;">
<label>Speed</label>
<button id="decSpeed" title="Decrease">-</button>
<button id="incSpeed" title="Increase">+</button>
</div>
CSS
.item {
border-style: solid;
border-width: 1px 1px 1px 0;
border-color: #ccc;
padding: .25em .5em;
cursor: pointer;
}
.item:nth-child(1) {
border-left-width: 1px;
}
.row-thumbnail .caption {
width: 100%;
text-align: center;
}
jQuery
function showToolTips(obj) {
if (obj.hasClass("on")) {
// Hide ToolTip
obj.removeClass("on");
obj.tooltip("close");
} else {
// Show ToolTip
obj.addClass("on");
obj.tooltip("open");
}
}
function addItem() {
var divCount = $(".item").length + 1;
if (divCount == 8) {
return false;
}
var img = "https://dummyimage.com/50x50/000000/fff";
var item = $("<div>", {
id: "speed-" + divCount,
class: "trigger item",
"data-tip-content": img + "|" + divCount,
"data-tip-id": divCount,
})
.css("float", "left");
item.html(divCount);
item.tooltip({
disabled: true,
hide: {
effect: "flip",
duration: 1000
},
position: {
my: "center bottom+5",
at: "center top",
collision: "flip"
},
items: "[data-tip-content]",
content: '<div class="row row-thumbnail" id="box-search"><div class="thumbnail text-center"><img width="50" height="50" src="' + item.data("tip-content").split("|")[0] + '" class="img-responsive"><div class="caption"><span class="tooltip-text-size">' + item.data("tip-content").split("|")[1] + '</span></div></div>'
});
$('#temperature_bar').append(item);
}
// Make Items
function init() {
var c = 5;
var divCount = 1;
for (divCount; divCount <= c; divCount++) {
var item = $("<div>", {
id: "speed-" + divCount,
class: "trigger item",
"data-tip-content": "https://dummyimage.com/50x50/000000/fff" + "|" + divCount,
"data-tip-id": divCount,
})
.css("float", "left");
item.html(divCount);
item.tooltip({
disabled: true,
hide: {
effect: "flip",
duration: 1000
},
position: {
my: "center bottom+5",
at: "center top",
collision: "flip"
},
items: "[data-tip-content]",
content: '<div class="row row-thumbnail" id="box-search"><div class="thumbnail text-center"><img width="50" height="50" src="' + item.data("tip-content").split("|")[0] + '" class="img-responsive"><div class="caption"><span class="tooltip-text-size">' + item.data("tip-content").split("|")[1] + '</span></div></div>'
});
$('#temperature_bar').append(item);
}
}
$(function() {
init();
$(".trigger").on('mouseout', function(e) {
if ($(this).hasClass("on")) {
$(this).removeClass("on");
$(this).tooltip("close");
}
});
$("#temperature_bar").on("click", ".trigger", function() {
console.log("Click Triggered. Executing 'showToolTips()'.");
showToolTips($(this));
});
$("#decSpeed").click(function() {
$("#temperature_bar .item").last().remove();
});
$("#incSpeed").click(addItem);
});
When using a position like { my: "top", at: "top", collision: "flip" }, this caused some type of weird loading issue. I used a different position and it seemed to clear the issue.
You post did not give a very strong example, so I created some example buttons. the disable option was also helpful, this ensured that they didn't display on mouseover events. It also allows us to control the open and close.
I packaged all the content items into a data attribute. I separated it with a pipe (|) so that it can all be one spot, but easily worked with later.
Click a button, and the tip appears. Click it again, and it hides. Same if you move the mouse away.
If you need more info, please update your post with a better example.
I would simply execute
$(".ui-tooltip-content").hide();
to:
function showTooltips(clicked_id){
$(".ui-tooltip-content").hide(); // Clean up prior tips
//show
$(clicked_id).on('click', '.trigger', function () {
$(this).addClass("on");
$(this).tooltip({
...
hth
Related
I need to show a tooltip which is a Html list on hover.
I can show the date highlighted and a simple message but the list wont show at all. It has to do with the bootstrap. If I remove bootstrap then it shows but I need bootstrap in the app. Is there any way to show a list in a tooltip on hover with bootstrap?
Here is the code
export class DatepickerDateClassExample {
list: string =
"Date - (3)<br/>" +
"Names - (4)<br/>" +
"Addresses - (25)<br>" +
"Values - (30)";
constructor(private renderer: Renderer2) {}
dates = [
{ date: "2020-04-20", text: this.list }
];
dateClass = (d: Date) => {
const dateSearch = this.dateToString(d);
return this.dates.find(f => f.date == dateSearch)
? "example-custom-date-class"
: undefined;
};
displayMonth() {
let elements = document.querySelectorAll(".endDate");
let x = elements[0].querySelectorAll(".mat-calendar-body-cell");
x.forEach(y => {
const dateSearch = this.dateToString(
new Date(y.getAttribute("aria-label"))
);
const data = this.dates.find(f => f.date == dateSearch);
if (data) y.setAttribute("aria-label", data.text);
});
}
streamOpened(event) {
setTimeout(() => {
let buttons = document.querySelectorAll("mat-calendar .mat-icon-button");
buttons.forEach(btn =>
this.renderer.listen(btn, "click", () => {
setTimeout(() => {
//debugger
this.displayMonth();
});
})
);
this.displayMonth();
});
}
dateToString(date: any) {
return (
date.getFullYear() +
"-" +
("0" + (date.getMonth() + 1)).slice(-2) +
"-" +
("0" + date.getDate()).slice(-2)
);
}
Css:
::ng-deep .example-custom-date-class {
background: orange;
border-radius: 100%;
}
.tooltip
{
display: none;
position: absolute;
text-align: center;
margin-top: 30px;
width: 155px;
padding: 10px;
z-index: 2000;
box-shadow: 0px 0px 4px #222;
border-radius: 10px;
background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #eeeeee),color-stop(1, #cccccc));
background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc);
color: gray;
}
.tooltip:before {
content: '';
display: block;
position: absolute;
left: 10px;
top: -20px;
width: 0;
height: 0;
border: 9px solid transparent;
border-bottom-color: #cccccc;
}
Html:
<mat-form-field class="example-full-width" >
<input matInput [matDatepicker]="picker" placeholder="Choose a date">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker (opened)="streamOpened($event)" [dateClass]="dateClass" #picker panelClass="endDate" ></mat-datepicker>
</mat-form-field>
<div #toolTip class="tooltip" (mouseover)="onTool=true"
(mouseout)="onTool=false"
[style.display]="show || onTool?'inline-block':'none'" [innerHTML]="toolTipMessage">
</div>
Here is the stackblitz
I'm afraid that you can not use a simple css, because content only admit \A to make a break line but it's not possible using attr -it's possible indicate que \A as string in the content- (and don't allow .html)
Well, we can take another aproach that is use a div that make as tooltip and use renderer to listen mouseout and mouseover
If our div is like
<div #toolTip class="tooltip"
(mouseover)="onTool=true"
(mouseout)="onTool=false"
[style.display]="show || onTool?'inline-block':'none'"
[innerHTML]="toolTipMessage">
</div>
And has two variables and get the div using ViewChild
#ViewChild('toolTip') tool:ElementRef
show:boolean=false;
onTool:boolean=false;
We can change our function displayMonth to add the mouseover and mouse out
displayMonth() {
let elements = document.querySelectorAll(".endDate");
let x = elements[0].querySelectorAll(".mat-calendar-body-cell");
x.forEach(y => {
const dateSearch = this.dateToString(
new Date(y.getAttribute("aria-label"))
);
const data = this.dates.find(f => f.date == dateSearch);
if (data) {
this.renderer.listen(y, "mouseover", () => this.showTool(y, data.text));
this.renderer.listen(y, "mouseout", () => this.hideTool());
}
});
}
showTool(y, data) {
this.show = true;
this.toolTipMessage = data;
this.renderer.setStyle(
this.tool.nativeElement,
"top",
y.getBoundingClientRect().y+ "px"
);
this.renderer.setStyle(
this.tool.nativeElement,
"left",
y.getBoundingClientRect().x + "px"
);
}
hideTool() {
this.show = false;
}
See the stackblitz
You just need to set the tooltip's opacity to 1. Bootstrap sets tooltip's classes opacity to 0 by default.
.tooltip
{
/*.... */
opacity: 1;
}
You could also just change your class name and not use tooltip.
Modified stackblitz
Explanation
If you use native bootstrap js, you normally need to call the .tooltip('show') method on the element for which the tooltip should appear. This will in turn change the opacity of the tooltip element.
Here, it looks like you are just using the css part of bootstrap, not the js lib, so you need to change the opacity yourself.
Note: using bootstrap's js requires jquery, which is not recommended in angular projects. There are some like libraries out there which provide bootstrap components for angular without requiring jquery, like ngx-bootstrap
Edit
Just for info, if you really wanted to use jquery and bootstrap for your tooltip, have a look at this stackblitz example.
Basically, you just call tooltip on the calendar dates and pass the text to display. Bootstrap will handle hiding/showing and positionning of the tooltip.
$(y).tooltip({'title': data.text, html: true});
I am using Vue to create a web app in which it is possible to create new divs (one at the time) with a button click. It is also possible to minimize these divs. It's isn't these divs that are changing size, but it needs to be this way because of functionality I cant reveal here. You can visit this jsFiddle to see it in action: jsFiddle.
If you click on the Increase button it will be possible to increase the limitation of divs that it is possible to generate on the website. If you click on the button the div will "change size".
There are some limitations though that I haven't been able to solve yet. The most important issue is that I want it to be possible to change the size of the divs, on at the time. How do I do that? It must be possible to handle several divs this way.
I have thought of placing them in an array like you can find in this: example. I think that it would also help me target some selected "small" divs for other functions with help of the index. In one case in need to select all minimized divs but the first one. Is an array the best way to get the functionality I have revealed?
Here is my progress so far... This code is not working in its present shape. The goal is to make it have the same functionality as in the codePen example, but still be able to the same things as the code in the jsFiddle.
If you prefer, visit this jsFiddle in which you can find this code:
HTML
<div id="lotsOfDivs">
<addingdivs></addingdivs>
</div>
Vue.js
var gate = 0; // This global variable is used to increase the limitation of divs to be generated.
var expArray=[]; //The array where I want to place the "small divs"
$(document).ready(function(){
$(".expandable").each(function(){ displayDiv.push($(this));});
});
Vue.component('addingdivs', {
template: `
<div>
<div id="header">
<button class="addDiv" type="button" #click="createDiv">ADD LOCATION</button>
</div>
<div id=parent v-for="n in count" :style="{ 'height': height}">
<div id="big" v-for="(item, i) in displayDiv" v-if="expand(i)>
<div class="firstChild">
<button class="done" #click="increaseLimit">INCREASE</button>
</div>
<div class="secondChild">
<button class="done" #click="expand">EXPAND</button>
</div>
</div>
<div id="smal" v-for="(item, i) in displayDiv" v-if="expand(i)">
<button class="done" #click="expand">EXPAND</button>
</div>
</div>
</div>
`,
data: function() {
return {
displayDiv: [false],
gate: gate,
height: "",
count: 0,
i:0,
}
},
methods: {
expand: function() {
this.$set(this.displayDiv, i, !this.displayDiv[i]);
if (!this.displayDiv) {
this.height = '7vh';
}
else {
this.height = "";
}
},
createDiv: function() {
if (this.count <= gate) { // Here you can decide how many divs that will be generated
this.count++;
}
},
increaseLimit: function() {
// Here you can increase the number of divs that it's possible to generate
gate++;
}
}
});
new Vue({
el: '#lotsOfDivs',
});
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#header {
background: #30BFB7;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
height: 2vh;
margin-bottom: 2vh
}
#big {
background: #207F7A;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
height: 20vh;
margin-bottom: 2vh
}
#smal {
background: #10403D;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
height: 2vh;
padding-bottom: 2vh;
}
You need to pass $event into the function expand. And then in the function get the clicked elements parent.
Here is a working fiddle link:
https://jsfiddle.net/wwf8nwsg/15/
var gate = 0;
Vue.component('addingdivs', {
template: `
<div>
<div id="header">
<button class="addDiv" type="button" #click="createDiv">ADD LOCATION</button>
<button class="done" #click="increaseLimit">INCREASE</button>
</div>
<div class="big" v-for="n in count" :style="{ 'height': height}">
<button class="done" #click="expand($event)">Small</button>
</div>
</div>
</div>
`,
data: function() {
return {
displayDiv: [false],
gate: gate,
height: "",
count: 0,
locationsArr: ["one", "two", "three"],
}
},
methods: {
expand: function(e) {
console.log(e);
console.log(e.originalTarget.parentElement.className);
if (e.originalTarget.parentElement.className == 'big') {
e.originalTarget.parentElement.className = 'small';
e.originalTarget.innerText = 'Big';
} else {
e.originalTarget.parentElement.className = 'big'
e.originalTarget.innerText = 'Small';
}
},
createDiv: function() {
if (this.count <= gate) { // Here you can decide how many divs that will be generated
this.count++;
}
},
increaseLimit: function() {
// Here you can increase the number of divs that it's possible to generate
gate++;
}
}
});
new Vue({
el: '#lotsOfDivs',
});
Linus Borg at Vue.js forum posted a solution to this question! Click here to go to see the solution!
I am trying to create a directive in AngularJS which acts as Input and Select box together. Just like when you type in search textbox a dropdown list popups for assisting user to select. The selection is working fine via mouseclick, but I want my user to use arrow keys to move up and down and select on enter as well. Below is my HTML , CSS and Javascript code. Your quick assistance in this regard will be appreciated.
/*******CSS Code******/
.input-dropdown {
position: relative;
display: inline-block;
}
.input-dropdown .dropdown {
display: none;
position: absolute;
top: 100%;
left: 0;
width: 100%;
margin-top: 2px;
background: #EEE;
}
.input-dropdown .dropdown div {
cursor: pointer;
padding: 2px 5px;
}
.input-dropdown input:focus + .dropdown {
display: block;
}
/*******AngularJS Code*****************/
var app = angular.module('myApp', []);
app.controller('MainCtrl', function ($scope) {
$scope.values = ['Chrome', 'Firefox', 'IE'];
$scope.pick = function (value) {
console.log('Picked', value)
};
});
app.directive('inputDropdown', function ($compile) {
var template =
'<input ng-model="ngModel">' +
'<div class="dropdown">' +
'<div ng-repeat="value in list | filter: ngModel">' +
'<div ng-mousedown="select($event, value)">{{value}}</div>' +
'</div>' +
'</div>';
return {
restrict: 'EA',
scope: {
ngModel: '=',
list: '=',
onSelect: '&'
},
template: template,
link: function (scope, element, attrs) {
element.addClass('input-dropdown');
scope.select = function (e, value) {
scope.ngModel = value;
scope.onSelect({ $event: e, value: value });
};
}
};
});
HTML Code:
<html ng-app="myApp">
<head>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<body ng-controller="MainCtrl">
<input-dropdown ng-model="preference" list="values" on-select="pick(value)"></input-dropdown> {{preference}}
</body>
</html>
I have this code for making a nav bar. I am trying to add image buttons with text below them. The problem is that the images can be of different sizes and thus they are not centered properly in the output.
Also, the title for all images must come at same level but its not the case.
ul.nav-icon {
list-style: none;
display: block;
margin: auto;
width: 800px;
}
ul.nav-icon li {
float: left;
}
ul.nav-icon a {
display: inline-block;
text-decoration: none;
}
ul.nav-icon a:hover {
background: #4095A6;
}
ul.nav-icon img {
margin: 0px 0px 0px 0px;
padding-top: 16px;
padding-left: 30px;
}
.img-box {
width: 160px;
height: 138px;
}
h6 {
color: white;
text-align: center;
}
<ul class="nav-icon">
<li>
<a href="#" class="img-box">
<img src="http://imgur.com/Et4vXHk.png">
<h6>Families</h6>
</a>
</li>
<li>
<a href="#" class="img-box">
<img src="http://i.imgur.com/lubEbTP.png">
<h6>Families</h6>
</a>
</li>
<li>
<a href="#" class="img-box">
<img src="http://i.imgur.com/lubEbTP.png">
<h6>Families</h6>
</a>
</li>
</ul>
Here's a way to deal with your problem: https://github.com/smohadjer/sameHeight
Here's the .js file you'll need to include in your html. It's better if it's an external file. For any confusion, this file can also be found in the link above with both minified/unminified versions.
;(function ($, window, document, undefined) {
'use strict';
var pluginName = 'sameHeight',
defaults = {
oneHeightForAll: false,
useCSSHeight: false
};
//private method
var getHeightOfTallest = function(elms) {
var height = 0;
$.each(elms, function() {
var _h = $(this).outerHeight();
if (_h > height) {
height = _h;
}
});
return height;
};
// The actual plugin constructor
function Plugin(element, options) {
this.$element = $(element);
this.options = $.extend({}, defaults, options);
this.init();
}
// methods
var methods = {
init: function() {
var self = this;
self.index = 0;
self.$elms = self.$element.children();
self.cssProperty = self.options.useCSSHeight ? 'height' : 'min-height';
$(window).on('resize.' + pluginName, function() {
//remove previously set height or min-height
self.$elms.css(self.cssProperty, '');
initSameHeight();
});
//use setTimeout to make sure any code in stack is executed before
//calculating height
setTimeout(function() {
initSameHeight();
}, 0);
function initSameHeight() {
//if there are adjacent elements
if (self.getRow(0).length > 1) {
self.setMinHeight(0);
if (self.options.callback) {
self.options.callback();
}
}
}
},
setMinHeight: function(index){
var self = this;
var row = self.options.oneHeightForAll ? self.$elms : self.getRow(index);
var height = getHeightOfTallest(row);
$.each(row, function() {
$(this).css(self.cssProperty, height);
});
if (!self.options.oneHeightForAll && self.index < self.$elms.length - 1) {
self.setMinHeight(self.index);
}
},
getRow: function(index) {
var self = this;
var row = [];
var $first = self.$elms.eq(index);
var top = $first.position().top;
row.push($first);
self.$elms.slice(index + 1).each(function() {
var $elm = $(this);
if ($elm.position().top === top) {
row.push($elm);
self.index = $elm.index();
} else {
self.index = $elm.index();
return false;
}
});
return row;
},
destroy: function() {
var self = this;
//remove event handlers
$(window).off('resize.' + pluginName);
//remove dom changes
self.$elms.css(self.cssProperty, '');
self.$element.removeData('plugin_' + pluginName);
}
};
// build
$.extend(Plugin.prototype, methods);
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[pluginName] = function(options) {
this.each(function() {
if(!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
}
});
return this;
};
})(jQuery, window, document);
After you include the above .js file, add this script to your current page:
$('.img-box').sameHeight();
This should make all of your boxes with image/text be the same size height wise.
Next in order to make sure the text is always at a certain point within your img-box, add some css inline, or make a class with the css as
h6 {
bottom:10px;
}
The amount of pixels can be anything you'd like it to be. To explain, the text will now always be 10 pixels from the bottom of the img-box.
Either this, or just make the images the background image for the container and set them all to predetermined sizes.
I've made it work by these codes for an addtional title (a new div inside fancybox):
beforeShow: function(){
this.title=$(this.element).data('caption');
this.title2="<div class='photo_exif'>"+$(this.element).data('exif')+"</div>";
$(this.title2)
.bind("contextmenu", function (e) {
return false; /* Disables right click */
})
.prependTo( $.fancybox.inner );
}
and the html is :
<a href='PhotoURL' class='fancybox' data-fancybox-group='gallery' data-caption='PhotoTitle' data-exif='photoTitle2'>pic</a>
now i want this div (div.photo_exif) hover to show or hide, so i added these codes:
afterShow:function() {
$("#fancybox-wrap").hover(function() {
$(".photo_exif").show();
}, function() {
$(".photo_exif").hide();
});
}
but it doesnt work. The div is always show on fancybox. My css is :
.photo_exif {
position: absolute;
bottom: 0;
left: 0;
color: #fff;
width:100%;
height:30px;
background: #000;
background: rgba(0, 0, 0, .8);
}
and my whole fancybox code (with ie6 crack) is :
$('.fancybox').fancybox({
fitToView: false,
mouseWheel: false,
beforeShow: function(){
this.title=$(this.element).data('caption');
this.title2="<div class='photo_exif'>"+$(this.element).data('exif')+"</div>";
$(this.title2)
.bind("contextmenu", function (e) {
return false; /* Disables right click */
})
.prependTo( $.fancybox.inner );
},
afterShow: function(){
if (jQuery.browser.msie && parseInt(jQuery.browser.version, 10) <= 6) {
$("div#fancybox-buttons").css("top", $("html").scrollTop());
$(window).scroll(function () {
$("div#fancybox-buttons").css("top", $("html").scrollTop());
});
}
$("#fancybox-wrap").hover(function() {
$(".photo_exif").show();
}, function() {
$(".photo_exif").hide();
});
}
});
Is there anything wrong?
This one was easy. This line of your code :
$("#fancybox-wrap").hover(function() {
... should be :
$(".fancybox-wrap").hover(function() {
The fancybox selector is a class not an ID