I'm needing to pass different values delay for show and hide attributes to a popover, and I'm needing an HTML attribute solution. I've tested this code and it works passing an string in data-delay attribute. I'm using Bootstrap 3.
<span style="white-space: nowrap;" data-toggle="popover" data-delay="1000" data-trigger="hover" data-html="true" data-content="content of my popover>
How can I pass different values for show and hide delays using HTML attributes?
Thanks in advance!
You can use the data-delay attribute, however this will set both the 'show' and 'hide' time delays. If you wish to set them individually you'll need to configure the popover. With jQuery you can easily do so:
$(function() {
// This will enable and configure all popovers present in the page
$('[data-toggle="popover"]').popover({
delay: {
"show": 500,
"hide": 100
}
})
})
.container {
padding-top: 40px;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<div class="container">
<a tabindex="0" class="btn btn-lg btn-success" role="button" data-toggle="popover" data-trigger="focus" title="Dismissible popover" data-content="And here's some amazing content. It's very engaging. Right?">click me</a>
</div>
You can pass a number or an object. Therefore, you can specify 'show' and 'hide' delays like this :
<span
data-toggle="popover"
data-delay="{'show':0, 'hide':200}"
data-trigger="hover"
data-html="true"
data-content="content of my popover"
>
TEST
</span>
for Bootstrap v5, you can instantiate it like this:
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => {
if (el.hasAttribute('data-bs-delay-show')) {
return new Tooltip(el, {
delay: {
show: el.getAttribute('data-bs-delay-show'),
hide: el.getAttribute('data-bs-delay-hide') || 0,
},
});
}
return new Tooltip(el);
});
and then use data-bs-delay-show and data-bs-delay-hide attributes on the element.
Related
EDIT:
I implemented some logic to hide my icons and how them only when a specific row from parent component is on mouseover. I need to adjust this logic to my project. Changing global styles is unfortunately unacceptable in my project :(
I tried to implement it with Subject, but now instead of current row, all rows are affaected and all icons are shown. Is it possible to use these Subject Operator logic and show icons only on curretnly hovered row?
This is now my parent component HTML:
<ng-container *ngIf="!emptyList else emptyListTemplate">
<tr requestRow *ngFor="let request of requests"
(mouseenter)="emitEventToChild(true)"
(mouseleave)="emitEventToChild(false)"
[isRequestRowHighlighted]="eventsSubject.asObservable()"
[attr.data-cy-request-id]="request.id"
[request]="request"
[actionable]="true"
[isRequest]="isRequestsList"
(delete)="deleteRequest($event)"
appMemoTooltip>
</tr>
</ng-container>
This is the TS part:
isMouseEnter: boolean
eventsSubject: Subject<boolean> = new Subject<boolean>();
emitEventToChild(e: boolean) {
this.eventsSubject.next(e)
}
private filterSubscription: Subscription
This is my child component HTML (its selector is 'tr[requestRow]' )
<td *ngIf="actionable" class="p-auto text-center actions" (mouseenter)="memoControls.pause()" (mouseleave)="memoControls.resume()">
<div class="d-flex align-items-center justify-content-end" [ngClass]="{'invisible': !isMouseEnter}">
<button
*ngIf="preferredEditType"
type="button" class="btn btn-primary bg-transparent border-0"
title="Edit"
data-cy-id="cy-btn-edit"
(click)="load($event, request, isRequest, preferredEditType)">
<i class="icon-edit-request"></i>
</button>
<button *ngIf="hateoas.supports(request, 'details')"
type="button" class="btn btn-success bg-transparent border-0"
title="Reuse"
data-cy-id="cy-btn-reuse"
(click)="load($event, request, isRequest, requestOperationType.REUSE)">
<i class="icon-copy"></i>
</button>
<button *ngIf="hateoas.supports(request, 'delete')"
type="button" class="btn btn-danger bg-transparent border-0"
title="Delete"
data-cy-id="cy-btn-delete"
(click)="deleteRequest($event)">
<i class="icon-trash"></i>
</button>
</div>
This is the TS file:
#Input() isRequestRowHighlighted: Observable<boolean>
isMouseEnter: boolean
ngOnInit(): void {
this.eventsSubscription = this.isRequestRowHighlighted.subscribe(value => this.isMouseEnter = value)}
enter code here
ngOnDestroy(): void {
this.eventsSubscription.unsubscribe();
}
Expected Result
As is now
Please, let me know how can I achieve displaying icons only for current(on mouseenter) row, not for all of them.
Thank you.
the .css to mannage two differents components should be global, so try in styles.css
tr[requestRow] button {
visibility: hidden;
}
tr[requestRow]:hover button{
visibility: visible;
}
A Simple stackblitz
Update
Well, we can use a ViewEncapsulation.None, who apply all the .css in our component in a way global.
#Component({
selector: [requestRow]
...
encapsulation:ViewEncapsulation.None,
})
But be carefull, if in our component we use also e.g. h1{color:red} this style is also propagate to all our aplication
Another way (but is marked as deprecated) is using some like (in parent.css)
:host ::ng-deep tr[hello] button {
visibility:hidden
}
:host ::ng-deep tr[hello]:hover button{
visibility:visible
}
I have this button, I need to add Pendo Data that is dynamically working based on which button we chose. Mostly this is making the Button unique. When I have a button that is not changing I add like this:
<button mat-button
data-pendo="pendo-prospects-send-application"
class='round-button'
color='primary'
type='button'
.....>
</button>
But sometime I need to add this data to one button that is changing based on CSS class. I am not sure how check for that.
For example I need to add to a button when :
if [class.fa-pencil] then data-pendo "Something"
if [class.fa-plus] then data-pendo "Something else"
This is the button that changes base on class:
<button mat-button
class='round-button'
type='button'
[class.disabled-button]='GuidId'
color='primary'
(click)='onAssignLoanOfficer()'>
<i class='fal'
[class.fa-pencil]='GuidId'
[class.fa-plus]='!GuidId'></i>
</button>
How I can do that?
Based on your comments I think this is what you want to do:
<button
(click)="onAssignLoanOfficer()"
[class.disabled-button]="GuidId"
[attr.data-pendo]="GuidId ? 'pendo-edit-loan' : 'pendo-add-loan'"
class="round-button"
color="primary"
type="button">
<i [class.fa-pencil]="GuidId"
[class.fa-plus]="!GuidId"
class="fall">
</i>
</button>
ALTERNATIVE:
As a more sophisticated alternative (I really don't know how you intend to use what you're asking for), you can build a directive to add the attribute you want based on a map of class-to-pendo-data conversion information:
#Directive({
selector: '[addPendoData]'
})
export class AddPendoDataDirective implements AfterViewInit {
constructor(private _el: ElementRef, private _renderer: Renderer2) {}
ngAfterViewInit() {
const pendoData: string | null | undefined = this._getPendoValue();
if (!pendoData) { return;}
const $button: HTMLElement = this._el.nativeElement;
this._renderer.setAttribute($button, 'data-pendo', pendoData);
}
private _getPendoValue() {
const $child: HTMLElement = this._el.nativeElement;
if(!$child) { return null; }
const $i: HTMLElement = $child.querySelector('i');
if(!$i) { return null; }
const listOfClasses: string[] = $i.className.split(' ');
if (!(listOfClasses && listOfClasses.length)) { return null; }
for(const className of listOfClasses) {
if(PENDO_MAP[className]) { return PENDO_MAP[className]; }
}
return null;
}
}
const PENDO_MAP: { [className: string]: string } = {
'fa-pencil': 'pendo-edit-loan',
'fa-plus': 'pendo-add-loan'
// add other mappings here...
};
and you can use it like this:
<button
(click)="onAssignLoanOfficer()"
[class.disabled-button]="GuidId"
addPendoData
class="round-button"
color="primary"
type="button">
<i [class.fa-pencil]="GuidId"
[class.fa-plus]="!GuidId"
class="fall">
</i>
</button>
I've put together this stackblitz demo.
You could define a directive, as julianobrasil suggests.
I want to point a different way to achieve this using Angular templates.
Define two buttons, addition and edition, separately.
Put a default where you want to be rendered
<div class="action-button" *ngIf="GuidId">
<!-- Add button -->
<button mat-button
data-pendo="pendo-add-loan"
(click)="add(...)"
class="round-button"
color="primary">
<i class="fal fa-plus"></i>
</button>
</div>
Then, define a ng-template tag with the other button definition. A completely fresh new.
<ng-template #edit-button>
<div class="action-button">
<!-- Edit button -->
<button mat-button
(click)="edit(...)"
data-pendo="pendo-edit-loan"
class="round-button"
color="primary">
<i class="fal fa-pencil"></i>
</button>
</div>
</ng-template>
Finally, just change the *ngIf statement to render either an addition button or an edition one.
<div class="action-button" *ngIf="!GuidId else edit-button">
<!-- Add button here -->
</div>
This is a way that scales in order to keep components isolated. The buttons are not related anymore, so you can implement w/o having to condition every style, action, etc.
Hope it helps.
How can I set the icon of the grid button to aria-hidden="true"?
$("#grid").kendoGrid({
toolbar: ["excel"],
excel: {
allPages: true
},
dataSource: {
transport: {
read: {
url: "https://demos.telerik.com/kendo-ui/service/products",
dataType: "jsonp"
}
},
pageSize: 10
},
pageable: true
});
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2020.1.219/styles/kendo.default-v2.min.css"/>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2020.1.219/js/jszip.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2020.1.219/js/kendo.all.min.js"></script>
<div id="grid"></div>
Current html:
<div class="k-header k-grid-toolbar"><a role="button" class="k-button k-button-icontext k-grid-excel" href="#"><span class="k-icon k-i-file-excel"></span>Export to excel</a></div>
Desired result:
<div class="k-header k-grid-toolbar"><a role="button" class="k-button k-button-icontext k-grid-excel" href="#"><span aria-hidden="true" class="k-icon k-i-file-excel"></span>Export to excel</a></div>
The icon has class k-i-file-excel. Use that class to select the element and set the attribute:
$("#grid .k-i-file-excel").attr("aria-hidden","true");
You don't need to do anything.
Test your application with a keyboard and screen reader. Since you're not modifying tab indices, either the outer <a> tag will get the focus (and should be correctly announced as "Export to excel"), or nothing will. Your user will know what the button is for.
My tooltips are working on the mainpage perfectly. In a modal which is generated later by an ajax call the tooltips won't work.
I have included the following code inside the generated modal (result of the ajax call).
To re-ini the tooltips
<script>
$('.tooltips').tooltip();
</script>
In the html of the modal
<button class="btn btn-lg default tooltips blue-madison" type="submit"
name="O" data-container="body" data-placement="top"
data-original-title="THIS TEXT FOR TOOLTIPS">
<i class="fa fa-industry blue-madison"></i> BUTTON1
</button>
<button class="btn btn-lg default tooltips green-jungle" type="submit"
name="P" data-container="body" data-placement="top"
data-original-title="THIS TEXT FOR TOOLTIPS">
<i class="fa fa-user green-jungle "></i> BUTTON2
</button>
Why don't the tooltips show- what I'm doing wrong?
The issue is because of the z-index of modal and tooltip. You can try this,
.tooltip {
z-index: 100000000;
}
Probably it's because you should call $('.tooltips').tooltip(); after the modal's content have been inserted in the document.
Otherwise, please post a fiddle with your current code where we can test it.
Another solution is to bind the tooltip to the modal using the container option:
$('#modal').on('shown.bs.modal', function() {
console.log("modal show");
$('.tooltips').tooltip({
container: $(this)
});
});
Maybe this helps someone: I had a case when needed with ajax to populate & display a bootstrap modal (render view) on click (calling showModal(url, event) below); bootstrap tooltip and also fengyuanchen/datepicker were unresponsive, so I managed to trigger them after detecting modal loading, like this:
function showModal(url, event) {
$.when(
$.ajax({
url: url,
method: 'GET',
success: function (data) {
$('#modal-wrapper').html(data);
}
})
).then(function() {
$('.loaded_modal').modal().on('shown.bs.modal', function() {
$('[data-toggle="datepicker"]').datepicker({
format: "dd/mm/yyyy",
autoclose: true,
todayHighlight: true,
zIndex: 1070,
container: '.modal'
});
$('.modal [data-toggle="tooltip"]').tooltip({trigger: 'hover'});
// could also be on click {trigger: 'hover click'}
});
});
If you are using react I had success with a different answer. All you have to
do is give the parent container a ref and then in the overlayTrigger component you just have to pass in the ref as a param to the container.
import React, { Component } from 'react';
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
class random extends Component {
constructor(props) {
super(props);
this.ref= React.createRef()
}
render() {
return (
<div ref={this.ref}>
<OverlayTrigger
placement="top"
container={this.ref}
overlay={
<Tooltip data-container="body">Some text</Tooltip>
}
>
<span className="d-inline-block">
<i className="mdi mdi-help-circle pointer"></i>
</span>
</OverlayTrigger>
</div>
);
}
}
Best way to fix this behaviour is by adding this prop inside your md-tooltip:
md-z-index="9999"
or a different z-index.
No need to hardcode this in the css.
You can also define the z-index in your scope variable inside your controller as the following
// in controller
$scope.btnOptions = {
isOpen:false,
label: 'test button',
class: 'md-scale',
zIndex: 99999
};
in you html ( normally I would use {{}} to print the variable, but I'm on laravel so I used <% %> instead
<md-button aria-label="Édit" class="md-fab md-raised md-mini">
<md-tooltip md-direction="top" md-z-index="<% btnOptions.zIndex %>">Mode édition</md-tooltip>
<i class="far fa-edit"></i>
</md-button>
I am trying to display HTML inside a bootstrap popover, but somehow it's not working. I found some answers here but it won't work for me. Please let me know if I'm doing something wrong.
<script>
$(function(){
$('[rel=popover]').popover({
html : true,
content: function() {
return $('#popover_content_wrapper').html();
}
});
});
</script>
<li href="#" id="example" rel="popover" data-content="" data-original-title="A Title">
popover
</li>
<div id="popover_content_wrapper" style="display: none">
<div>This is your div content</div>
</div>
You cannot use <li href="#" since it belongs to <a href="#" that's why it wasn't working, change it and it's all good.
Here is working JSFiddle which shows you how to create bootstrap popover.
Relevant parts of the code is below:
HTML:
<!--
Note: Popover content is read from "data-content" and "title" tags.
-->
<a tabindex="0"
class="btn btn-lg btn-primary"
role="button"
data-html="true"
data-toggle="popover"
data-trigger="focus"
title="<b>Example popover</b> - title"
data-content="<div><b>Example popover</b> - content</div>">Example popover</a>
JavaScript:
$(function(){
// Enables popover
$("[data-toggle=popover]").popover();
});
And by the way, you always need at least $("[data-toggle=popover]").popover(); to enable the popover. But in place of data-toggle="popover" you can also use id="my-popover" or class="my-popover". Just remember to enable them using e.g: $("#my-popover").popover(); in those cases.
Here is the link to the complete spec:
Bootstrap Popover
Bonus:
If for some reason you don't like or cannot read content of a popup from the data-content and title tags. You can also use e.g. hidden divs and a bit more JavaScript. Here is an example about that.
you can use attribute data-html="true":
<a href="#" id="example" rel="popover"
data-content="<div>This <b>is</b> your div content</div>"
data-html="true" data-original-title="A Title">popover</a>
Another way to specify the popover content in a reusable way is to create a new data attribute like data-popover-content and use it like this:
HTML:
<!-- Popover #1 -->
<a class="btn btn-primary" data-placement="top" data-popover-content="#a1" data-toggle="popover" data-trigger="focus" href="#" tabindex="0">Popover Example</a>
<!-- Content for Popover #1 -->
<div class="hidden" id="a1">
<div class="popover-heading">
This is the heading for #1
</div>
<div class="popover-body">
This is the body for #1
</div>
</div>
JS:
$(function(){
$("[data-toggle=popover]").popover({
html : true,
content: function() {
var content = $(this).attr("data-popover-content");
return $(content).children(".popover-body").html();
},
title: function() {
var title = $(this).attr("data-popover-content");
return $(title).children(".popover-heading").html();
}
});
});
This can be useful when you have a lot of html to place into your popovers.
Here is an example fiddle: http://jsfiddle.net/z824fn6b/
You need to create a popover instance that has the html option enabled (place this in your javascript file after the popover JS code):
$('.popover-with-html').popover({ html : true });
I used a pop over inside a list, Im giving an example via HTML
<a type="button" data-container="body" data-toggle="popover" data-html="true" data-placement="right" data-content='<ul class="nav"><li><a href="#">hola</li><li><a href="#">hola2</li></ul>'>
You only need put data-html="true" in the link popover. Is gonna work.
This is an old question, but this is another way, using jQuery to reuse the popover and to keep using the original bootstrap data attributes to make it more semantic:
The link
<a href="#" rel="popover" data-trigger="focus" data-popover-content="#popover">
Show it!
</a>
Custom content to show
<!-- Let's show the Bootstrap nav on the popover-->
<div id="list-popover" class="hide">
<ul class="nav nav-pills nav-stacked">
<li>Action</li>
<li>Another action</li>
<li>Something else here</li>
<li>Separated link</li>
</ul>
</div>
Javascript
$('[rel="popover"]').popover({
container: 'body',
html: true,
content: function () {
var clone = $($(this).data('popover-content')).clone(true).removeClass('hide');
return clone;
}
});
Fiddle with complete example:
http://jsfiddle.net/tomsarduy/262w45L5/
This is a slight modification on Jack's excellent answer.
The following makes sure simple popovers, without HTML content, remain unaffected.
JavaScript:
$(function(){
$('[data-toggle=popover]:not([data-popover-content])').popover();
$('[data-toggle=popover][data-popover-content]').popover({
html : true,
content: function() {
var content = $(this).attr("data-popover-content");
return $(content).children(".popover-body").html();
},
title: function() {
var title = $(this).attr("data-popover-content");
return $(title).children(".popover-heading").html();
}
});
});
On the latest version of bootstrap 4.6, you might also need to use sanitize:false for adding complex html.
$('.popover-with-html').popover({ html : true, sanitize : false })
I really hate to put long HTML inside of the attribute, here is my solution, clear and simple (replace ? with whatever you want):
<a class="btn-lg popover-dismiss" data-placement="bottom" data-toggle="popover" title="Help">
<h2>Some title</h2>
Some text
</a>
then
var help = $('.popover-dismiss');
help.attr('data-content', help.html()).text(' ? ').popover({trigger: 'hover', html: true});
You can change the 'template/popover/popover.html' in file 'ui-bootstrap-tpls-0.11.0.js'
Write: "bind-html-unsafe" instead of "ng-bind"
It will show all popover with html.
*its unsafe html. Use only if you trust the html.
For Bootstrap >= 5.2
To enable HTML content in Popovers: data-bs-html="true"
Example:
<a href="#"
data-bs-toggle="popover"
data-bs-title="A Title"
data-bs-html="true"
data-bs-content="This is <strong>bold</strong>">popover</a>
Doc: https://getbootstrap.com/docs/5.3/components/popovers/#options
You can use the popover event, and control the width by attribute 'data-width'
$('[data-toggle="popover-huongdan"]').popover({ html: true });
$('[data-toggle="popover-huongdan"]').on("shown.bs.popover", function () {
var width = $(this).attr("data-width") == undefined ? 276 : parseInt($(this).attr("data-width"));
$("div[id^=popover]").css("max-width", width);
});
<a class="position-absolute" href="javascript:void(0);" data-toggle="popover-huongdan" data-trigger="hover" data-width="500" title="title-popover" data-content="html-content-code">
<i class="far fa-question-circle"></i>
</a>
Actually if you're using Bootstrap5 with Django then their method of passing in content as a string is perfect and in line with Django's template inclusion. You can create a template file with whatever partial HTML that you need, so for example, there is not X-editable for Bootstrap5 that seems to work, so maybe you'd want to make a line edit together with Ok|Cancel buttons as content. Anyway, this is what I mean:
<button data-bs-content="{% include './popover_content.html' %}" type="button" class="btn btn-lg btn-danger" data-bs-toggle="popover" title="Popover title" >
Click to toggle popover
</button>
Where my settings.py templates section looks like this:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True, # True is necessary for django-bootstrap5 to work!
'OPTIONS': {
'debug': True,
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
I keep my templates (of every single app) in a <project dir>/templates/<app name> folder. I have MyMainApp/popover_content.html right beside MyMainApp/home.html wher the above example code was tested. But if you keep your templates in each app's Django folder, then you'll need to add "MyApp/templates" to the TEMPLATES[0]{'DIRS': ['MyApp/templates', 'MyApp2/templates']} list.
So at least this will give you the ability to put your popover HTML in the usual, syntax-highlighted Django template format, and makes good use of modularizaton of your Django template into components.
I'm personally going to use it to make an editable label (title and description fields of some data in my app).
One drawback is that if you use doublequotes (") when including: "{% include './popover_content.html' %}", then you must use single quotes all throughout the popover_content.html` template.
You also need to enable html for popovers, so your site-wide popover initializer would go:
<script type="text/javascript">
$(document).ready(() => {
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))
var popoverList = popoverTriggerList.map(
function (popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl, {
html: true,
});
});
});
</script>
Here is the (unstyled) result. In conclusion, use the default-provided string method of passing in, and pass in an included Django template file. Problem solved!