Angularjs Tooltip Directive Jquery Independent - angularjs

I want to create a tooltip in angularjs without using jquery or bootstrap.
I tried to make a directive where I try to find the x, y position of the parent where tooltip directive is placed. This is my link function.
element.parent().css('position', 'relative');
left = offset(element.parent()).left;
right = offset(element.parent()).right;
function offset(elm) {
try {return elm.offset();} catch(e) {}
var rawDom = elm[0];
var _x = 0;
var _y = 0;
var body = document.documentElement || document.body;
var scrollX = window.pageXOffset || body.scrollLeft;
var scrollY = window.pageYOffset || body.scrollTop;
_x = rawDom.getBoundingClientRect().left + scrollX;
_y = rawDom.getBoundingClientRect().top + scrollY;
return { left: _x, top:_y };
}
But left and right are always coming to be zero.
I couldn't find a tooltip without jquery or bootstrap dependency online. Can anyone please help me out with this?

I made a tooltip library for angularJS.
It might be a good start even though it's using JQuery for things like removing and showing.
https://github.com/jeremistadler/angular-tooltip

Related

Restrict AngularJS ng-style

I'm calculating containers heights as per viewport by ng-style through my custom method.
Everything works well, but it keeps calling the method even if the element is styled. I have a big amount of DOM elements that are need to be styled. That's why, I can't allow continuous execution for all elements. Please note, I can't use ng-class because each element contains different content. And can't use controller scope variable due to unlimited numbers of elements.
HTML:
<div class="myElement" ng-style="styleElement('myElement')">
...
...
</div>
Function:
$scope.styleElement = function (elementCls) {
var elementToSet = $('.'+elementCls+':visible');
if(elementToSet.length){
var winHeight = $( window ).height();
var eTop = elementToSet.offset().top;
if(eTop == 0){
var elemChilds = elementToSet;
var elemChildsLen = elemChilds.length;
for(var i=0;i<elemChildsLen;i++){
var elem = elemChilds[i];
var r = elem.getBoundingClientRect();
if(r.top != 0){
eTop = r.top;
i= elemChildsLen;
}
}
}
var nScrollHeight = winHeight - eTop - 20;
return {
'height': nScrollHeight + 'px',
'overflow-x': 'hidden',
'overflow-y': 'auto'
};
}
};
I've tried using a custom directive but binding DOM or writing a watcher isn't a preferable solution for me due to performance. Thanks in advance!
Use one time binding, which will only call styleElement once.
<div class="myElement" ng-style="::styleElement('myElement')">
...
...
</div>

Angular $scope.$apply exceptions when maximing a Malhar widget

I am working in the Malhar widget framework, which is based on jQuery sortable widgets. ex/ https://github.com/DataTorrent/malhar-angular-dashboard
I am working on some DOM manipulation on each widget (maximize/minimize/refresh), and running into some Angular $scope.$apply exceptions below.
Function details:
The $scope.grabSouthResizer function (working fine) is the Mahlar function that came with the framework; I just modified it slight to also refresh the Kendo UI charts.
The $scope.maxResizer function is my custom function, which is throwing $rootScope:inprog exceptions every time is hits my $scope.$apply();.
$scope.grabSouthResizer = function (e) {
var widgetElm = $element.find('.widget');
e.stopPropagation();
e.originalEvent.preventDefault();
// get the starting horizontal position
// .. code ommitted for brevity
// sets new widget width on mouseup
var mouseup = function (e) {
// calculate height change
var curY = e.clientY;
var pixelChange = curY - initY;
var widgetContainer = widgetElm.find('.widget-content');
var diff = pixelChange;
var height = parseInt(widgetContainer.css('height'), 10);
var newHeight = (height + diff);
$scope.widget.setHeight(newHeight + 'px');
$scope.$emit('widgetChanged', $scope.widget);
$scope.$apply(); // *** NO EXCEPTIONS THROWN ***
$scope.$broadcast('widgetResized', {
height: newHeight
});
// kendo chart - refresh height
var chart = widgetElm.find('.k-chart').data("kendoChart");
if (chart != undefined) {
chart.setOptions({ chartArea: { height: newHeight - (newHeight * .10) } });
chart.resize($(".k-chart"));
}
};
};
$scope.maxResizer = function (e) {
// TODO: properly restore the window to original position..
var widgetElm = $element.find('.widget');
e.stopPropagation(); // testing - same as grabSouthResizer() below
e.originalEvent.preventDefault();
var pixelHeight = widgetElm.height();
var pixelWidth = widgetElm.width();
// fyi: '.k-tree' will auto-resize, so no need to find that
var chart = widgetElm.find('.k-chart').data("kendoChart");
var treelist = widgetElm.find('.k-treelist').data("kendoTreeList");
// height differential (reduce height of container if inner widget is a treelist)
var ht_diff = (chart != undefined ? 200 : 600);
var newHeight = window.innerHeight - ht_diff;
if (!widget.maximized) {
// widget container maximize
widget.maximized = true;
$scope.widget.setWidth(window.innerWidth);
$scope.widget.setHeight(newHeight); //window.innerHeight - ht_diff);
$scope.$emit('widgetChanged', widget);
$scope.$apply(); // *** THROWS $rootScope:inprog EXCEPTIONS !!! ***
$scope.$broadcast('widgetResized', {
width: window.innerWidth,
height: newHeight
});
if (chart != undefined) {
// refresh Kendo chart
chart.setOptions({ chartArea: { height: widgetElm.height()*.9, width: widgetElm.width()*.95 } });
chart.resize($(".k-chart"));
}
}
kendoRefreshTimer(); // this work-around used instead of $scope.$apply()
}
var timer;
function kendoRefreshTimer() {
timer = $timeout(function () {
refreshKendo();
}, 1);
}
function refreshKendo() {
// Kendo chart refresh here...
}
Big question: why is $scope.$apply(); causing errors in my maxResizer function, but not in the Malhar original grabSouthResizer function ? I also understand that $scope.$apply() is NOT recommended, but it seems to be widely used as a work-around.
I would create an online plunk, but I still haven't set up this Malhar widget framework online as of yet. It's a bit complicated to set up.
Your advice is appreciated.
regards,
Bob
* UPDATE *
I updated my post to show how I've worked around this scope.apply issue by using a $timeout function, but I don't like the split-second delay in the UI. i.e. You can see the Kendo chart resizing itself, so it doesn't look so smooth.

How do I read mouse position in angularjs when a click is made?

I want to get the in-element (x, y) position of a ng-clicked element. Using clientX and clientY gets transformed by the page scroll. Using pageX and pageY is not scroll-dependent, but it is absolute. Those four properties belong to the $event object, available inside the ng-click directive. How would I calculate the in-element x and y?
In jQuery I'd do something like:
$("#something").click(function(e){
var parentOffset = $(this).parent().offset();
//or $(this).offset(); if you really just want the current element's offset
var relX = e.pageX - parentOffset.left;
var relY = e.pageY - parentOffset.top;
});
But now, I want to do it in angularjs (i.e. inside a controller, not inside a postLink function). What is a good way to do it? Is it safe to do the same but using angular.element? Or is there another way of calculating the values I need?
Edit Clarifying: In a controller, I'd try:
$scope.onClick = function($event) {
//currently I can...
var pageX = $event.pageX;
var pageY = $event.pageY;
};
But I need to transform those coordinates to clicked-element related coordinates, since those elements are absolute. Consider an appropiate HTML:
<div ng-click="onClick($event)">Nestor Kirchner</div>
this should get you started:
$scope.doClick = function(event){
var x = event.x;
var y = event.y;
var offsetX = event.offsetX;
var offsetY = event.offsetY;
// you have lots of things to try here, not sure what you want to calculate
console.log(event, x, y, offsetX, offsetY);
};
and HTML:
<div ng-click="doClick($event)"></div>
Please clarify what you are trying to calculate? Some examples?
Sample code: http://plnkr.co/edit/TnhEliSUgChCaMN4gmYn?p=preview
It will not work in mozilla firefox.
For mozilla to work use,
var offsetX = event.originalEvent.layerX;
var offsetY = event.originalEvent.layerY;

When I set an element to be visible is there a delay between then and the time I can check the element's width?

If I have:
<div id="abc" data-ng-show="abc.visible">xxx</div>
and in javascript:
$scope.abc.visible = true;
var modal = document.getElementById('abc');
var modal_width = parseInt(modal.width, 10)
var modal_height = parseInt(modal.height, 10)
var abc = $('#abc').width();
How can I now get the width of the div straight after setting the visible to true? I tried the above but it does not seem to be available to me.
Note that modal.width and modal.height both show here as undefined
Yes there is a delay. You need to watch $scope.abc.visible for changes. I've created a plunker to show you what I mean: http://plnkr.co/edit/zmPPcHVkc6RbdQvYRBtX?p=preview.

AngularJS ng-Grid and ngGridFlexibleHeightPlugin not working as I expect

I am trying to use Angular ng-grid to show some dynamic content. The grid will have 0 - 25 rows. I want to have a minimum size and then have the ng-grid auto adjust the height as items get added to the array. For some reason the auto size stops after adding 6-7 items (it even seems to depend on your resolution).
Can anyone help? What am I missing? I have a Plunker below that shows the issue.
http://plnkr.co/edit/frHbLTQ68GjMgzC59eSZ?p=preview
If you are still having issues I would suggestion not using the ng-grid and create your layout directly in html (Use DIVs, column width formatting, styles, etc...). Then populate your new layout using your $scope. Between variables, models and ng-repeat you should be able to do everything you need.
The code bellow is a modification to the plugin. It works by checking number of items in the grid data and calculating the height based on that. The options passed in to the plugin are height of row and header height.
ngGridCustomFlexibleHeightPlugin = function (opts) {
var self = this;
self.grid = null;
self.scope = null;
self.init = function (scope, grid, services) {
self.domUtilityService = services.DomUtilityService;
self.grid = grid;
self.scope = scope;
var recalcHeightForData = function () { setTimeout(innerRecalcForData, 1); };
var innerRecalcForData = function () {
var gridId = self.grid.gridId;
var footerPanelSel = '.' + gridId + ' .ngFooterPanel';
var extraHeight = self.grid.$topPanel.height() + $(footerPanelSel).height();
var naturalHeight = (grid.data.length - 1) * opts.rowHeight + opts.headerRowHeight;
self.grid.$viewport.css('height', (naturalHeight + 2) + 'px');
self.grid.$root.css('height', (naturalHeight + extraHeight + 2) + 'px');
// self.grid.refreshDomSizes();
if (!self.scope.$$phase) {
self.scope.$apply(function () {
self.domUtilityService.RebuildGrid(self.scope, self.grid);
});
}
else {
// $digest or $apply already in progress
self.domUtilityService.RebuildGrid(self.scope, self.grid);
}
};
scope.$watch(grid.config.data, recalcHeightForData);
};
};
I find using this piece of code on the stylesheet solved my problem. I disabled the plugin but it works either way.
.ngViewport.ng-scope{
height: auto !important;
overflow-y: hidden;
}
.ngTopPanel.ng-scope, .ngHeaderContainer{
width: auto !important;
}
.ngGrid{
background-color: transparent!important;
}
I hope it helps someone

Resources