Close popover clicking somewhere outside in angular - angularjs

I have something like this:
http://plnkr.co/edit/CoDdWWQz8jPPM4q1mhC5?p=preview
What I would like to do is closing the popover window after clicking somewhere outside. I know that there were similar questions but I would like to know how to do that in Angular. Problem is, my popover is located inside script tag.
<script type="text/ng-template" id="templateId.html">
This is the content of the template {{name}}
</script>

In bootstrap's documentation they have an example of a 'dismissable' popover.
The trick is to add trigger: 'focus' to your popover options. You then need to change your element to a 'focusable' element (in this example i have used a button)
Here is my fork of your example.
PS. it is worth mentioning that not all elements are natively 'focusable'. You can make sure that an element can become focusable, but adding the attribute tabindex (eg. tabindex="-1").

Looks like I have found an answer to my question. All we need to do is to apply this solution: How to dismiss a Twitter Bootstrap popover by clicking outside? to directive responsible for showing popover. What's more, we need to add data-toggle="popover" to our button.
And, surprisingly, it works very well.

If you want it to work seamlessly on any kind of elements without having to use any external code nor weird things, all you have to do is add this 2 attributes to your markup: tabindex="0" to make the element focusable, and popover-trigger="focus" to make it dismiss the popup once you click off.
Example with <i> tag which is not focusable:
<i popover-html="someModelWhichContainsMarkup" popover-trigger="focus"
tabindex="0" class="fa fa-question-circle"></i>

You can use following code:
<div ng-app="Module">
<div ng-controller="formController">
<button uib-popover-template="dynamicPopover.templateUrl" popover-trigger="focus" popover-placement="left" type="button" class="btn btn-default">Popover With Template</button>
<script type="text/ng-template" id="myPopoverTemplate.html">
<div>
<span>prasad!!</span>
</div>
</script>
</div>
</div>
In Script :
<script type="text/javascript">
var app = angular.module("Module", ['ui.bootstrap']);
app.controller("formController", ['$scope', function ($scope) {
$scope.dynamicPopover = {
templateUrl: 'myPopoverTemplate.html'
};
}]);
</script>

Works for me, add this attribute to the tag which is calling/opening the popup, DON'T MISS THE SINGLE QUOTES AROUND outsideClick
popover-trigger="'outsideClick'"

This opens only one popover and closes upon clicking outside of popover
popover-trigger="outsideClick"

Related

How to disable a button in ANGULARJS

i have angularJS 1.5.0-rc.2
I found on the internet that i can use the directive
data-ng-disabled="Expression"
But it won't disable a button.
What i tried :
<button data-ng-disabled="false">Select</button> // don't work
<button data-ng-disabled="loaded">Select</button> // don't work
<button data-ng-disabled="loaded != false">Select</button> // don't work
Loaded is defined in my controller as $scope.loaded = false.
How can i disable a button ? Thanks
The button will be disabled only if the expression is true.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-init="disableBtn=true">
<button ng-disabled="disableBtn">test</button>
</div>
I make it without derective. I made it like this:
remove
In controller first of all made
$scope.disabled = true;
Than in if/else remove class disabled and change $scope.disabled = false;
I give you example with tag <a></a> this work with button simple.
And in button ng-click first made Test ng-click="disabled||usertaskctrl.removeTasksToArchive()" before make click on some you function.
Try this
1 This is direct method of implementation
<script>src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<button ng-disabled=true>test</button>
</div>
2 another way you can change the value for
<div ng-app>
<button ng-disabled=dsblBtn>test</button>
</div>
in controller inside init function
$scope.dsblBtn = true;
Always use the button tag with ng-disabled in angular js otherwise it will not work.

Type error : Cannot read property 'childNodes' of undefined

I am trying to display a modal when the view is loaded.
Code :
//View
<div id="showCom" ng-controller="showmodalCtrl" ng-init="init()">
<div class="modal fade" id="companyModal" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">Please Select Company</h4>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label class="control-label">Recipient:</label>
<input type="text" class="form-control">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Submit</button>
</div>
</div>
</div>
</div>
//Controller
.controller('showmodalCtrl', ['$scope', function($scope){
$scope.init = function(){
$('#companyModal').modal("show");
}
}])
Everything works fine and the modal is displayed but I get this error on the console :
Type error : Cannot read property 'childNodes' of undefined
I have no idea why this is happening.
Also if I remove the "form" from the modal , i don't get any error. So I guess the problem is with the form but I am not able to resolve it.
Thanks in advance.
I had the same problem and I managed to resolve it by wrapping the modal open function inside a $timeout() or a normal setTimeout() function.
setTimeout(function(){
jQuery('#messageModal').modal('show');
}, 0);
I had the same error message when trying to use a JQuery plugin. Running it after document ready resolved the issue for me. The plugin was running fine but the angular code that followed in the current scope was not.
It was the "Set timeout"-answer in this thread that led me to try this solution.
Solution for me:
angular.element(document).ready(function () {
//Angular breaks if this is done earlier than document ready.
setupSliderPlugin();
});
As another solution in AngularJS context I'm using this approach:
Include $timeout module in your JS controller
Run init() function with all initializers like this:
$timeout(init, 0);
Works good.
Sorry for edit. Is your HTML well formed? Check that all the tags match.
In your code snippet, it looks like you're missing a closing div. check that - the one that closes the controller div.
I had a similar problem. It would throw an exception when i tried to add some html to dom and compile it using $compile in angularJs.
Inside of the html was another directive that tried to add some dom element from the page to somewhere else in the page.
I just had to call .clone of that element before i moved it to the new location.
And the exception was gone.
$popupContent = $(attrs.popupSelector).clone();
$container = $('<div class="popup-container"></div>');
$container.append($popupContent);
$container.hide();
$('body').append($container);

angular ngclick of ngTouch: mouse click works right, while touch does not(Using iscroll5)

Firstly I'm using angular 1.2.14,
In this case ng-click of ngTouch is used:
<section class="scroller-container">
<div id="wrapper">
<ul id= "scroller">
<li data-ng-repeat="competitor in competitors">
<div class="competitor-title" data-ng-click="selectCompetitor(competitor)">
<div class="title-name">
<span>{{competitor.competitorTitle}}</span>
<br>
<span>{{competitor.competitorName}}</span>
</div>
<div class="landmark"></div>
<div class="landmark-emphasis">
<i class="icon-arrow-down-blue"></i>
</div>
</div>
</li>
</ul>
Then the controller:
app.controller('intelligenceController', ['$scope', '$http', function($scope, $http){...}]);
In which:
$scope.selectCompetitor = function(competitor) {...};
And I used ng-click-active, the document says:"This directive also sets the CSS class ng-click-active while the element is being held down (by a mouse click or touch) so you can restyle the depressed element if you wish."
So I click or touch the div, style changes. However touch doesn't trigger the method, while mouse click trigger the method.
In short, mouse click works right, while touch only change the style, why?
Edit(old): The problem is solved, using android webview it works all right. I tested my webapp on surface pro, the touch does not work ok.
Edit The root cause is you need to set iscoll option (click: true), otherwise in UIWebview and surface pro it will not work ok.
did you add ngtouch in your module ?
var sellApp = angular.module('process', ['ngTouch']);
and also include it
<script src="js/angular-touch.min.js" type="text/javascript"></script>

Bootstrap 3 Tooltips with Angular

I'm attempting to use Boostrap 3 tooltips with Angular JS so that the tooltip displays the value of an object in the Angular scope. This works fine when the page loads, but when the value of the object in the scope is updated the tooltip still displays the original value.
HTML:
<div ng-app>
<div ng-controller="TodoCtrl">
<span data-toggle="tooltip" data-placement="bottom" title="{{name}}">Hello {{name}}</span>
<button type="button" ng-click="changeName()">Change</button>
</div>
Javascript:
function TodoCtrl($scope) {
$scope.name = 'Ian';
$scope.changeName = function () {
$scope.name = 'Alan';
}
}
$(document).ready(function () {
$('span').tooltip();
});
There's an example demonstrating my code so far and the issue in this Fiddle
Instead of:
<span data-toggle="tooltip" data-placement="bottom" title="{{name}}">Hello {{name}}</span>
Use:
<span data-toggle="tooltip" data-placement="bottom" data-original-title="{{name}}">Hello {{name}}</span>
Bootstrap Tooltip first checks data-original-title, so as long as you keep this value updated, you'll be fine. Check out this working Fiddle
My guess is that it is missing an apply for changed values, so angular knows nothing about that and does not update. I recommend angular ui bootstrap instead of raw bootstrap components for this reason.
http://angular-ui.github.io/bootstrap/
This way there is no need for jquery which is a bonus in my book.
EDIT:
try this in change handler for a quick and dirty workaround:
$('span').tooltip('hide')
.attr('data-original-title', $scope.name)
.tooltip('fixTitle');
But as i said, check out angular version as this hack has several issues....
For Latest Angular Versions Use: [attr.data-original-title]="dynamicTooltipMsg"
<button
data-toggle="tooltip"
[data-title]="dynamicTooltipMsg"
[attr.data-original-title]="dynamicTooltipMsg">
Testing
</button>

Using Bootstrap Tooltip with AngularJS

I am trying to use the Bootstrap tooltip in an app of mine. My app is using AngularJS Currently, I have the following:
<button type="button" class="btn btn-default"
data-toggle="tooltip" data-placement="left"
title="Tooltip on left">
Tooltip on left
</button>
I think I need to use
$("[data-toggle=tooltip]").tooltip();
However, I'm not sure. Even when I add the line above though, my code doesn't work. I'm trying to avoid using UI bootstrap as it has more than I need. However, if I had to include just the tooltip piece, I'd be open to that. Yet, I can't figure out how to do that.
Can someone show me how to get the Bootstrap Tooltip working with AngularJS?
In order to get the tooltips to work in the first place, you have to initialize them in your code. Ignoring AngularJS for a second, this is how you would get the tooltips to work in jQuery:
$(document).ready(function(){
$('[data-toggle=tooltip]').hover(function(){
// on mouseenter
$(this).tooltip('show');
}, function(){
// on mouseleave
$(this).tooltip('hide');
});
});
This will also work in an AngularJS app so long as it's not content rendered by Angular (eg: ng-repeat). In that case, you need to write a directive to handle this. Here's a simple directive that worked for me:
app.directive('tooltip', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
element.hover(function(){
// on mouseenter
element.tooltip('show');
}, function(){
// on mouseleave
element.tooltip('hide');
});
}
};
});
Then all you have to do is include the "tooltip" attribute on the element you want the tooltip to appear on:
<a href="#0" title="My Tooltip!" data-toggle="tooltip" data-placement="top" tooltip>My Tooltip Link</a>
The best solution I've been able to come up with is to include an "onmouseenter" attribute on your element like this:
<button type="button" class="btn btn-default"
data-placement="left"
title="Tooltip on left"
onmouseenter="$(this).tooltip('show')">
</button>
Simple Answer - using UI Bootstrap (ui.bootstrap.tooltip)
There seem to be a bunch of very complex answers to this question. Here's what worked for me.
Install UI Bootstrap - $ bower install angular-bootstrap
Inject UI Bootstrap as a dependency - angular.module('myModule', ['ui.bootstrap']);
Use the uib-tooltip directive in your html.
<button class="btn btn-default"
type="button"
uib-tooltip="I'm a tooltip!">
I'm a button!
</button>
If you're building an Angular app, you can use jQuery, but there is a lot of good reasons to try to avoid it in favor of more angular driven paradigms. You can continue to use the styles provided by bootstrap, but replace the jQuery plugins with native angular by using UI Bootstrap
Include the Boostrap CSS files, Angular.js, and ui.Bootstrap.js:
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://code.angularjs.org/1.2.20/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.0.js"></script>
Make sure you've injected ui.bootstrap when you create your module like this:
var app = angular.module('plunker', ['ui.bootstrap']);
Then you can use angular directives instead of data attributes picked up by jQuery:
<button type="button" class="btn btn-default"
title="Tooltip on left" data-toggle="tooltip" data-placement="left"
tooltip="Tooltip on left" tooltip-placement="left" >
Tooltip on left
</button>
Demo in Plunker
Avoiding UI Bootstrap
jQuery.min.js (94kb) + Bootstrap.min.js (32kb) is also giving you more than you need, and much more than ui-bootstrap.min.js (41kb).
And time spent downloading the modules is only one aspect of performance.
If you really wanted to only load the modules you needed, you can "Create a Build" and choose tooltips from the Bootstrap-UI website. Or you can explore the source code for tooltips and pick out what you need.
Here a minified custom build with just the tooltips and templates (6kb)
Have you included the Bootstrap JS and jQuery?
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min.js"></script>
If you don't already load those, then Angular UI (http://angular-ui.github.io/bootstrap/) may not be much overhead. I use that with my Angular app, and it has a Tooltip directive. Try using tooltip="tiptext"
<button type="button" class="btn btn-default"
data-toggle="tooltip" data-placement="left"
title="Tooltip on left"
tooltip="This is a Bootstrap tooltip"
tooltip-placement="left" >
Tooltip on left
</button>
I wrote a simple Angular Directive that's been working well for us.
Here's a demo: http://jsbin.com/tesido/edit?html,js,output
Directive (for Bootstrap 3):
// registers native Twitter Bootstrap 3 tooltips
app.directive('bootstrapTooltip', function() {
return function(scope, element, attrs) {
attrs.$observe('title',function(title){
// Destroy any existing tooltips (otherwise new ones won't get initialized)
element.tooltip('destroy');
// Only initialize the tooltip if there's text (prevents empty tooltips)
if (jQuery.trim(title)) element.tooltip();
})
element.on('$destroy', function() {
element.tooltip('destroy');
delete attrs.$$observers['title'];
});
}
});
Note: If you're using Bootstrap 4, on lines 6 & 11 above you'll need to replace tooltip('destroy') with tooltip('dispose') (Thanks to user1191559 for this upadate)
Simply add bootstrap-tooltip as an attribute to any element with a title. Angular will monitor for changes to the title but otherwise pass the tooltip handling over to Bootstrap.
This also allows you to use any of the native Bootstrap Tooltip Options as data- attributes in the normal Bootstrap way.
Markup:
<div bootstrap-tooltip data-placement="left" title="Tooltip on left">
Tooltip on left
</div>
Clearly this doesn't have all the elaborate bindings & advanced integration that AngularStrap and UI Bootstrap offer, but it's a good solution if you're already using Bootstrap's JS in your Angular app and you just need a basic tooltip bridge across your entire app without modifying controllers or managing mouse events.
You can use selector option for dynamic single page applications:
jQuery(function($) {
$(document).tooltip({
selector: '[data-toggle="tooltip"]'
});
});
if a selector is provided, tooltip objects will be delegated to the
specified targets. In practice, this is used to enable dynamic HTML
content to have tooltips added.
You can create a simple directive like this:
angular.module('myApp',[])
.directive('myTooltip', function(){
return {
restrict: 'A',
link: function(scope, element){
element.tooltip();
}
}
});
Then, add your custom directive where is necessary:
<button my-tooltip></button>
You can do this with AngularStrap which
is a set of native directives that enables seamless integration of Bootstrap 3.0+ into your AngularJS 1.2+ app."
You can inject the entire library like this:
var app = angular.module('MyApp', ['mgcrea.ngStrap']);
Or only pull in the tooltip feature like this:
var app = angular.module('MyApp', ['mgcrea.ngStrap.tooltip']);
Demo in Stack Snippets
var app = angular.module('MyApp', ['mgcrea.ngStrap']);
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.1.2/angular-strap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.1.2/angular-strap.tpl.min.js"></script>
<div ng-app="MyApp" class="container" >
<button type="button"
class="btn btn-default"
data-trigger="hover"
data-placement="right"
data-title="Tooltip on right"
bs-tooltip>
MyButton
</button>
</div>
easiest way , add $("[data-toggle=tooltip]").tooltip(); to the concerned controller.
var app = angular.module('MyApp', ['mgcrea.ngStrap']);
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.1.2/angular-strap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-strap/2.1.2/angular-strap.tpl.min.js"></script>
<div ng-app="MyApp" class="container" >
<button type="button"
class="btn btn-default"
data-trigger="hover"
data-placement="right"
data-title="Tooltip on right"
bs-tooltip>
MyButton
</button>
</div>
Please remember one thing if you want to use bootstrap tooltip in angularjs is order of your scripts if you are using jquery-ui as well, it should be:
jQuery
jQuery UI
Bootstap
It is tried and tested
Only read this if you are assigning tooltips dynamically
i.e. <div tooltip={{ obj.somePropertyThatMayChange }} ...></div>
I had an issue with dynamic tooltips that were not always updating with the view. For example, I was doing something like this:
This didn't work consistently
<div ng-repeat="person in people">
<span data-toggle="tooltip" data-placement="top" title="{{ person.tooltip }}">
{{ person.name }}
</span>
</div>
And activating it as so:
$timeout(function() {
$(document).tooltip({ selector: '[data-toggle="tooltip"]'});
}, 1500)
However, as my people array would change my tooltips wouldn't always update. I tried every fix in this thread and others with no luck. The glitch seemed to only be happening around 5% of the time, and was nearly impossible to repeat.
Unfortunately, these tooltips are mission critical for my project, and showing an incorrect tooltip could be very bad.
What seemed to be the issue
Bootstrap was copying the value of the title property to a new attribute, data-original-title and removing the title property (sometimes) when I would activate the toooltips. However, when my title={{ person.tooltip }} would change the new value would not always be updated into the property data-original-title. I tried deactivating the tooltips and reactivating them, destroying them, binding to this property directly... everything. However each of these either didn't work or created new issues; such as the title and data-original-title attributes both being removed and un-bound from my object.
What did work
Perhaps the most ugly code I've ever pushed, but it solved this small but substantial problem for me. I run this code each time the tooltip is update with new data:
$timeout(function() {
$('[data-toggle="tooltip"]').each(function(index) {
// sometimes the title is blank for no apparent reason. don't override in these cases.
if ($(this).attr("title").length > 0) {
$( this ).attr("data-original-title", $(this).attr("title"));
}
});
$timeout(function() {
// finally, activate the tooltips
$(document).tooltip({ selector: '[data-toggle="tooltip"]'});
}, 500);
}, 1500);
What's happening here in essence is:
Wait some time (1500 ms) for the digest cycle to complete, and the titles to be updated.
If there's a title property that is not empty (i.e. it has changed), copy it to the data-original-title property so it will be picked up by Bootstrap's toolips.
Reactivate the tooltips
Hope this long answer helps someone who may have been struggling as I was.
Try the Tooltip (ui.bootstrap.tooltip). See Angular directives for Bootstrap
<button type="button" class="btn btn-default"
tooltip-placement="bottom" uib-tooltip="tooltip message">Test</button>
It is recommended to avoid JavaScript code on the top of AngularJS
for getting tooltips to refresh when the model changes, i simply use data-original-title instead of title.
e.g.
<i class="fa fa-gift" data-toggle="tooltip" data-html="true" data-original-title={{getGiftMessage(gift)}} ></i>
note that i'm initializing use of tooltips like this:
<script type="text/javascript">
$(function () {
$("body").tooltip({ selector: '[data-toggle=tooltip]' });
})
</script>
versions:
AngularJS 1.4.10
bootstrap 3.1.1
jquery: 1.11.0
AngularStrap doesn't work in IE8 with angularjs version 1.2.9 so not use this if your application needs to support IE8
impproving #aStewartDesign answer:
.directive('tooltip', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
element.hover(function(){
element.tooltip('show');
}, function(){
element.tooltip('hide');
});
}
};
});
There's no need for jquery, its a late anwser but I figured since is the top voted one, I should point out this.
install the dependencies:
npm install jquery --save
npm install tether --save
npm install bootstrap#version --save;
next, add scripts in your angular-cli.json
"scripts": [
"../node_modules/jquery/dist/jquery.min.js",
"../node_modules/tether/dist/js/tether.js",
"../node_modules/bootstrap/dist/js/bootstrap.min.js",
"script.js"
]
then, create a script.js
$("[data-toggle=tooltip]").tooltip();
now restart your server.
Because of the tooltip function, you have to tell angularJS that you are using jQuery.
This is your directive:
myApp.directive('tooltip', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.on('mouseenter', function () {
jQuery.noConflict();
(function ($) {
$(element[0]).tooltip('show');
})(jQuery);
});
}
};
});
and this is how to use the directive :
<a href="#" title="ToolTip!" data-toggle="tooltip" tooltip></a>

Resources