Increase width of column in ui.grid - angularjs

I have inserted some dummy object in Grid,The data displays in the grid found some issues. Here is My code:
html:
<div class="gridStyle" ui-grid="gridOptions"></div>
js:
$scope.myData = [{
JobId: '196',
siteType: 'abc',
Title: 'Happy womans day',
Message: 'hello',
devicetype: 'A',
jobDuration: '819',
totalMsgs: '2016',
msgsDelivered: 'Msg not found In the whole Body',
msgsFailed: '789',
jobCreatedDate: '11-03-2015',
jobCreatedBy: 'abc#abc.com'
}];
$scope.gridOptions = {
data: 'myData'
};
css :
.ui-grid-header-cell .ui-grid-cell-contents {
height: 48px;
white-space: normal;
-ms-text-overflow: clip;
-o-text-overflow: clip;
text-overflow: clip;
overflow: visible;
}
Data displays in the grid but only upto some fixed width. Unable to wrap the long text,
for eg:Msg not found In the whole Body, Displays as Msg not foun...........
How can I increase width of each and every column?
I am not able to wrap the long text lines into 2-3 lines, the whole text displays in one line only
The above css works only for headers

OK, a few things.
Firstly, to set the column width you need to use column definitions, then you can set a width in pixels or percentage on each. Refer http://ui-grid.info/docs/#/tutorial/201_editable as an example that has column widths.
Secondly, there is the ability to add tooltips, which are one way to show longer cells that don't fit in the space available. Refer http://ui-grid.info/docs/#/tutorial/117_tooltips
Thirdly, you can make the rows taller and therefore have space to wrap content within them. Be aware that all rows must be the same height, so you can't make only the rows that need it taller.
gridOptions.rowHeight = 50;
You'll also need to set the white-space attribute on the div so that it wraps, which you can do by setting a class in the cellTemplate, and then adding a style to the css.
A plunker as an example: http://plnkr.co/edit/kyhRm08ZtIKYspDqgyRa?p=preview

Set the Dependency for the javascript:
angular.module('app', [
'ngTouch',
'ui.grid',
'ui.grid.autoResize',
'ui.grid.resizeColumns'
])
for ui-grid 3.0, I am using this directive:
.directive('setOuterHeight',['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element) {
$timeout(function(){
// Get the Parent Divider.
var parentContainer = element.parent()[0];
console.log(parentContainer.offsetHeight);
// Padding of ui-grid-cell-contents is 5px.
// TODO: Better way to get padding height?
var topBottomPadding = 10;
//Get the wrapped contents rowHeight.
var rowHeight = topBottomPadding + parentContainer.offsetHeight;
var gridRowHeight = scope.grid.options.rowHeight;
// Get current rowHeight
if (!gridRowHeight ||
(gridRowHeight && gridRowHeight < rowHeight)) {
// This will OVERRIDE the existing rowHeight.
scope.grid.options.rowHeight = rowHeight;
}
},0);
}
};
}])
Under the controller:
.controller('MainCtrl',
['$scope', '$q', '$timeout', 'uiGridConstants',
function ($scope, $q, $timeout, uiGridConstants) {
$scope.gridOptions = {
enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
columnDefs: [
{name: 'firstName', width: '*'},
{name: 'lastName', width: '*'},
{
name: 'company', width: '*',
cellTooltip: function (row) {
return row.entity.company;
},
cellTemplate: '<div class="ui-grid-cell-contents wrap" title="TOOLTIP"><div><span class="label" set-row-height>{{row.entity.company}} </span></div><div>'
},
{name: 'employed', width: '*'}
],
enableColumnResize: true,
rowHeight: 10,
};
}]);
*Note the set-row-height directive for cellTemplate.
For CSS, you will have to put the white-space as normal:
.wrap {
white-space: normal;
}
.wrap .label {
display: inline-block;
}
Lastly, the HTML to change the Grid Height:
<div id="grid1" ui-grid="gridOptions" class="grid" ng-style="{height: (gridOptions.data.length*gridOptions.rowHeight)+32+'px'}" ui-grid-resize-columns ui-grid-auto-resize></div>
Plunker example is here:
http://plnkr.co/edit/OwgEfru0QyFaU1XJFezv?p=preview

Related

AngularJs - ag-grid rowData using "controller as" syntax

[Update] This Plunker does what I want, but :
it uses ui-grid, rather than ag-grid.
it injects the grid into the module, rather than just the single controller which uses it.
I presume that these changes would be straightforward & will try to work them into my code when I get home in about 14 hours time.
If anyone wants to fork that Plunk and make those changes, I will award a bounty, as this is a good basic start point demo for others wanting to do the same, so that a Plunker would be of general help.
I am tantalizingly close, but
Cannot read property 'setRowData' of undefined (caused by "<ui-view class="ng-scope ng-binding">")"TypeError: Cannot read property 'setRowData' of undefined
I am using "controller as" syntax, hence the Self; (Self = this;). That is working fine, my problem is when I try to set the rowData for an ag-grid in the templateURL of a ui-router state.
It's much to big to post, but here's the relevant stuff:
<div id="currentCandidatesGridDiv"
ag-grid="Search_result_controller.currentCandidatesGrid"
class="ag-theme-balham red_border"
style="height: 30%; width:90%">
</div>
// lookup the container we want the Grid to use
const currentCandidatesGridDiv = document.querySelector('#currentCandidatesGridDiv');
// create the grid passing in the div to use together with the columns & data we want to use
new agGrid.Grid(currentCandidatesGridDiv, Self.currentCandidatesGrid);
Self.currentCandidatesGrid =
{
columnDefs: [
{ headerName: "Candidate", field: "candidate_name", sortable: true },
{ headerName: "Skills", field: "skills", sortable: true },
{ headerName: "Start date", field: "start_date", sortable: true }
],
rowData: [],
pagination: true,
paginationAutoPageSize: true,
};
Was I correct to rowData: [], or ought I to have rowData: <someVariable>?
Then I calculate the row data into an array, Self.currentCandidatesGridRowData.
When I try to Self.currentCandidatesGrid.api.setRowData(Self.currentCandidatesGridRowData); I get error showing above.
I searched, but cannot find a working Plunker using the controller as syntax.
[Dupers] 1) the "dupe" question does not have an answer, so is of no use to me
2) my question is specifically about using Self.xxxGrid.api.setRowData(Self.xxxGridRowData); with the `controller as syntax. Pleas ere-open. Thnaks
DEMO of ag-Grid with AngularJS using "controller As" syntax
When the ag-Grid script loads, it does not register with AngularJS 1.x. This is because AngularJS 1.x is an optional part of ag-Grid and you need to tell ag-Grid you want to use it:
agGrid.initialiseAgGridWithAngular1(angular);
angular.module("example", ["agGrid"])
For more information, see
Ag-Grid Documentation - Basic AngularJS 1.x Example
The DEMO on PLNKR
agGrid.initialiseAgGridWithAngular1(angular);
angular.module("example", ["agGrid"])
.controller("exampleCtrl", function() {
var columnDefs = [
{headerName: "Make", field: "make"},
{headerName: "Model", field: "model"},
{headerName: "Price", field: "price"}
];
var rowData = [
{make: "Toyota", model: "Celica", price: 35000},
{make: "Ford", model: "Mondeo", price: 32000},
{make: "Porsche", model: "Boxter", price: 72000}
];
this.gridOptions = {
columnDefs: columnDefs,
rowData: rowData
};
})
html, body {
height: 100%;
width: 100%;
margin: 0;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
}
html {
position: absolute;
top: 0;
left: 0;
padding: 0;
overflow: auto;
}
body {
padding: 1rem;
overflow: auto;
}
<script src="//unpkg.com/angular/angular.js"></script>
<script src='//unpkg.com/#ag-grid-community/all-modules/dist/ag-grid-community.min.js'>
</script>
<body ng-app="example" ng-controller="exampleCtrl as $ctrl"
style="height: 100%">
<div ag-grid="$ctrl.gridOptions" class="ag-theme-balham"
style="height: 100%;">
</div>
</body>
Was I correct to rowData: [], or ought I to have rowData: <someVariable>?
You can even ignore this property in gridOptions, but the difference is that:
if you will define rowData as an empty array - grid will render handle it as 'No rows to show', but if you will not define it, grid will show 'Loading...' - which is more correct, with a delayed request case.
Besides, you can handle overlay logic by yourself for more details check here.
Now, as I said in comments
Cannot read property 'setRowData' of undefined
this issue could be caused by using the wrong reference.
First, take a look and check this answer with ag-grid developer comment also.
Secondly, about an issue itself:
.controller('yourController', [function() {
var Self = this; // here's your controller reference
// then you will have columns and rowData (probably)
// but the most important part is here
Self.currentCandidatesGrid = {
... // anything that you need
onGridReady: gridReady // major point for future api reference
}
function gridReady(params){
Self.gridApi = params.api;
Self.columnsApi = params.columnsApi;
}
}]);
And after gridReady you would be able to use grid API methods via Self.gridApi
Demo

How to get the rowcol object of a cell DOM element selected in the grid of UIGrid?

I'm using UIGrid.
How can I get the row-column object of a selected cell's DOM element in the grid?
$(".ui-grid-cell-focus") this gives you the HTML DOM of the currently focused/selected cell. I'm trying to get the uiGrid row-col object using this HTML DOM value. I dont know how to!
Please try as shown below.
js
var editCellTemplate = '<div class="ngCellText"><button class="btn btn-icon-only
green height-28" ng-click="grid.appScope.editProperty(row.entity.id)"><i
class="fa fa-edit"></i></button></div>';
vm.yourGridOptions = {
appScopeProvider: vm,
flatEntityAccess: false,
fastWatch: true,
showHeader: false,
columnDefs: [
{
name: 'id',
field: 'id',
width: 240,
},
{
name: 'Edit',
cellTemplate: editCellTemplate,
width: 40,
}
],
data: []
};
//edit property
vm.editProperty = function (id) {
// your logic here
};
You could try in your gridOptions declaration:
onRegisterApi: function(gridApi){
gridApi.cellNav.on.navigate($scope,function(newRowcol, oldRowCol){
console.log(newRowcol);
});
}
Just be sure to inject ui.grid.cellNav into your angular module and ui-grid-cellNav in your grid directive view. newRowcol is your row-col object

"Global" variables in ng-repeat in AngularJS

I am creating a web app that has multiple dialog windows set up by ng-repeat'ing a directive, <make-dialog>. Information specific to each dialog (width, height, position, etc), is stored in an array in the controller and passed into the directive as a scope variable.
Now, I would like to add a boolean scope variable that can be accessed and modified by all the dialog windows. So when you click the "+" button in any of the dialogs, the scope variable changes to "true", and all the other dialogs recognize that that change has been made.
Here is a sketch of the code I have tried:
Controller:
angular.module('root', [])
.controller('index', ['$scope', function($scope){
$scope.dialogs = [
{
minimized: false,
maximized: false,
width: 200,
height: 300,
top: 5,
left: 5,
zindex: 1,
template: 'experiment-dialog.html'
},
{
minimized: false,
maximized: false,
width: 200,
height: 250,
top: 257,
left: 238,
zindex: 0,
template: 'other-dialog.html'
}];
$scope.bool = false; //The variable I want to be able to access and change
}]);
Directive:
.directive('makeDialog', function($document) {
return {
restrict: 'E',
scope: {
model: '=',
dialogs: '=',
bool: '='
},
template: "<button ng-click='maximize()> + </button>'",
link: function(scope, element, attrs) {
scope.maximize = function() {
scope.bool = true;
}
}
}
});
index.html:
<html>
<body ng-app='root' ng-controller='index'>
<div id='container'>
<div ng-repeat='dialog in dialogs|filter:{minimized:false}'>
{{bool}}
<make-dialog model='dialog' dialogs='dialogs' bool='bool'></make-dialog>
</div>
</div>
</body>
</html>
This displays on the screen two buttons and the words
"false false". But when I click one of the "+" buttons, only one of the "false" values changes to true. So this variable is not global, but is somehow only seen by one dialog. Is there any way to fix this, so that clicking on one button will make both dialogs realize that the variable is now true?
Check working demo: Plunker
Your problem is that you bind the model to some primitive variable inside the ng-repeat:
The ngRepeat directive instantiates a template once per item from a collection. Each template instance gets its own scope
So, use some object to perform the two-way binding.

Manual trigger of show / hide in angularstrap datepicker

I want to use a button to show and hide the datepicker.
http://mgcrea.github.io/angular-strap/##datepickers
there are no documentations on how to do this
var app = angular.module('mgcrea.ngStrapDocs', ['ngAnimate', 'ngSanitize',
'mgcrea.ngStrap']);
app.controller('MainCtrl', function($scope) {
});
'use strict';
angular.module('mgcrea.ngStrapDocs')
.config(function($datepickerProvider) {
angular.extend($datepickerProvider.defaults, {
dateFormat: 'dd/MM/yyyy',
startWeek: 1,trigger:manual
});
})
.controller('DatepickerDemoCtrl', function($scope, $http,$datepicker) {
//ng-click
$scope.datepickerpop = function() {
$datepicker.show();
//$datepicker._show();
};
});
This is now much easier with v2.0.4 of ngStrap Datepicker. For more details, see this Github comment. Here's a working plunk to demonstrate the datepicker as both a manually-triggered dropdown, and as a manually-triggered inline element.
<bs-datepicker ng-model="myDatepicker.date" data-bs-show="myDatepicker.show"></bs-datepicker>
In your controller:
$scope.myDatepicker = {
date: null,
show: false
};
You'll also need to override the CSS:
bs-datepicker[bs-show] .datepicker.dropdown-menu,
bs-datepicker[bs-show] + .datepicker.dropdown-menu,
bs-datepicker[data-bs-show] .datepicker.dropdown-menu,
bs-datepicker[data-bs-show] + .datepicker.dropdown-menu {
position: relative;
top: 0 !important;
left: 0 !important;
}
To always show the datepicker, just change the attribute to data-bs-show="true".
If you add the attribute data-container="self", the datepicker will be placed inside the <bs-datepicker> element, which might be useful depending on your needs.

How do I create an AngularJS UI bootstrap popover with HTML content?

I want to create a bootstrap popover with a pre tag containing a prettified JSON object. The naive implementation,
<span popover='<pre>{[ some_obj | json:" " ]}</pre>'
popover-trigger='mouseenter'>
escapes the content before inserting it into the popup. What's the best way of specifying a popover body with html content?
UPDATE:
As can been seen in this, you should now be able to do this without overriding the default template.
ORIGINAL:
As of angular 1.2+ ng-bind-html-unsafe has been removed. You should be using the $sce service Reference.
Here is a filter for creating trusted HTML.
MyApp.filter('unsafe', ['$sce', function ($sce) {
return function (val) {
return $sce.trustAsHtml(val);
};
}]);
Here is the overwritten Angular Bootstrap 0.11.2 template making use of this filter
// update popover template for binding unsafe html
angular.module("template/popover/popover.html", []).run(["$templateCache", function ($templateCache) {
$templateCache.put("template/popover/popover.html",
"<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
" <div class=\"arrow\"></div>\n" +
"\n" +
" <div class=\"popover-inner\">\n" +
" <h3 class=\"popover-title\" ng-bind-html=\"title | unsafe\" ng-show=\"title\"></h3>\n" +
" <div class=\"popover-content\"ng-bind-html=\"content | unsafe\"></div>\n" +
" </div>\n" +
"</div>\n" +
"");
}]);
EDIT: Here is a Plunker implementation.
EDIT 2: As this answer keeps getting hits, I'll keep it updated as best I can. As a reference Here is the template from the angular-ui bootstrap repo. If this changes, the override template will require matching updates and the addition of the ng-bind-html=\"title | unsafe\" and ng-bind-html=\"content | unsafe\" attributes to continue working.
For updated conversation check the issue here.
Use the popover-template directive
If you are using a version of angular-ui equal or above 0.13.0, your best option is to use the popover-template directive. Here is how to use it:
<button popover-template="'popover.html'">My HTML popover</button>
<script type="text/ng-template" id="popover.html">
<div>
Popover content
</div>
</script>
NB: Do not forget the quotes around the template name in popover-template="'popover.html'".
See demo plunker
As a side note, it is possible to externalize the popover template in a dedicated html file, instead of declaring it in a <script type="text/ng-template> element as above.
See second demo plunker
I have posted a solution on the github project: https://github.com/angular-ui/bootstrap/issues/520
I you want to add this functionality to your project, here is a patch.
Add those directives:
angular.module("XXX")
.directive("popoverHtmlUnsafePopup", function () {
return {
restrict: "EA",
replace: true,
scope: { title: "#", content: "#", placement: "#", animation: "&", isOpen: "&" },
templateUrl: "template/popover/popover-html-unsafe-popup.html"
};
})
.directive("popoverHtmlUnsafe", [ "$tooltip", function ($tooltip) {
return $tooltip("popoverHtmlUnsafe", "popover", "click");
}]);
And add the template:
<div class="popover {{placement}}" ng-class="{ in: isOpen(), fade: animation() }">
<div class="arrow"></div>
<div class="popover-inner">
<h3 class="popover-title" ng-bind="title" ng-show="title"></h3>
<div class="popover-content" bind-html-unsafe="content"></div>
</div>
</div>
Usage: <button popover-placement="top" popover-html-unsafe="On the <b>Top!</b>" class="btn btn-default">Top</button>
View it on plunkr: http://plnkr.co/edit/VhYAD04ETQsJ2dY3Uum3?p=preview
You need to alter the default popover template to specify you want to allow Html content.
Look the popover-content div, it now has its binding done to the content property allowing unsafe html:
angular.module("template/popover/popover.html", []).run(["$templateCache", function ($templateCache) {
$templateCache.put("template/popover/popover.html",
"<div class='popover {{placement}}' ng-class='{ in: isOpen(), fade: animation() }'>" +
"<div class='arrow'></div><div class='popover-inner'>" +
"<h3 class='popover-title' ng-bind='title' ng-show='title'></h3>" +
"<div class='popover-content' ng-bind-html-unsafe='content'></div>" +
"<button class='btn btn-cancel' ng-click='manualHide()'>Cancel</button>" +
"<button class='btn btn-apply' ng-click='manualHide()'>Apply</button></div></div>");
}]);
For all your conventional Bootstrap popover needs you could utilize the following angular directive. It removes clutter from the HTML template and is very easy to use.
You can configure popover's title, content, placement, fade in/out delay, trigger event and whether content should be treated as html. It also prevents content overflow & clipping.
Related plunker with all teh codes here http://plnkr.co/edit/MOqhJi
Screencap
Usage
<!-- HTML -->
<div ng-model="popup.content" popup="popup.options">Some element</div>
/* JavaScript */
this.popup = {
content: 'Popup content here',
options: {
title: null,
placement: 'right',
delay: { show: 800, hide: 100 }
}
};
JavaScript
/**
* Popup, a Bootstrap popover wrapper.
*
* Usage:
* <div ng-model="model" popup="options"></div>
*
* Remarks:
* To prevent content overflow and clipping, use CSS
* .popover { word-wrap: break-word; }
* Popup without title and content will not be shown.
*
* #param {String} ngModel popup content
* #param {Object} options popup options
* #param {String} options.title title
* #param {Boolean} options.html content should be treated as html markup
* #param {String} options.placement placement (top, bottom, left or right)
* #param {String} options.trigger trigger event, default is hover
* #param {Object} options.delay milliseconds or { show:<ms>, hide:<ms> }
*/
app.directive('popup', function() {
return {
restrict: 'A',
require: 'ngModel',
scope: {
ngModel: '=',
options: '=popup'
},
link: function(scope, element) {
scope.$watch('ngModel', function(val) {
element.attr('data-content', val);
});
var options = scope.options || {} ;
var title = options.title || null;
var placement = options.placement || 'right';
var html = options.html || false;
var delay = options.delay ? angular.toJson(options.delay) : null;
var trigger = options.trigger || 'hover';
element.attr('title', title);
element.attr('data-placement', placement);
element.attr('data-html', html);
element.attr('data-delay', delay);
element.popover({ trigger: trigger });
}
};
});
See https://github.com/jbruni/bootstrap-bower-jbruni, which allow to use a popover-template
The following CSS styling seems to have done what I wanted in my specific case:
.popover-content {
white-space: pre;
font-family: monospace;
}
The general question still remains open.
Here is a fiddle of my solution that:
Is accessible (you can use tab keys to activate/deactivate).
Allows a user to hover the popover and for the popover to remain open.
Allows multiple popovers on the page, but only a single popover to be activated at any given time.
Doesn't rely on any third party, though the bootstrap popover styles have been borrowed.
The way this works is that we instantiate however many popovers we will have on the page in a popover array (see the TODO in the comments on how to wire this up).
Then anytime a user tabs into or hovers into an element that should trigger a popover we activate that specific popover in the popover array. When the user is no longer hovering the element we set a timeout for that specific popover in the array. If that timeout has elapsed it does a quick check to see if the user has re-hovered or re-focused (via tabbing) the element. If so then we keep the popover alive. If not we hide the popover.
For the CSS I did not want to rely on using bootstrap so I borrowed the styles directly from bootstrap. If you try to use bootstrap's popover styles you may run into some weird behavior where bootstrap is running it's own scripts on our custom popover which we do not want.
HTML:
<section>
<a href="#"
ng-mouseover="showPopover(i)"
ng-mouseleave="hidePopover(i)"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">
I trigger a popover - {{i}}
</a>
<popover popover-show="popover[i].popoverTracker">
<div class="arrow"></div>
<div class="custom-popover-content"
ng-mouseover="showPopover(i)"
ng-mouseleave="hidePopover(i)"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">
<a href="#"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">You can tab into me, I'm accessible!</a>
<br/>
<a href="#"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">You can tab into me, I'm accessible!</a>
</div>
</popover>
</section>
Angular Controller and Directive:
angular.module('controllers', []);
angular.module('directives', []);
angular.module('myApp', ['ngAnimate', 'controllers', 'directives']);
angular.module('controllers')
.controller('MainCtrl', function ($scope, $timeout) {
$scope.popover = [];
(function init() {
// TODO: Make this dynamic so that we can pass it a value and it will generate the right amount
// Initializing the array of popovers on startup
createPopoverTrackers(20);
})();
// Creating an array of popovers equal to the number of popovers on the page
function createPopoverTrackers(count) {
for(var i = 0; i < count; i++) {
$scope.popover.push({
popoverTracker: false,
popoverKeepAlive: false,
timer: null
})
}
}
// A user has focused on an element that has an associated popover
$scope.queueOpenPopover = function(index) {
// Show our specified tracker
$scope.popover[index].popoverTracker = true;
// Hide the rest
Object.keys($scope.popover)
.filter(function(trackerIndex) {
return trackerIndex != index
})
.forEach(function(trackerIndex) {
$scope.popover[trackerIndex].popoverTracker = false;
$scope.popover[trackerIndex].popoverKeepAlive = false;
const timer = $scope.popover[trackerIndex].timer;
if(timer) {
$timeout.cancel(timer);
$scope.popover[trackerIndex].timer = null;
}
})
};
// Queuing up the demise of the popover
$scope.queueKillPopover = function(index) {
$scope.popover[index].timer = $timeout(function() {
if (!$scope.popover[index].popoverKeepAlive) {
// Popover or the popover trigger were not hovered within the time limit, kill it!
$scope.popover[index].popoverTracker = false;
}
}, 700);
};
// When a user focuses into the actual popover itself or it's trigger, we need to keep it alive
$scope.showPopover = function(index) {
$scope.popover[index].popoverKeepAlive = true;
$scope.queueOpenPopover(index);
};
// The user has removed focus from the popover or it's trigger, set this to false so the timer knows to kill it
$scope.hidePopover = function(index) {
$scope.popover[index].popoverKeepAlive = false;
$scope.queueKillPopover(index);
};
});
angular.module('directives')
.directive('popover', function () {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
'popoverShow': '='
},
template: '<div class="custom-popover bottom" ng-show="popoverShow" ng-transclude></div>'
};
});
CSS borrowed from bootstrap:
.custom-popover {
position: absolute;
z-index: 1010;
max-width: 276px;
padding: 1px;
text-align: left;
white-space: normal;
background-color: #fff;
border: 1px solid rgba(0,0,0,0.2);
border-radius: 6px;
box-shadow: 0 5px 10px rgba(0,0,0,0.2);
background-clip: padding-box;
}
.custom-popover .arrow,
.custom-popover .arrow:after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
}
.custom-popover .arrow {
border-width: 11px;
}
.custom-popover .arrow:after {
border-width: 10px;
content: "";
}
.custom-popover.bottom {
margin-top: 10px;
}
.custom-popover.bottom .arrow {
top: -11px;
left: 50%;
margin-left: -11px;
border-bottom-color: rgba(0, 0, 0, 0.25);
border-top-width: 0;
}
.custom-popover.bottom .arrow:after {
top: 1px;
margin-left: -10px;
border-bottom-color: #ffffff;
border-top-width: 0;
content: " ";
}
.custom-popover-content {
padding: 9px 14px;
}

Resources