How to render custom directive inside ui-bootstrap tooltip - angularjs

I have following code
// Template
<span>
hello world!
</span>
// Directive
'use strict';
var referenceFieldTemplate = require('./reference-field.html');
module.exports = directiveFunction;
/* #ngInject */
function directiveFunction($http) {
return {
restrict: 'E',
scope: {
fieldName: '=',
fieldValue: '='
},
templateUrl: referenceFieldTemplate,
controller: function($scope){
console.log($scope);
},
link: function(scope, element, attr) {
element.bind('mouseover',function(e) {
console.log(e);
});
}
}
}
I'm trying to render custom directive in uib-tooltip using following code
function eventRender(event, element, view) {
var hoverMarkup = '\'<reference-field field-name="test" field-value="test"></reference-field>\''
element.attr({
'uib-tooltip-html': hoverMarkup,
'tooltip-append-to-body': true,
'tooltip-class': 'tooltip-wrapper'
});
$compile(element)($scope);
};
After compilation, the directive is not there in DOM. I want to understand the reason why it's not getting rendered. There are no errors in console.
Thanks in advance.

I've done recently something similar using "uib-tooltip-template", put all your html code inside the template and it will work just fine.
You just need to create a html file with your directive inside and asign it via $scope to the tooltip.

Related

Typeerror - Not a function in angular directive

I have defined a custom click directive as below:
(function() {
'use strict';
angular.module('myApp.core')
.directive('customClick', customClick);
customClick.$inject = ['$rootScope'];
function customClick() {
return {
restrict: 'A',
/*scope: {
customClick: '&'
},*/
link: function(scope, element, attrs){
$(element).on('click', function(e) {
scope.$apply(function() {
console.log("Hello..customClick..");
scope.customClick();
});
});
}
};
}
})();
And I get the following error on this;
Error logged by WDPR Angular Error handler service {xx.."stacktrace":"TypeError: a.customClick is not a function","cause":"unknown cause"}(anonymous function)bowerComponents.js:5745
How can I resolve this? If I add scope with '&' I get demanding isolated scope. Hence how to resolve it?
If I remove - scope.customClick();, it does not show anything on second html for custom-click, it has impact on only 1 html, and its controller. I want to use it in multiple controller + html.
customClick is a function on the directive itself. It is not a function on the scope. That's why the error has occurred.
link is used to manipulate dom/add event handlers on elements, which you have rightly done with element.bind('click', function() {
Whenever click occurs, the function binded to click automatically gets invoked. There is no need of watch and the invoking statement.
Your link can just be
link: function(scope, element){
element.bind('click', function() {
console.log("Hello..customClick..");
});
}
As you have used camel case in naming the directive, exercise caution in its usage in template.
You can use it as <p custom-click>hi</p>
I would recommend you to avoid using jQuery in angular apps. Try following
angular.module('newEngagementUI.core')
.directive('customClick', customClick);
customClick.$inject = ['$rootScope'];
function customClick() {
return {
restrict: 'A',
scope: {
customClick: '&'
},
link: function(scope, element, attrs){
element.bind('click', function () {
scope.customClick();
})
}
};
}
In your template:
<div custom-click="clickFunction"></div>
And your template controller should be like:
angular.module('myApp', []).controller(['$scope', function ($scope) {
$scope.clickFunction = function () {
alert('function passed');
}
}])
Working fiddle here: https://jsfiddle.net/xSaber/sbqavcnb/1/

AngularJS Directive integrating bootstrap tooltip

I have a bootstrap tooltip which isnt rendering within my NG-repeat from my research I see the tooltip wont render on angular driven content and a directive should be created to handle this issue to establish it.
If I have an existing directive relating to this ng-repeat is it possible to include this in the existing directive?
From another stackoverflow article I took on board their tooltip function and tried to apply it to my existing directive but it isn't working:
(function () {
'use strict';
angular
.module("tpAccStatus")
.directive(["tpAccStatusTransactionRow", tpAccStatusTransactionRow], ["tooltip", tooltip]);
function tpAccStatusTransactionRow() {
return {
scope: {
trans: "=tpAccStatusTransactionRow",
accountNumber: "=",
setMessageState: '&'
},
restrict: "A",
replace: true,
templateUrl: "tpAccStatusTransactionRow.directive.html",
bindToController: true,
controller: "tpAccStatusTransactionRowCtrl",
controllerAs: "transCtrl"
};
}
function tooltip() {
return {
restrict: 'A',
link: function (scope, element, attrs) {
$(element).hover(function () {
$(element).tooltip('show');
}, function () {
$(element).tooltip('hide');
});
}
};
}
})();
Within my directive template I then reference:
<td><span tooltip data-toggle="tooltip" title="" data-original-title="Select an Account"><span class="fa fa-sort fa-fw"></span></span></td>
Thanks

Cant use directive controller values in directive template

Im having a hard time accessing the attributes passed in to my directive from the template of that directive. I want to be able to access 'companyId' from album.tmpl.html but no matter what i try i can't get it. The strangest part is i can see it has made its way in to the controller, but somehow it's not getting from the controller to the template. I know the template is correctly calling the controller as it can succesfully print out the value of 'testVar' which is initialised inside the controller. Any advice would be appreciated.
directive + directive controller
(function () {
'use strict';
angular.module('erCommon')
.directive('erAlbum', albumDirective)
.controller('AlbumController', AlbumController);
function AlbumController() {
var vm = this;
vm.testVar = "test var initiated";
}
function albumDirective($log) {
function albumLink(scope, element, attrs, AlbumController) {
//watch vars in here
}
return {
restrict: 'E',
scope: {
companyId: '=companyId'
},
bindToController: true,
templateUrl: 'components/temp/album.tmpl.html',
controller: 'AlbumController',
controllerAs: 'albumCtrl',
link: albumLink
};
}
})();
template ( album.tmpl.html
<div ng-controller="AlbumController as albumCtrl">
testVar: {{albumCtrl.testVar}}<BR>
companyId:{{albumCtrl.companyId}}<BR>
</div>
usage
<er-album company-id="2"></er-album>
output
test var: test var initiated
companyId:
You need to remove ng-controller from your template:
<div>
testVar: {{albumCtrl.testVar}}<BR>
companyId:{{albumCtrl.companyId}}<BR>
</div>
To achieve the result you wanted i had to modify the structure of your code slightly. Hope this helps you to understand the issue. Look for materials about isolated scopes which Angular uses with directives.
HTML:
<div ng-app="erCommon" ng-controller="AlbumController as albumCtrl">
<er-album company-id="2" test = "albumCtrl.testVar"></er-album>
</div>
Controller:
angular.module('erCommon', [])
.directive('erAlbum', albumDirective)
.controller('AlbumController', AlbumController);
function AlbumController() {
var vm = this;
vm.testVar = "test var initiated";
}
function albumDirective() {
return {
restrict: 'E',
scope: {
test: '=test',
companyId: '#companyId'
},
template: '<div> testVar: {{test}}<BR> companyId:{{companyId}}<BR> </div>', // it will work fine with templateUrl as well, just didn't want to cr8 another file...
link: function(scope, element, attrs){
//do whatever else you might need;
}
};
}

KendoUI not working in AngularJS directive with transclude = true

In this example, I have two AngularJS KendoDatePickers. The first one works perfectly, if you click on the button you open the calendar. The second one is within a directive that has the transclude attribute set to true. If you click on the second button, you get an error.
My understanding is that the scope of the transcluded portion inherits from the control scope, so this should work. Where am I wrong?
This is the plunk
HTML
<input kendo-date-picker="picker" />
<button ng-click="openPicker()">Open Date Picker</button>
<my-window>
<input kendo-date-picker="picker2" />
<button ng-click="openPicker2()">Open Date Picker 2</button>
</my-window>
Javascript
var app = angular.module("app", [ "kendo.directives" ]);
app.controller('MyCtrl', function($scope) {
$scope.openPicker = function () {
$scope.picker.open();
};
$scope.openPicker2 = function () {
$scope.picker2.open();
};
});
app.directive('myWindow', function() {
return {
transclude: true,
scope: {
someVar: '='
},
restrict: 'EA',
template: function(element, attrs) {
var html = '<div ng-transclude></div>';
return html;
}
};
});
There are two things about your code:
first: you create an isolatedScope so you do not have access to the controller scope inside the directive scope.
second: transcluded content get their own scope. One way to work around this is by not using transclude at all, like the example below:
return {
transclude: false,
restrict: 'EA',
template: function(element, attrs) {
var html = '<div>'+element.html()+'</div>';
return html;
}
or use the link function and manually transclude the element with the scope of the directive

How do I create an AngularJS tooltip directive with a compiled template?

I've searched the internet long and hard and found no straight answer. My question is simple, I want to have something like this in my markup:
<div my-tooltip-template="'mytt.tpl.html'" my-tooltip-scope="myDataItem">Some text...</div>
EDIT: Where myDataItem is a scope variable which contains my data object, and with a template which might look like:
<h1>{{dataItem.title}}</h1>
<span>{{dataItem.description}}</span>
And I want to have that template compiled with the a scope which contains myDataItem as dataItem and displayed as a tooltip. As far as I could tell by experimenting with ui-bootstrap tooltip module, the way to inject html into a tooltip is by using the directive tooltip-html-unsafe but the html injected doesn't get compiled, i.e., angular expressions are not evaluated, directives are not expanded, etc.
How do I go about creating a directive for this? I want a lean result, I don't want to have to include jQuery or any other library, just AngularJS and ui-bootstrap.
Thanks a lot!
Here're the blueprints of how you could create a tooltip according to your requirements (or modify/encorporate this with ui-bootstrap's tooltip).
app.directive("myTooltipTemplate", function($compile){
var contentContainer;
return {
restrict: "A",
scope: {
myTooltipScope: "="
},
link: function(scope, element, attrs, ctrl, linker){
var templateUrl = attrs.myTooltipTemplate;
element.append("<div ng-include='\"" + templateUrl + "\"'></div>");
var toolTipScope = scope.$new(true);
angular.extend(toolTipScope, scope.myTooltipScope);
$compile(element.contents())(toolTipScope);
}
};
});
This, of course, doesn't have any of the actual tooltip functionality, like popup, placement, etc... - it just appends the compiled template to whatever the element that this directive applies to.
Plunker
Changed plunker with closer-to-tooltip behavior;
I was able to just copy and override the directive for the tooltip-html-unsafe
angular.module( 'ui.bootstrap.tooltip')
.directive( 'tooltipSpecialPopup', function () {
return {
restrict: 'EA',
replace: true,
scope: { content: '#', placement: '#', animation: '&', isOpen: '&' },
templateUrl: 'tooltip.tpl.html'
};
})
.directive( 'tooltipSpecial', [ '$tooltip', function ( $tooltip ) {
return $tooltip( 'tooltipSpecial', 'tooltip', 'mouseenter' );
}]);
I just changed the unsafe bit to special in the directive name and changed the template.
Here's a Plunker
I found this question searching for a classic tooltip implementation in AngularJS, jQuery (and other libraries) free.
I have built the following directive if anyone is searching for one:
app.directive('tooltip', function($sce, $compile) {
return {
restrict: 'A',
scope: {
content: '=tooltipContent'
},
link: function(scope, element, attributes) {
/* Attributes */
scope.displayTooltip = false;
/* Methods */
scope.updateTooltipPosition = function(top, left) {
tooltip.css({
top: top + 'px',
left: left + 'px',
});
};
scope.getSafeContent = function(content) {
return $sce.trustAsHtml(content);
};
/* Bootstrap */
var tooltip = angular.element(
'<div ng-show="displayTooltip" class="tooltip">\
<span ng-bind-html="getSafeContent(content)"></span>\
</div>'
);
angular.element(document.querySelector('body')).append(tooltip);
/* Bindings */
element.on('mouseenter', function(event) {
scope.displayTooltip = true;
scope.$digest();
});
element.on('mousemove', function(event) {
scope.updateTooltipPosition(event.clientY + 15, event.clientX + 15);
});
element.on('mouseleave', function() {
scope.displayTooltip = false;
scope.$digest();
});
/* Compile */
$compile(tooltip)(scope);
}
};
});
You can test it here: http://jsfiddle.net/m4sr9jmn/2/
Hope it will help !

Resources