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):

@Directive({
    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) {
            this.componentResolver.resolveComponent(Tooltip)
                .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.destroy();
        this.tooltip = undefined;
    }
 
    private get options (): TooltipOptions {
        return _.defaults({}, this.tooltipOptions || {}, defaultTooltipOptions);
    }
}
 
@Component({
    selector: "tooltip",
    template:
    `<div class="inner">
        <template [ngTemplateOutlet]="content"></template>
    </div>
    <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 {
        this.position();
    }
}

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.

原文链接: https://stacksandfoundations.com/2016/07/13/using-templateref-to-create-a-tooltippopover-directive/

pip Fatal error in launcher: Unable to create process using

接上篇“Eclipse启动报错:JVM terminated. Exit code=2”,今天把Python的安装位置也从C盘剪切到了D盘,然后修改了Path环境变量中对应的盘符:D:\Python2...

kubernetes1.4 基础篇:Learn Kubernetes 1.4 by 6 steps(3):Step 2. Using kubectl to Create a Deployment

在上一篇文章中我们学习到了如何快速搭k8s的集群。本文将会将会学到Kubernetes的应用部署(Deployment),以及如何使用kubectl来部署我们的应用。被部署的应用我们将直接使用kube...

How to Create and Optimize Sprite Sheets in Cocos2D with Texture Packer and Pixel Formats

How to Create and Optimize Sprite Sheets in Cocos2D with Texture Packer and Pixel FormatsLike this p...

How To Create Buttons in Cocos2D: Simple, Radio, and Toggle

How To Create Buttons in Cocos2D: Simple, Radio, and ToggleLike this post? Follow me on Twitter!Butt...

Using #region Directive With JavaScript Files in Visual Studio

本文转载自:http://blog.devarchive.net/2008/04/using-region-directive-with-javascript.html 这是一个不错的小创意,可...

转:SIMPLE DIRECTIVE TO LAZY LOAD IMAGES IN YOUR IONIC APP

转:Simple Directive to Lazy load images in your ionic app.

GOOD_JSTL配置问题:According to TLD or attribute directive in tag file

http://blog.csdn.net/xiaofei14/article/details/4091577 JSTL配置问题:According to TLD or attribute dire...
  • Baple
  • Baple
  • 2015年03月27日 16:33
  • 684

解决:According to TLD or attribute directive in tag file, attribute value does not accept any express。

背景:在mysql中有一个字段声明为datetime类型,在用hibernate映射时对应的类型为java.util.Date。因此从数据库中读出来,在前台jsp页面显示时,日期格式为年月日,时分秒,...

According to TLD or attribute directive in tag file, attribute items does not accept any expression

今天在使用JSTL的时遇到一个错误,如下 According to TLD or attribute directive in tag file, attribute items does...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Using TemplateRef to create a tooltip/popover directive in Angular 2
举报原因:
原因补充:

(最多只允许输入30个字)