Getting Angular UI Calendar to work with UI-Bootstrap Tooltips - angularjs

I am trying to display a tooltip on angular UI calendarEvent's mouse-hover. I managed to do this as explained in the following thread,
Tooltip for fullcalendar in year view
$scope.eventMouseover = function (calEvent, jsEvent) {
var tooltip = '<div class="tooltipevent">' + calEvent.description + '</div>';
$("body").append(tooltip);
$(this).mouseover(function (e) {
$(this).css('z-index', 10000);
$('.tooltipevent').fadeIn('500');
$('.tooltipevent').fadeTo('10', 1.9);
}).mousemove(function (e) {
$('.tooltipevent').css('top', e.pageY + 10);
$('.tooltipevent').css('left', e.pageX + 20);
});
}
$scope.eventMouseout = function (calEvent, jsEvent) {
$(this).css('z-index', 8);
$('.tooltipevent').remove();
},
Obviously, this is not the best way to do this. With the latest UI-Bootstrap, we have a much nicer looking tooltips. Did anyone successfully integrated these tooltips with the Angular-UI Calendar?
Update 1 : As explained in http://arshaw.com/fullcalendar/docs/event_rendering/eventRender/ , I tried overriding the eventRender and simply added the tool tip attribute to the calendarEvent divs. Still not working. I can see that even the mouseover and mouseout events are not added to the those calendarEvent divs that contain 'tooltip' attribute.

if you add this function to the calendar config it will work.
$scope.eventRender = function( event, element, view ) {
$timeout(function(){
$(element).attr('tooltip', event.title);
$compile(element)($scope);
});
};
Anything can be placed in the tooltip attribute. even {{bindings}}
The $timeout is there because $scope.$apply must be called. By using $timeout with no delay it is ensured that a digest will be called without ever throwing a "digest in progress" error.

Related

Bootstrap 3 Popover in Angular-UI Calendar

I'm using Angular-UI Calendar directive and Bootstrap 3 popover to attempt to create a popover on click. I tried using the day click event:
$scope.dayClick = function(event, allDay, jsEvent, view){
jsEvent.stopPropagation();
jsEvent.preventDefault();
var eventID = event.getDate();
eventID = jsEvent.target;
$(eventID).popover({
html: true,
title: 'Hello',
placement: 'bottom',
content: '<button id="close-me">Close Me!</button>'
}).parent().delegate('button#close-me', 'click', function() {
jsEvent.stopPropagation();
$(eventID).popover('hide');
return false;
});
$(eventID).popover('show');
};
The problem with this way is that it causes the calendar cells to push to the right at times or duplicate. Is there a better way I could attach the popover to the existing calendar?
Are you trying to create pop-over when any day is clicked?
If yes, then dayClick is the correct way for a popover.
Can you create a Plunk to provide more details.
I think the problem may be due to CSS.

Hide angular-ui tooltip on custom event

I've been looking around and trying out different things but can't figure it out. Is it possible to hide an angular-ui tooltip with a certain event?
What I want to do is to show a tooltip when someone hovers over a div and close it when a users clicks on it because I will show another popup. I tried it with custom trigger events but can't seem to get it working. I made this:
<div ng-app="someApp" ng-controller="MainCtrl" class="likes" tooltip="show favorites" tooltip-trigger="{{{true: 'mouseenter', false: 'hideonclick'}[showTooltip]}}" ng-click="doSomething()">{{likes}}</div>
var app = angular.module('someApp', ['ui.bootstrap']);
app.config(['$tooltipProvider', function($tooltipProvider){
$tooltipProvider.setTriggers({
'mouseenter': 'mouseleave',
'click': 'click',
'focus': 'blur',
'hideonclick': 'click'
});
}]);
app.controller('MainCtrl', function ($scope) {
$scope.showTooltip = true;
$scope.likes = 999;
$scope.doSomething = function(){
//hide the tooltip
$scope.showTooltip = false;
};
})
http://jsfiddle.net/3ywMd/
The tooltip has to close on first click and not the 2nd. Any idea how to close the tooltip if user clicks on div?
I tried #shidhin-cr's suggestion of setting $scope.tt_isOpen = false but it had the rather significant issue that, while the tooltip does fade out, it is still present in the DOM (and handling pointer events!). So even though they can't see it, the tooltip can prevent users from interacting with content that was previously behind the tooltip.
A better way that I found was to simply trigger the event used as tooltip-trigger on the tooltip target. So, for example, if you've got a button that's a tooltip target, and triggers on click...
<button id="myButton"
tooltip="hi"
tooltip-trigger="click">
</button>
Then in your JavaScript, at any point, you can trigger the 'click' event to dismiss your tooltip. Make sure that the tooltip is actually open before you trigger the event.
// ... meanwhile, in JavaScript land, in your custom event handler...
if (angular.element('#myButton').scope().tt_isOpen) {
angular.element('#myButton').trigger('click');
}
Since this triggers the actual internals of AngularUI's Tooltip directive, you don't have the nasty side-effects of the previous solution.
Basically you cannot play with the tooltip-trigger to make this work. After digging through the ToolTip directive code, I found that the ToolTip attribute exposes a scope attribute called tt_isOpen.
So in your ng-click function, if you set this attribute to false, that will make the tooltip hide.
See the updated demo here
http://jsfiddle.net/3ywMd/10/
Like this
app.controller('MainCtrl', function ($scope) {
$scope.likes = 999;
$scope.doSomething = function(){
//hide the tooltip
$scope.tt_isOpen = false;
};
})
Michael's solution got me 90% of the way there but when I executed the code, angular responded with "$digest already in progress". I simply wrapped the trigger in a timeout. Probably not the best solution, but required minimal code
// ... meanwhile, in JavaScript land, in your custom event handler...
if (angular.element('#myButton').scope().tt_isOpen) {
$timeout( function(){
angular.element('#myButton').trigger('click');
}, 100);
}
For future reference, the accepted answer angular.element('.yourTooltip').scope().tt_isOpen will not work in new versions as tooltip has been made unobservable. Therefore, the entire tootlip is removed from DOM. Simple solution is to just check if tooltip is present in DOM or not.
Borrowing from #liteflier's answer,
// ... meanwhile, in JavaScript land, in your custom event handler...
if (angular.element('.yourTooltip').length) { //if element is present in DOM
setTimeout( function(){
//Trigger click on tooltip container
angular.element('.yourTooltipParent').trigger('click');
}, 100);
}

How can I provide callbacks for an AngularStrap or Angular UI Bootstrap Popover, to execute on open and on close?

I am using the Angular UI Bootstrap popover ( http://angular-ui.github.io/bootstrap/#/popover ) and would like to specify a callback function to execute when it is opened and another for when it is closed. My use case is that I am using the popover to contain filters for a grid of data. I would like to load some remote filtering options on open, apply the selected filters only when the popover is closed.
The documentation only appears to support a few basic options but no indication of callback support. I'm not seeing anything in the source code either. Is my only option to set an interval function to check periodically if the popover is visible in the DOM?
I'm also considering Angular Strap's popover to achieve the same result, but can't seem to find the option to set callbacks there either.
Seems that Koni's and user2453461's answers no longer work as popover.js utilizes tooltip.js that does the emit event. You should be able to do the following:
$scope.$on('tooltip.show.before', function() {
console.log("show before");
});
$scope.$on('tooltip.show', function() {
console.log("show");
});
$scope.$on('tooltip.hide.before', function() {
console.log("hide before");
});
$scope.$on('tooltip.hide', function() {
console.log("hide");
});
Not sure how good an idea this is, though, as the syntax seems to change over versions.
I found a solution for AngularStrap. It emits popover-* events that I can hook into here:
https://github.com/mgcrea/angular-strap/blob/3c8bd1d37ab3b023bd79f9b0c1a6931b18e2ac84/src/directives/popover.js#L110
So using this in my popover controller I can hook into hidden/shown. This is for modals but works the same for the popover with the popover- prefix
https://github.com/mgcrea/angular-strap/issues/107#issuecomment-16701662
For me worked as user2453461 said:
$scope.$on('popover-shown', function() {
console.log("SHOWN");
});
$scope.$on('popover-hidden', function() {
console.log("HIDDEN");
});
Popover "inherits from" $tooltip, which $emits a tooltip.hide.before and then a tooltip.hide event. However, since it is $emiting and not $broadcasting, only the popover's scope (and its children, but it is unlikely to have any) has access to the event.
In my code (coffeescript), this looks like:
.directive 'ngPopoverParent', ($popover) ->
link: (scope, element, attrs) ->
popover = $popover element,
'title': attrs.title
'content': attrs.content
'animation': attrs.animation
'trigger': 'click'
popover.$promise.then ->
popover.$scope.$on 'tooltip.hide', ->
console.log('tooltip hidden!')
Relevant source:
https://github.com/mgcrea/angular-strap/blob/08167f7d5f52424b0f6fe40f3a053e134f550472/src/tooltip/tooltip.js

Sencha: How to trigger click event on li element

I've been unable to figure out how to manually fire DOM events.
Here, for example, is my attempt to fire the "click" event for a li
Ext.DomQuery.select('#mapRoutesPanel ol li:nth-child('+(index+1)+')')[0].click();
It's working fine on google chrome, but when i build android native app of same application it gives me error
Uncaught TypeError: Object #<HTMLLIElement> has no method 'click'
Ext JS provides its methods for search elements in DOM tree.
Look Sencha Fiddle - its sencha touch app, i tested it on my android(opera) and iphone(safari) its work for me
Something like this:
var liElement = Ext.get('mapRoutesPanel').down('ol li:nth-child(' + (index + 1) + ')');
Have you tried
Ext.dom.Element-method-fireEvent?
Ext.DomQuery.select('#mapRoutesPanel ol li:nth-child('+(index+1)+')')[0].fireEvent('click')
Not all touch device browsers/apps support the click event because it is a mouse event. Why don't you try using Sencha's normalized event system to bind a click handler to the component, you can then check if the <li/> was clicked inside the component's click event handler.
Sencha has already done the work for us so we can handle clicks & taps in the same manner, so take advantage of it.
Btw, event delegation from a parent element is usually more performant than binding event handlers to a bunch of different DOM elements. It looks like your binding events to elements in a loop, this is a bad practice. I just wanted to point that out too.
Here is a code example:
var cmp = Ext.getCmp('someComponentId');
cmp.on('click', function(me, event) {
if (event.currentTarget.tagName == "LI") {
// do something since the <li/> tag was clicked.
// event.currentTarget will be the <li/> DOM element,
// feel free to do with it as you please :)
}
}
I did as below in my case.
Below is the sample html code of div with li s.
<div class="menu1" id="menu1">
<ul>
<li id="students_tab">Students</li>
<li id="emps_tab">Employees</li>
</ul>
</div>
And below is the extjs code to add click event to li element.
<script type="text/javascript">
Ext.onReady(function(){
var tabs= Ext.query("li", "menu1");
Ext.each(tabs, function(item){
var el = Ext.get(item);
el.on("click", function(){
var tabName = this.id.substr(0, this.id.indexOf("_"));
alert("U have clicked on "+ tabName + " tab");
});
});
});
</script>

AngularJS modal window directive

I'm trying to make a directive angularJS directive for Twitter Bootstrap Modal.
var demoApp = angular.module('demoApp', []);
demoApp.controller('DialogDemoCtrl', function AutocompleteDemoCtrl($scope) {
$scope.Langs = [
{Id:"1", Name:"ActionScript"},
{Id:"2", Name:"AppleScript"},
{Id:"3", Name:"Asp"},
{Id:"4", Name:"BASIC"},
{Id:"5", Name:"C"},
{Id:"6", Name:"C++"}
];
$scope.confirm = function (id) {
console.log(id);
var item = $scope.Langs.filter(function (item) { return item.Id == id })[0];
var index = $scope.Langs.indexOf(item);
$scope.Langs.splice(index, 1);
};
});
demoApp.directive('modal', function ($compile, $timeout) {
var modalTemplate = angular.element("<div id='{{modalId}}' class='modal' style='display:none' tabindex='-1' role='dialog' aria-labelledby='myModalLabel' aria-hidden='true'><div class='modal-header'><h3 id='myModalLabel'>{{modalHeaderText}}</h3></div><div class='modal-body'><p>{{modalBodyText}}</p></div><div class='modal-footer'><a class='{{cancelButtonClass}}' data-dismiss='modal' aria-hidden='true'>{{cancelButtonText}}</a><a ng-click='handler()' class='{{confirmButtonClas}}'>{{confirmButtonText}}</a></div></div>");
var linkTemplate = "<a href='#{{modalId}}' id= role='button' data-toggle='modal' class='btn small_link_button'>{{linkTitle}}</a>"
var linker = function (scope, element, attrs) {
scope.confirmButtonText = attrs.confirmButtonText;
scope.cancelButtonText = attrs.cancelButtonText;
scope.modalHeaderText = attrs.modalHeaderText;
scope.modalBodyText = attrs.modalBodyText;
scope.confirmButtonClass = attrs.confirmButtonClass;
scope.cancelButtonClass = attrs.cancelButtonClass;
scope.modalId = attrs.modalId;
scope.linkTitle = attrs.linkTitle;
$compile(element.contents())(scope);
var newTemplate = $compile(modalTemplate)(scope);
$(newTemplate).appendTo('body');
$("#" + scope.modalId).modal({
backdrop: false,
show: false
});
}
var controller = function ($scope) {
$scope.handler = function () {
$timeout(function () {
$("#"+ $scope.modalId).modal('hide');
$scope.confirm();
});
}
}
return {
restrict: "E",
rep1ace: true,
link: linker,
controller: controller,
template: linkTemplate
scope: {
confirm: '&'
}
};
});​
Here is JsFiddle example http://jsfiddle.net/okolobaxa/unyh4/15/
But handler() function runs as many times as directives on page. Why? What is the right way?
I've found that just using twitter bootstrap modals the way the twitter bootstrap docs say to is enough to get them working.
I am using a modal to house a user edit form on my admin page. The button I use to launch it has an ng-click attribute that passes the user ID to a function of that scope, which in turn passes that off to a service. The contents of the modal is tied to its own controller that listens for changes from the service and updates values to display on the form.
So.. the ng-click attribute is actually only passing data off, the modal is still triggered with the data-toggle and href tags. As for the content of the modal itself, that's a partial. So, I have multiple buttons on the page that all trigger the single instance of the modal that's in the markup, and depending on the button clicked, the values on the form in that modal are different.
I'll take a look at my code and see if I can pull any of it out to build a plnkr demo.
EDIT:
I've thrown together a quick plunker demo illustrating essentially what I'm using in my app: http://embed.plnkr.co/iqVl0Wb57rmKymza7AlI/preview
Bonus, it's got some tests to ensure two password fields match (or highlights them as errored), and disables the submit button if the passwords don't match, or for new users username and password fields are empty. Of course, save doesn't do anything, since it's just a demo.
Enjoy.
There is a working native implementation in AngularStrap for Bootstrap3 that leverages ngAnimate from AngularJS v1.2+
Demo : http://mgcrea.github.io/angular-strap/##modals
You may also want to checkout:
Source : https://github.com/mgcrea/angular-strap/blob/master/src/modal/modal.js
Plunkr : http://plnkr.co/edit/vFslNmBAoKPVXtdmBXgv?p=preview
Well, unless you want to reinvent this, otherwise I think there is already a solution.
Check out this from AngularUI. It runs without twitter bootstrap.
I know it might be late but i started trying to figure out why the handler got called several times as an exercise and I couldn't stop until done :P
The reason was simply that each div you created for each modal had no unique id, once I fixed that everything started working. Don't ask me as to what the exact reason for this is though, probably has something to do with the $('#' + scope.modalId).modal() call.
Just though I should post my finding if someone else is trying to figure this out :)

Resources