Angular UI Popover close button - javascript

I've read Angular UI Bootstrap adding a close button and show hidden div on ng-click within ng-repeat. I'd like to use the solution from the latter article and apply it to the problem stated in the first article. In essence, I want to be able to close an Angular UI Bootstrap popover with ng-show or ng-click.
I have an example piece of code to illustrate this. This code just applies a CSS class to a particular element whenever it is clicked, and removes it when it is clicked again:
<div ng-class="{'gray-inset-border': style}">
<div ng-click="style=!style"></div>
</div>
Whenever an element containing a popover is clicked, a popover template is created. In the Chrome DOM inspector, the opening tag looks like this:
<div class="popover ng-isolate-scope right fade in"
tooltip-animation-class="fade" tooltip-classes=""
ng-class="{ in: isOpen() }" popover-template-popup="" title=""
content-exp="contentExp()" placement="right" popup-class="" animation="animation"
is-open="isOpen" origin-scope="origScope"
style="top: 317.5px; left: 541.8125px; display: block;">
Notice the ng-class="{in: isOpen()}". I am assuming that this controls whether the popover is open or not, and want to use the same ng-click method as in the example above, and apply it to a button within the popover. However, when I tried that, it didn't work. I also can't find the popover template anywhere in the ui-bootstrap-tpls.js code. As far as I know, popover creation is voodoo magic.
It's also frustrating that Angular UI Bootstrap doesn't have this functionality already. I've been trying to solve this problem off and on for over a week now, and every "solution" I have seen doesn't seem to work for me.
Am I understanding the ng-class="{in: isOpen()}" correctly? Where do I edit the popover template to add a close button?

This was solved by #ognus on a GitHub thread.
He stated:
I've found that using a simple custom directive worked best for my use case. I just want to be able to close the popover from within the popover template.
The directive exposes scope.toggle method that user custom trigger to open and close popover. I'm then using this method in the popover template.
There is a plnkr that I adapted to test my own issue. The solution involved creating a directive (of course).
HTML
<!DOCTYPE html>
<html ng-app="main">
<head>
<script data-require="angular.js#1.x" data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js"></script>
<script data-require="ui-bootstrap#0.13.0" data-semver="0.13.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.13.0.min.js"></script>
<link data-require="bootstrap-css#*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<script src="popoverToggle.js"></script>
<script src="script.js"></script>
</head>
<body style="margin: 50px">
<!-- Show popover link -->
<a
href=""
popover-placement="bottom"
popover-trigger="open"
popover="Lorem ipsum dolor sit amet, consectetur."
popover-title="This is a title"
popover-toggle>
Show popover</a>
<div popover-placement="bottom" popover-trigger="open"
popover-template="'popover-template.html'" popover-toggle>Show Popover 2</div>
</body>
</html>
popoverToggle directive
angular.module('main')
.config(function($tooltipProvider) {
$tooltipProvider.setTriggers({'open': 'close'});
})
.directive('popoverToggle', function($timeout) {
return {
scope: true,
link: function(scope, element, attrs) {
scope.toggle = function() {
$timeout(function() {
element.triggerHandler(scope.openned ? 'close' : 'open');
scope.openned = !scope.openned;
});
};
return element.on('click', scope.toggle);
}
};
});
Popover template
<p>Are you sure you want to remove this item?</p>
<a href='' ng-click='remove(item)'>Yes</a>
<div ng-click='toggle()'>No</div>

app = angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
app.controller(
'dataCtrl', function() {
var self = this;
self.data = [
{name: "one", num: 23},
{name: "two", num: 87},
{name: "three", num: 283}
]
return self;
}
)
app.controller(
'myPopoverCtrl', ['$scope',
function($scope) {
// query popover
$scope.myPopover = {
isOpen: false,
templateUrl: 'myPopoverTemplate.html',
open: function open( value ) {
$scope.myPopover.isOpen = true;
$scope.myPopover.data = "(" + value.num + ")";
},
close: function close() {
$scope.myPopover.isOpen = false;
}
};
}
]);
<body ng-app="ui.bootstrap.demo" class='container'>
<div ng-controller='dataCtrl as dc' >
<li ng-repeat="d in dc.data">
{{d.name}}
<a ng-controller="myPopoverCtrl"
popover-template="myPopover.templateUrl"
popover-title="This is a popover"
popover-placement="right"
popover-is-open="myPopover.isOpen"
ng-click="myPopover.open(d)">
pop
</a>
</li>
</div>
<script
type="text/ng-template"
id="myPopoverTemplate.html">
<h2 ng-bind="myPopover.data"/>
<button
class="btn btn-success"
ng-click="myPopover.close()">Close me!</button>
</script>
</body>
Link to the working example
This is solution using another controller for the popover.
this controller opens and closes the popover.
you can also write the directive instead of controller.
Its works fine if data is in repeat.

Related

Angular bootstrap popover disappears when the mouse enters it

I have an angular bootstrap popover on some text. In the popover, I show some link where the user can click on that link and go to that website. Presently, when the user is trying to go inside popover it disappears.
If I try to keep the popover open on click instead of hovering, it doesn't close when I go to another popover.
I have created a jsfiddle where you can see
<div popover="{{careerAttribute.value}}"
popover-append-to-body="true"
popover-title="{{careerAttribute.title}}"
popover-trigger="mouseenter"
popover-placement="right"> HP
</div>
I should be able to click on the link displayed in hover and at a time single hover should be open.
You can do this by removing the popover-append-to-body. This way it will append it to the current element. Now instead of using the default popover-trigger, we will manually open and close the element from the parent td. For this we need to set popover-trigger to none and then use ng-mouseenter and ng-mouseleave on the parent to manually trigger the popover using popover-is-open. You will need to use an array to track the open popovers. You will also have to sanitize the URL to be shown as HTML in the popover.
Here is a working example.
angular.module('myApp', ['ngAnimate', 'ngSanitize', 'ui.bootstrap'])
.controller('myCtrl', ['$scope', '$sce', ($scope, $sce) => {
$scope.isOpen = new Array(2).fill(false);
$scope.careerAttribute = {
'title': 'Here is The Title',
'value': $sce.trustAsHtml('<a target="_blank" href="https://www.google.com">Google</a>')
};
$scope.open = (popoverId) => {
$scope.isOpen[popoverId] = true;
}
$scope.close = (popoverId) => {
$scope.isOpen[popoverId] = false;
}
}]);
[uib-popover-html] {
margin: 25px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.7.5/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.7.5/angular-sanitize.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<div ng-app="myApp" ng-controller='myCtrl'>
<table>
<thead>
<tr>
<th>Name</th>
<th>Address</th>
</tr>
</thead>
<tr>
<td ng-mouseenter="open(0)" ng-mouseleave="close(0)">
<div uib-popover-html="careerAttribute.value" popover-title="{{careerAttribute.title}}" popover-is-open="isOpen[0]" popover-trigger="'none'" popover-placement="right">
Hover for Popup
</div>
</td>
<td>India</td>
</tr>
<tr>
<td ng-mouseenter="open(1)" ng-mouseleave="close(1)">
<div uib-popover-html="careerAttribute.value" popover-title="{{careerAttribute.title}}" popover-is-open="isOpen[1]" popover-trigger="'none'" popover-placement="right">
Hover for Popup
</div>
</td>
<td>India</td>
</tr>
</table>
</div>
Note: I'm not sure why clicking the link does not open it when using the code snippets on StackOverflow (it works on other online code editors) but you can right-click and open in a new tab to see that it works. This is clearly an issue with the snippets itself as even using the link in the HTML directly does not open the link.

delegate event on jquery for popover bootstrap not working correctly

i am quite new with this delegate thing for dynamic elements. so today i tested again with a generated dynamic template from some example in stackover for popover.
here is my dynamic html content.
<a id="testpop" 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>
and then, i have this script on my js
$('#resultContent').on('click','#testpop', function(e) { //use on if jQuery 1.7+
// Enables popover #2
$("[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();
}
});
});
resultContent is the div here where i add .html all my html codes.
i manage to attached the delegate event (i think) but is acting strange as my 1st click on the testpop button, the popover won't show. Until i press the 2nd and 3rd time only it will pop up. Am i doing this delegating wrong?
credits for this test code: HTML inside Twitter Bootstrap popover
You forgot to add a trigger in the popover options. The data-trigger in the element doesn't do too much when you really only initialize the popover() once you click the element. In fact, your JS code would propably work better like so:
$("[data-toggle=popover]").popover({
html : true,
trigger: 'click',
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();
}
});
EDIT
Popover should generally be initialized on page load:
$("[data-toggle=popover]").popover();
Putting it inside a click event will not enable popover on the element until you click it first.
Removing the click event from your original JS code should enable it on page load.
If however, the element you mean to attach the popover to is dynamically added to the DOM after page load, you should reinitalize the popover after adding it.
Wrapping the popover in a function would make that much easier.
function addPopover(selector){
$(selector).popover({
html : true,
trigger: 'click',
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();
}
});
}
And whenever you add an element to the page that should have a popover, you simply call the function, with a selector for the element. Example for the element you have in your code:
addPopover("[data-toggle=popover]");
In your code, you are configuring the popover on click event of the button.
So, this is how it happens.
Click the anchor link
Initialize the popover with options. (This doesnt mean it displays the popover, it is just a initialization)
Click on the popover again (Popover is already bound because of the earlier call and then it shows)
Also, you need to ensure the popover is not bound to the element again and again to avoid repeated popover bindings.
$('#resultContent').on('click', '#testpop', function(e) { //use on if jQuery 1.7+
// Enables popover #2
$("[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();
}
}).popover('show');
// Explicitly show the popover.
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div id="resultContent">
<a id="testpop" class="btn btn-primary" data-placement="bottom" data-popover-content="#a1" data-toggle="popover" data-trigger="focus" href="#" tabindex="0">Popover Example</a>
</div>
<!-- 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>

Looking for options on how to display info alert when mouse highlights link

I'm making a relatively simple site that displays links my team and I use. One of the requirements is to display note information when a user has their mouse cursor over any of the links. I understand that the easiest method is simply not list the link if no one's using it, but the team insists on posting the URL on this site for archival reasons. They may also come back to the link and use it again in their environment(s).
Consider this link:
Test Environment #1
I want this alert (below) to become displayed when the mouse cursor is hovering over the link:
<div class="container">
<div class="alert alert-info">
<strong>Note: The testers are not using this link as a part of their test environment!</strong>
</div>
</div>
If there are any other suggestions on other methods to accomplish this, I'd love to hear.
Give your link and alert each an id so you can target it with JavaScript, also hide your alert by default, something like this:
<a id="testenv" href="www.footester.com/foofootestest">Test Environment #1</a>
<div id="testalert" style="display:none" class="alert alert-info">
<!-- ... -->
</div>
Then use JavaScript to fire the mouseover event when the link is hovered like this:
var testenv = document.getElementById("testenv"),
testalert = document.getElementById("testalert");
testenv.addEventListener("mouseover", function( event ) {
testalert.style.display = "block";
}, false);
Just for fun you could also add a mouseout event making the alert disappear again when the mouse gets off the link (not hovered anymore):
testenv.addEventListener("mouseout", function( event ) {
testalert.style.display = "none";
}, false);
Here is the full code inside a code snippet block:
var testenv = document.getElementById("testenv"),
testalert = document.getElementById("testalert");
testenv.addEventListener("mouseover", function( event ) {
testalert.style.display = "block";
}, false);
testenv.addEventListener("mouseout", function( event ) {
testalert.style.display = "none";
}, false);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<a id="testenv" href="www.footester.com/foofootestest">Test Environment #1</a>
<div class="container">
<div id="testalert" style="display:none" class="alert alert-info">
<strong>Note: The testers are not using this link as a part of their test environment!</strong>
</div>
</div>
Here you can play with this code on bootply (the bootstrap testing sandbox): http://www.bootply.com/TfrhmIbqq8
I did something similar for a personal project I am working on, and used the Bootstrap Popover plugin for this type of display. With a little jQuery, it's fairly simple to hook it up to the mouseover event and have the popover even follow your cursor around on the note.
Here's a jsFiddle as an example! :D
$(document).ready(function() {
function onRowMouseLeave(e)
{
$(e.target).popover("hide");
}
function onRowMouseMove(e)
{
$(e.target).popover("show");
// Magic numbers to offset from cursor slightly and prevent popover from flashing as much
$(".popover").css({ top: e.pageY - 14, left: e.pageX + 6 }).find(".arrow").css("top", "14px");
}
$("[data-toggle='popover']").popover({
animation: false,
container: "body",
html: true,
placement: "right",
trigger: "manual",
}).on("mousemove", "", onRowMouseMove)
.on("mouseleave", "", onRowMouseLeave);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container">
<a href="#" data-toggle="popover" data-content="<div class='alert alert-danger'>Here is the note to display</div>">
Content I want to hover
</div>
</div>
It may be very basic, but did you consider to try:
Test Environment #1
The advantage is that you'll not be alerted on any link you hover, But receives a note.
This would work but you have to add the alert container below every link
a {
float: left;
clear: both;
padding: 10px;
width: 100%;
}
.alert {
display: none;
}
a:hover + .container .alert {
display: block;
}
Test Environment #1
<div class="container">
<div class="alert alert-info">
<strong>Note: The testers are not using this link as a part of their test environment!</strong>
</div>
</div>
Test Environment #1
<div class="container">
<div class="alert alert-info">
<strong>Note: The testers are not using this link as a part of their test environment!</strong>
</div>
</div>
This does not get Alert
Test Environment #1
<div class="container">
<div class="alert alert-info">
<strong>Note: The testers are not using this link as a part of their test environment!</strong>
</div>
</div>

AngularUI popover style change of parent element on click

I have a pretty specific problem. Recently I figured out how to add a close button to an AngularUI popover. Originally the user had to click on the popover parent to open and to close it, so I had functionality added in that changed the style of that element on a click event. With the addition of the close button, I want to simulate the same effect when the user clicks it. I set up a plnkr here to play with.
So far I've tried to add ng-click="toggle(); style=!style" in the popover template, but that didn't work. I think that I have to access the style variable in the popoverToggle directive, but I don't know how to do that. It might also just be possible to manipulate it in the HTML.
Popover template
<div><span ng-click="toggle()">X</span></div>
<p>content</p>
popoverToggle.js
angular.module('app')
.config(function($tooltipProvider) {
$tooltipProvider.setTriggers({'open': 'close'});
})
.directive('popoverToggle', function($timeout) {
return {
scope: true,
link: function(scope, element, attrs) {
scope.toggle = function() {
$timeout(function() {
element.triggerHandler(scope.openned ? 'close' : 'open');
scope.openned = !scope.openned;
scope.style = !scope.style; // doesn't do anything either
});
};
return element.on('click', scope.toggle);
}
};
});
index.html
<span ng-class="{'border-gray': style}" style="margin: 40px" ng-click="style=!style" class="red-btn">
<span popover-placement="bottom" popover-template="'popover-template.html'"
popover-trigger="open" popover-append-to-body="true" popover-toggle>click me</span>
</span>
The solution is very straightforward, all that needs to be changed is the style variable. Simply change it to $scope.style, like so:
popover-template.html
<div><span ng-click="toggle(); $scope.style=!$scope.style">X</span></div>
<p>content</p>
index.html
<span ng-class="{'border-gray': $scope.style}" style="margin: 40px" ng-click="$scope.style=!$scope.style" class="red-btn">
<span popover-placement="bottom" popover-template="'popover-template.html'"
popover-trigger="open" popover-append-to-body="true" popover-toggle>click me</span>
</span>

Assign dynamic controller in ng-repeat

I am new to Angularjs. I've tried a example in here.
file index.html:
<div ng-repeat="data in ctl.dataList">
<div class="col-md-6">
<textarea type="text" ng-mouseover="ctl.mouseOverFunc()" ng-mouseleave="ctl.mouseLeaveFunc()">{{data.value}}</textarea>
<button ng-show="ctl.showCloseBtn">X</button>
</div>
</div>
file app.js:
app.controller('FocusController', function() {
this.showCloseBtn = false;
this.dataList = [{
value: "one"
}, {
value: "two"
}];
this.mouseOverFunc = function() {
this.showCloseBtn = true;
};
this.mouseLeaveFunc = function() {
this.showCloseBtn = false;
};
});
I want to show close button when mouse overed every textarea like facebook chat in this picture. But my issues is when mouse over one of textarea then all X button was showed.
How do i assign dynamic controller to every textarea or how to do like facebook chat ?
Thanks for your help
You can do with CSS as well as AngularJS. I suggest you to do with CSS which is Simple. And Do your ng-click on the button.
This Plunker Demo is using with CSS and added ng-click there. Please check the styles and classes added.
Styles
<style>
.field:hover .btn-close {
display:block;
}
.btn-close {
display:none;
}
</style>
HTML
<div ng-repeat="data in ctl.dataList">
<div class="col-md-7 field">
<textarea></textarea>
<button ng-click="doSomething()" class="btn-close">X</button>
</div>
</div>
This Plunker Demo is with AngilarJS as explained in the other answer by New Dev.
<div ng-repeat="data in ctl.dataList">
<div ng-mouseover="data.showX = true"
ng-mouseleave="data.showX = false">
<textarea></textarea>
<button ng-click="doSomething()" ng-show="data.showX">X</button>
</div>
Typically, it would be best to create a directive for this functionality and encapsulate all the logic of clicking the "x" button, but for simplicity you could also leverage the child scope created by ng-repeat, and do the following:
<div ng-repeat="data in ctl.dataList">
<div ng-mouseover="data.showX = true"
ng-mouseleave="data.showX = false">
<textarea type="text"></textarea>
<button ng-show="data.showX" ng-click="ctl.close(data)">X</button>
</div>
</div>
ng-repeat="item in items" creates a child scope for each item, so you can set values on the child scope.
Here's your modified plunker
EDIT:
As suggested in the comments, if you have nothing more complex than showing or hiding the button, definitely CSS approach is the simplest way to go. Use the above example then as an illustration for how scopes work.

Categories

Resources