Using TemplateRef to create a tooltip/popover directive in Angular 2

转载 2016年08月30日 16:25:11

This post is about a Component created in the context of our application development.There is a demo here, and you can find the full source code here.

Lately, the need arose to create a tooltip directive. This brought up a lot of questions we hadn’t had to face before, such as how to create markup wrapping around rendered content, or rather“what is Angular 2’s transclude?”

Turns out, using TemplateRef is very useful for this, but the road to understanding it wasn’t easy. After seeing it used in a similar fashion by Ben Nadel, I decided to take a stab at it.

TemplateRef is used when using <template> elements, or perhaps most commonly when using *-prefixed directives such as NgFor of NgIf. For *-prefixed directives (or directives in <template>elements, TemplateRef can be injected straight into the constructor of the class. For other components, however, they can be queried via something like the ContentChild decorator.

Initially, I had thought to create two directives: a TooltipDirective to be placed on the parent element, plus a TooltipTemplate directive to be placed in a template, that would then inject itself into the parent. It proved too complex, though, and after finding what could be done with the ContentChild query the implementation became much simpler.

The end result looks like this (simplified for clarity):

    selector: "[tooltip]"
export class TooltipDirective implements OnInit {
    @Input("tooltip") private tooltipOptions: any;
    @ContentChild( "tooltipTemplate" ) private tooltipTemplate: TemplateRef <Object>;
    private tooltip: ComponentRef<Tooltip>;
    private tooltipId: string;
    constructor (
        private viewContainer: ViewContainerRef,
        public elementRef: ElementRef,
        private componentResolver: ComponentResolver,
        private position: PositionService ) {
            this.tooltipId = _.uniqueId("tooltip");
    ngOnInit () {
        // Attach relevant events
    private showTooltip () {
        if (this.tooltipTemplate) {
                .then(factory => {
                    this.tooltip = this.viewContainer.createComponent(factory);
                    this.tooltip.instance["content"] = this.tooltipTemplate;
                    this.tooltip.instance["parentEl"] = this.elementRef;
                    this.tooltip.instance["tooltipOptions"] = this.options;
    private hideTooltip () {
        this.tooltip = undefined;
    private get options (): TooltipOptions {
        return _.defaults({}, this.tooltipOptions || {}, defaultTooltipOptions);
    selector: "tooltip",
    `<div class="inner">
        <template [ngTemplateOutlet]="content"></template>
    <div class="arrow"></div>`
class Tooltip implements AfterViewInit {
    @Input() private content: TemplateRef <Object>;
    @Input() private parentEl: ElementRef;
    @Input() private tooltipOptions: TooltipOptions;
    constructor (
        private positionService: PositionService,
        public elementRef: ElementRef)
    private position() {
        // top and left calculated and set
    ngAfterViewInit(): void {

The TooltipDirective requires a <template #tooltipTemplate> element, that gets rendered through a  Tooltip Component, created and injected with the templateRef containing our content. Essentially, “transcluding” it. The Tooltip component’s role is only to wrap the content with some light markup, and position itself when inserted into the page.

A lot of the actual positioning (not shown here, but in the source code) is done directly to the rendered elements, though – I faced some issued when using the host properties object, that I believe were reintroduced in the latest RC.

All in all, it was a great learning experience, and Angular 2’s <template> surely beats Angular.js’transclude. Slowly but surely Angular 2 get’s more and more demystified to me, but it is hard work getting there.


Failed to resolve directive: link报错

Failed to resolve directive: link   这个问题是因为vue 版本的问题,vue的版本升级后,取消了v-link 指定,取而代之的为 router-link 看起来更...
  • shaleilei
  • shaleilei
  • 2018年01月27日 16:25
  • 60

ui.popover 一个轻量级AngularJS表单验证提示解决方案

使用过jQuery Validation插件的童鞋估计都很喜欢它直观、炫酷的提示。当我们进入AngularJS时代,我们还能方便地实现类似的验证和错误提示效果吗?我们知道,AngularJS的inpu...
  • u010567227
  • u010567227
  • 2014年03月25日 09:12
  • 2161

Bootstrap ace 中tooltip()与popover()方法demo,亲测

需要js,css如下:                                Form Elements - Ace Admin                            ...
  • wangfengtong
  • wangfengtong
  • 2017年04月19日 16:56
  • 872


  • heroboyluck
  • heroboyluck
  • 2017年08月08日 18:10
  • 318

Angular2 series – Component, Directive, Pipe and Service

原文链接: ...
  • stepstofuture
  • stepstofuture
  • 2017年01月24日 23:48
  • 400


官网参考 1、使用popover实现弹出框内包含下拉列表和输入框 采用内容模板的形式,然后在触发p...
  • S_Dan90
  • S_Dan90
  • 2017年03月29日 20:55
  • 478

angular2.0指令 (directive) 和组件 (component) 的生命周期解析

指令 (directive) 和组件 (component) 具有生命周期,由 Angular 在创建、更新和销毁它们的过程中进行管理。 你可以通过实现一个或多个生命周期钩子接口,切入到生命周期中...
  • u010977147
  • u010977147
  • 2016年12月15日 11:37
  • 1521

angular directive 总结

什么是指令 (directive)自定义HTML元素和属性 可以把它简单的理解成在特定DOM元素上运行的函数,指令可以扩展这个元素 的功能。指令的简单实例angular.module('myApp...
  • dcsky185
  • dcsky185
  • 2016年04月21日 21:44
  • 4749

angular directive详解之replace

replace属性为true时,会替换directive指向的元素;为false时将directive的内容作为子元素插入到directive指向的元素。默认为false。 看例子: ...
  • shidaping
  • shidaping
  • 2016年11月11日 17:55
  • 1399


app.directive('datetimepicker',function(){ return {                     restrict : 'A',//表示该directiv...
  • qq_23114525
  • qq_23114525
  • 2016年05月06日 09:54
  • 1366
您举报文章:Using TemplateRef to create a tooltip/popover directive in Angular 2