Popover content always close when click to focus cursor on Popover body
here my popover directive
angular.module('collect').directive('popover', function($timeout){
return {
restrict : 'E',
replace : true,
link: function(scope, element, attrs) {
var popover = null;
// define popover for this element
$timeout(function() {
// TODO: maybe can continue using $(element) or just element instead of saving popover var
popover = $(element).popover({
html: true,
placement: scope.placement || "top",
// grab popover content from the next element
content: $(element).siblings(".pop-content").contents(),
});
popover.on('show.bs.popover', function($event) {
//hide any visible popover
$('.popover').not($(element)).popover('hide');
});
},0 , false);
var unbinder = scope.$on(
"$destroy",
function handleDestroyEvent() {
if (popover) {
popover.off('show.bs.popover');
popover = null;
}
$(element).off('.popover.data-api'); // TODO: I think this is only for jquery, not bootstrap
$(element).popover('destroy');
element.remove();
unbinder();
}
);
$("body").on("click touchstart", '.popover', function() {
$(this).popover("show");
$('.popover').not(this).popover("hide"); // hide other popovers
return false;
});
}
};
});
and this one is how I use popover
<span>
<popover class="tbl-act-btn action-column action-column-ic popover-btn" title="Comments">
<span title="{{columnName}}">
<i class="fa" ng-class="{'fa-comments-o' : !isComment(commentContentTemp), 'fa-comments' : isComment(commentContentTemp)}"></i>
</span>
</popover>
<div ng-hide="true" class="pop-content">
<div class="form-group">
<textarea class="popover-textarea form-control" name="comment" ng-model="commentContentTemp"></textarea>
<div class="popover-footer">
<button type="button"
class="glyphicon glyphicon-ok btn btn-primary popover-submit" aria-hidden="true" ng-click="updateComment($event)"></button>
<button type="button" class="glyphicon glyphicon-remove btn btn-default popover-cancel" aria-hidden="true" ng-click="cancelUpdateComment($event)"></button>
</div>
</div>
</div>
It always close Popover when I click on textArea to edit text. I want it close whenever click on update, cancel, or outside Popover.
Related
I have a list of elements, each containing a ng-click. Nested inside each element is a div that should toggle a Bootstrap modal.
I have added the $event.stopPropagation to the nested div because i don't want the ng-click event from the parent element to fire, but this causes the modal to not begin displayed.
<div id="segment{{segment.Id}}" class="message" ng-class="{activeSegment: segment.Selected}" ng-click="!segmentIsLoaded || selectSegment(segment)">
<div>
<div class="pull-left">
<span>ID: {{segment.Id}}</span>
<span>{{segment.Name}} </span>
<i class="fa fa-info-circle fa-lg" data-toggle="tooltip" data-original-title="{{segment.Description}}" tooltip></i><br />
<small>{{formatJsonDate(segment.Updated)}}</small>
</div>
<div class="btn btn-danger pull-right" data-toggle="modal" data-target="#deleteSegmentModal" ng-click="$event.stopPropagation();">
<span><i class="fa fa-trash-o" aria-hidden="true"></i></span>
</div>
</div>
</div>
Any known work-arounds for this?
I should perhaps mention that the stopPropagation() works as far as preventing the click event from firing. My issue is with the bootstrap modal not being activated through data-toggle attribute
Have you tried using a directive
<a ng-click='expression' stop-event='click'>
.directive('stopEvent', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
if(attr && attr.stopEvent)
element.bind(attr.stopEvent, function (e) {
e.stopPropagation();
});
}
};
});
check SO link How can I make an AngularJS directive to stopPropagation?
Is there an easy way to have one tooltip for hovering and then another one for when you click it?
On hover:
<span data-toggle="popover" data-trigger="hover" data-content="Click to show details">{{ someData }}</span>
On click:
<span data-toggle="popover" title="More details" data-trigger="hover" data-html="true" data-content="{{ someDetailedData }}">{{ someData }}</span>
Just using this directive to wrap the boostrap popover:
(function() {
"use strict";
angular
.module("app.utils")
.directive("toggle", function() {
return {
restrict: "A",
link: function(scope, element, attrs) {
if (attrs.toggle == "tooltip") {
$(element).tooltip();
}
if (attrs.toggle == "popover") {
$(element).popover();
}
}
};
});
})();
You can use on ng-mousedown="mouseov = false" and ng-mouseover="mouseov = true" attribute
Than in title you can do something like
<span>< data-toggle="popover" title="{{mouseov
? 'title on mouseover true'
: 'title on mousedown leave'}}"
data-trigger="hover" data-content="Click to show details">{{ someData }}
</span>
I have the following directive
app.directive('replybox', function ($timeout, $window, $compile, $sce) {
var linkFn = function (scope, element, attrs) {
var exampleText= element.find('p');
var btn = element.find('button');
var windowSelection="";
scope.okOrCancel="None";
exampleText.bind("mouseup", function () {
scope.sel = window.getSelection().toString();
windowSelection=window.getSelection().getRangeAt(0);
if(scope.sel.length>0) {
scope.showModal = true;
scope.$apply();
}
});
btn.bind("click", function () {
if(scope.okOrCancel=='ok'){
range = windowSelection;
var replaceText = range.toString();
range.deleteContents();
var div = document.createElement("div");
div.innerHTML = '<poper>' + replaceText + '<button type="button" class="btn btn-danger btn-xs">×</button></poper>';
var frag = document.createDocumentFragment(), child;
while ((child = div.firstChild)) {
frag.appendChild(child);
}
$compile(frag)(scope);
range.insertNode(frag);
scope.showModal=false;
}
if(scope.okOrCancel=='cancel'){
scope.showModal=false;
}
scope.selection="None";
scope.okOrCancel='None';
});
};
return {
link: linkFn,
restrict: 'A',
scope: {
entities: '=',
selection:'='
},
template: `<ng-transclude></ng-transclude>
<div class="modal fade in" style="display: block;" role="dialog" ng-show="showModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
{{sel}}
</div>
<div class="radio">
<div ng-repeat="x in entities">
<div class="radio">
<label>
<input type="radio" name="choice" ng-model="$parent.selection" ng-value = "x">
{{x}}
</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" ng-click="okOrCancel='ok'">
Ok
</button>
<button type="button" class="btn btn-primary" ng-click="okOrCancel='cancel'">
Cancel
</button>
</div>
</div>
</div>
</div>`,
transclude: true
};
});
So there is a modal in the template which contains an "Ok" and a "Cancel" button. There is an ng-click on these buttons which sets scope.okOrCancel to the appropriate value. btn binds to a button click and performs different actions depending on the state of scope.okOrCancel. When the "Ok" button is clicked everything works as expected. But the "Cancel" button requires two clicks in order for the modal to dissappear. I would think this would happen immediately within
if(scope.okOrCancel=='cancel'){
scope.showModal=false;
}
Can anyone tell me why the cancel button requires two clicks to close the modal?
Currently you have a mix of jQuery and angularjs for your ok and cancel click. Probably that is the reason to require two clicks to take effect.
If I were you, I would have write click like below:
Template:
<div class="modal-footer">
<button type="button" class="btn btn-primary" ng-click="okClick()"> Ok </button>
<button type="button" class="btn btn-primary" ng-click="cancelClick()"> Cancel </button>
</div>
In JS:
scope.okClick = function() {
range = windowSelection;
var replaceText = range.toString();
range.deleteContents();
var div = document.createElement("div");
div.innerHTML = '<poper>' + replaceText + '<button type="button" class="btn btn-danger btn-xs">×</button></poper>';
var frag = document.createDocumentFragment(), child;
while ((child = div.firstChild)) {
frag.appendChild(child);
}
$compile(frag)(scope);
range.insertNode(frag);
scope.showModal=false;
}
scope.cancelClick = function() {
scope.showModal=false;
}
scope.selection="None";
scope.okOrCancel='None';
I hope this helps you!
Cheers
Completely agree with varit05's answer. Most likely it's because you do not trigger digest cycle in the click event handler. But in any way, the point is: it's not very good idea to mix jquery and angular stuff, unless: a) you absolutely sure it's necessary; b) you understand very well what you're doing and why; otherwise it will lead to such an unexpected consequences.
Just another a small addition. Another problem is here:
$compile(frag)(scope);
range.insertNode(frag);
The correct approach would actually be to insert new nodes into real DOM and only then $compile() them. Otherwise, any directives with require: "^something" in the DOM being inserted will fail to compile because they would not be able to find necessary controllers in upper nodes until new nodes actually make it to the "main" DOM tree. Of course, if you absolutely sure you don't have that then you can leave it as is and it will work... But then the problem will just wait out there for its "finest hour".
First I tried using angular-ui
<span popover-template="removePopover.html" popover-title="Remove?" class="glyphicon glyphicon-remove cursor-select"></span>
here the template is not included and no errors are provided in console. As I undestood from previous questions this capability is still in development (using v0.13.0).
Then I tried using bootstrap's popover
<span delete-popover row-index={{$index}} data-placement="left" class="glyphicon glyphicon-remove cursor-select"></span>
This is included to popover
<div id="removePopover" style="display: none">
<button id="remove" type="button" ng-click="removeElement()" class="btn btn-danger">Remove</button>
<button type="button" ng-click="cancelElement()" class="btn btn-warning">Cancel</button>
</div>
This is the managing directive
app.directive('deletePopover', function(){
return{
link: function(scope, element, attrs) {
$(element).popover({
html : true,
container : element,
content: function() {
return $('#removePopover').html();
}
});
scope.removeElement = function(){
console.log("remove"); //does not get here
}
scope.cancelElement = function(){
console.log("cancel"); //does not get here
}
}
};
});
In case of bootstrap's popover the scope is messed up. cancelElement() call does not arrive in directive neither the parent controller.
If anyone could help me get atleast on of these working it would be great.
I have form with modal, When i click enter or add email button it generates the new text box but cursor will not move into that text box.
But i need when i click enter or add email button, then cursor automatically should move to the newly generated text box.
My html code
<script type="text/ng-template" id="myModalContent">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
<li ng-repeat="item in items " ng-form="subForm">
<input type="text" name="name" ng-model="item.email" required ng-pattern="/^[_a-z0-9]+(\.[_a-z0-9]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/" ng-enter="addOrRemove($index,item.email)"/>
<span ng-show="subForm.name.$error.required" style="color: red">Email required</span>
<span ng-show="subForm.name.$invalid" ng-hide="subForm.name.$error.required" style="color: red">Invalid email</span>
<button ng-disabled="subForm.name.$invalid || subFform.name.$dirty" ng-click="addOrRemove($index,item.email)" >{{item.value}}</button>
expression: {{subForm.name.$invalid}}
</li>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
My javascript code
$scope.addOrRemove = function(indexSelected,rcvEmail)
{//alert($rootScope.email1);
if(!rcvEmail)
{
return
}
console.log("just check email",rcvEmail);
console.log("length of the object",$scope.items.length);
event.preventDefault();
if($scope.items[indexSelected].state == 1)
{
//console.log($scope.items[indexSelected].state);
$scope.items[indexSelected].value = "Remove email";
$scope.items[indexSelected].state = "0";
$scope.items[indexSelected].email = rcvEmail;
$scope.items.push({value: "Add email", state: "1"});
}
else
{
//console.log($scope.items[indexSelected].state);
//$scope.items.push({value: "Remove email", state: "1"});
$scope.items.splice(indexSelected, 1);
}
};
see the code here
In order to focus an input you have to create custom directive.
.directive('focus', function($timeout, $parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.$watch(attrs.focus, function(newValue, oldValue) {
if(newValue) {
element[0].focus();
}
});
element.bind("blur", function(e) {
$timeout(function() {
scope.$apply(attrs.focus + "=false");
}, 0);
});
element.bind("focus", function(e) {
$timeout(function() {
scope.$apply(attrs.focus + "=true");
}, 0);
})
}
}
})
And then you can use it in the input.
<input type="text" ng-init="inp_focus = true" focus="inp_focus" />
Please check this example.
http://jsfiddle.net/Serhioromano/bu2k2cb7/