Pass in Angular data-bound text to Bootstrap Tooltip title attribute - angularjs

I am using Bootstrap tooltips on my page and I want to pass in text to the title attribute on it, using {{ }} but it doesn't work.
Here's my HTML:
<a class="questionIcon" data-toggle="tooltip" data-placement="right" title="{{textBundle.tooltip-message}}">?</a>
I am initializing the tooltips in my controller like this:
$(function () {
$('[data-toggle="tooltip"]').tooltip();
});
However, when I hover over the ?, the message that is displayed is: {{textBundle.tooltip-message}} and not the actual content. Is there a way to get the dynamic content to be inputted using the standard Bootstrap tooltip?

Agree with the comments... never, ever use jquery inside a controller. And you should use a directive. For example, my directive is called "aiTooltip", and here is how it leverages angular strap (http://mgcrea.github.io/angular-strap/#)
plunkr: http://plnkr.co/edit/DIgj8vnZFyKFtX6CjDHi?p=preview (something is awry with the placement, but you get the idea)
In your template:
<p class="link" ai-tooltip="{{ name }}">{{ name }}</p>
And in the directive we inject the $tooltip service provided by angular-strap:
app.directive('aiTooltip', function aiTooltipDirective($rootScope, $timeout, $tooltip) {
return {
restrict: 'A',
scope: {
aiTooltip: '#', // text to display in caption
},
link: function aiTooltipLink(scope, elem, attrs) {
var tooltip;
$timeout(function() {
tooltip = $tooltip(elem, {
title: scope.aiTooltip,
html: true,
trigger: scope.aiTooltipTrigger|| 'hover',
placement: scope.aiTooltipPlacement || 'top',
container: scope.aiTooltipContainer || 'body'
});
});
}
};
});
And in the $scope of the template we pass in a scope variable called name
$scope.name = 'Foobar';

Related

AngularJS directive: Produce different HTML depending on $scope variable

I just started using AngularJS and immediately ran into a problem:
I have a sidebar which contains "action-buttons" - depending on the currently active view, different buttons should be visible.
My view-controller defines an object which looks as follows:
$scope.sidebar.actionButtons = [
{ icon: "plus", label: "Add", enabled: true, url: "customer.new" },
{ icon: "minus", label: "Delete", enabled: false, action: function(){ alert("Not implemented yet"); }}
];
As you can see, there are two different kinds of action-buttons: Either the button changes to another view (url is set to customer.new), or the button triggers an arbitrary function (action is set to alert()).
Each button type has to generate some slightly different html, and I'm not able to get this working.
After playing around for several hours, here is my current (not-working) approach:
My sidebar uses the following template-code to generate the buttons:
<ul class="nav" id="sidebar-action-buttons">
<action-button ng-repeat="button in actionButtons" button="button"/>
</ul>
Now, the actionButton directive has everything it needs and should produce the html depending on the button type:
angular.module('myApp')
.directive('actionButton', function($compile) {
function linker($scope, $element, $attrs){
var innerHtml = '';
$element.attr('ng-class', '{disabled: !button.enabled}');
if($scope.button.url) {
$element.attr('ui-sref-active', 'active')
innerHtml = '<a ui-sref="{{button.url}}">';
} else {
innerHtml = '<a ng-click="button.action()">';
}
innerHtml += '{{button.label}}</a>';
$element.html(innerHtml).show();
$compile($element.contents())($scope);
}
return {
restrict: 'E',
replace: true,
scope: { button: "=" },
link: linker,
template: "<li></li>"
}
});
This generates the correct content. The problem here is, that the attributes which are placed on the actionButton element (in this case ng-class='{disabled: !button.enabled}') are not compiled.
How can a directive produce different html depending on scope variables? What is the correct approach for doing this? How can I also compile the newly added attributes?
By the time the ng-class is added to the action-button element, the digest is over with for that element. You could call $scope.$apply(), but I would add the ng-class to each anchor element instead, then there would be no need to call $scope.$apply() again.
Because you are compiling content() of the li but ng-class has been added with li itself. Simple solution is to add ng-class directly with the action-button directive i.e.
<action-button ng-repeat="button in actionButtons" button="button" ng-class="{disabled: !button.enabled}" />

"Extending" Angular UI Bootstrap Popover

(I'm kinda new to AngularJS)
I would like to create a directive which triggers a Bootstrap Popover when the user click on the element where the directive is put. To popover will have an HTML content generated inside my directive and elements in this HTML will have ng-click directives.
I "plain jQuery" it would simply be
element.popover({
content: myGeneratedContent
})
.popover('show');
// some code to attach events to the content
But I can't really figure out how to achieve this with Angular UI. Any clue ?
Thanks
--
what I want to do is a button for https://github.com/mistic100/Angular-Smilies which display all available smileys and, on click, add the corresponding shortcode to the binded model.
The ui-bootstrap docs are pretty good. However, you said you wanted to put html in your popover. The ui-bootstrap popover does not support that. We have added some "extra" popover stuff in a separate module in our project, maybe you could try something like this too.
.directive( 'popoverHtmlPopup', [ function() {
return {
restrict: 'EA',
replace: true,
scope: { title: '#', content: '#', placement: '#', animation: '&', isOpen: '&' },
templateUrl: 'template/popover/popover-html.html'
};
}])
.directive( 'popoverHtml', [ '$compile', '$timeout', '$parse', '$window', '$tooltip', function ( $compile, $timeout, $parse, $window, $tooltip ) {
return $tooltip( 'popoverHtml', 'popover', 'click' );
}])
You will need the template too of course:
angular.module("template/popover/popover-html.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/popover/popover-html.html",
"<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
" <div class=\"arrow\"></div>\n" +
"\n" +
" <div class=\"popover-inner\">\n" +
" <h3 class=\"popover-title\" ng-bind=\"title\" ng-show=\"title\"></h3>\n" +
" <div class=\"popover-content\" ng-bind-html=\"content\"> </div>\n" +
" </div>\n" +
"</div>\n" +
"");
}]);
And then use it like so:
<i title="View More Info" class="icon-info-sign"
data-popover-html="varWithHtml"
data-popover-title="More Info">
</i>
ui-bootstrap popover does support HTML template which can contain ng-click.
Replace the default template with the attribute
popover-template="nameOfYourTemplate.html"
Seems like I was no clear enough, my problem was not (yet) to add HTML in the popover bu to create the popover from my own directive.
This is a way to do it:
.directive('myDirective', function() {
return {
restrict: 'A',
template: '<span popover="content" popover-title="title"></span>',
link: function($scope) {
$scope.content = '.....';
$scope.title = '.....';
}
};
})
And about HTML content, Chi Row gave a solution which is not applicable yet with the official version (tough available on a fork https://github.com/jbruni/bootstrap-bower-jbruni)
aet version also work on the current version

Angular UI Popover load custom template

I am using Angular UI Bootstrap popover . Rather than giving the text i want to load the popover content from Div or a html template. here is the sample directive i am using
app.directive('customPopover', function () {
return {
restrict: 'A',
template: '<span>{{label}}</span>',
link: function (scope, el, attrs) {
scope.label = attrs.popoverLabel;
$(el).popover({
trigger: 'click',
html: true,
content: attrs.popoverHtml,
placement: attrs.popoverPlacement
});
}
};
});
<button popover-placement="bottom" **popover**="On the Bottom!" class="btn btn-default">Bottom</button>
How can i get custom text either from a Div or from any HTML template ?
you can directly use popover-template="your-template.html" along with the other attribs of the button, because you are already using angular bootstrap version, that shouldn't be an issue

Call a function in a angular-controller from outside of the controller?

I have a lightbox-dierective and controller that looks like this:
directive('modalDialog', function() {
return {
restrict: 'E',
scope: {
show: '='
},
replace: true, // Replace with the template below
transclude: true, // we want to insert custom content inside the directive
template: '<div class="ng-modal" ng-show="show"><div class="ng-modal-overlay" ng-click="hideModal()"></div><div class="ng-modal-dialog" ng-style="dialogStyle"><div class="ng-modal-dialog-content" ng-transclude><div class="ng-modal-close" ng-click="hideModal()">X</div></div></div></div>'
};
}).controller('Lightbox', function($scope) {
$scope.modalShown = false;
$scope.toggleModal = function() {
$scope.modalShown = !$scope.modalShown;
};
});
Here is the desierd html, what I need is to open the secon ligthbox from withing the first one:
<div ng-controller="Lightbox">
<span ng-mousedown='toggleModal()'>Open lightbox one</span>
<modal-dialog show='modalShown'>
<h2>One lightbox <span ng-mousedown='toggleModal()'>Open lightbox two</span></h2>
</modal-dialog>
</div>
<div ng-controller="Lightbox">
<span ng-mousedown='toggleModal()'>Open lightbox one</span>
<modal-dialog show='modalShown'>
<h2>another lightbox</h2>
</modal-dialog>
</div>
For most cases it works great! I use it in several occations throughout the site, with diffrent lightboxes and different content.
I have now come across a case, where I need to call one of the lightboxes from outside of the controller. Can this be achieved and in that case how do I reference the right lightbox?
I'd extend that setting to an object
var modalSet = {
shown: false,
toggle: function(){ modalSet.shown = !modalSet.shown }
}
Then put it on your main controller (the one with ngApp attribute) and have your entire scope modaleble.
Also, directives do have a controller option, but since only one modal is gonna show up at any given time, you might not want to re-create a controller for every new instance.
Upon re-reading your question: Where is it exactly -> "outside of the controller"?

unable to make custom html with angular tags work with select2

I am using angular-ui's ui-select2. I want to add custom html formatting to the selections. Select2 allows this by specifying the formatSelection in its config.
I have html with angular tags as below that I want to use for formatting the selection-
var format_code = $compile('<div ng-click="showHide=!showHide" class="help-inline"><div style="cursor: pointer;" ng-show="!!showHide" ng-model="workflow.select" class="label">ANY</div><div style="cursor: pointer;" ng-hide="!!showHide" ng-model="workflow.select" class="label">ALL</div></div>')( $scope );
var format_html = "<span>" + data.n + ' : ' + data.v +' ng-bind-html-unsafe=format_code'+ "</span>"
$scope.select_config = {
formatSelection: format_html
}
If I compile the html as in above and assign it, I just see an [object,object] rendered in the browser. If I dont compile it, I see the html rendered properly, but the angular bindings dont happen, ie the clicks dont work.
Any ideas what is wrong?
I had the same problem, select2 loading in a jquery dialog and not using the options object I would give it.
What I ended up doing is isolating the element in a directive as following:
define(['./module'], function (module) {
return module.directive('dialogDirective', [function () {
return {
restrict: 'A',
controller: function ($scope) {
console.log('controller gets executed first');
$scope.select2Options = {
allowClear: true,
formatResult: function () { return 'blah' },
formatSelection: function () { return 'my selection' },
};
},
link: function (scope, element, attrs) {
console.log('link');
scope.someStuff = Session.someStuff();
element.bind('dialogopen', function (event) {
scope.select2content = MyResource.query();
});
},
}
}]);
and the markup
<div dialog-directive>
{{select2Options}}
<select ui-select2="select2Options" style="width: 350px;">
<option></option>
<option ng-repeat="item in select2content">{{item.name}}</option>
</select>
{{select2content | json}}
</div>
What is important here:
'controller' function gets executed before html is rendered. That means when the select2 directive gets executed, it will already have the select2Options object initialized.
'link' function populates the select2content variable asynchronously using the MyResource $resource.
Go on and try it, you should see all elements in the dropdown as "blah" and selected element as "my selection".
hope this helps, that was my first post to SO ever.

Resources