Make writing a habit together! This is the third day of my participation in the “Gold Digging Day New Plan · April More text Challenge”. Click here for more details.

Yeah, those of you who follow me should know that in the last article we looked at Angular development, and we already had an overview of Angular. In the custom directive part, we have been able to implement the authoring, but in the real scenario, we still need standardized management.

Angular is an upgraded version of angular.js

So, in this article, we will use Tooltip to explain the content of custom instructions.

The online renderings are as follows:

The directory structure

Based on the code project implemented in the previous article, execute the command line:

Enter the cache folder
$ cd directives

Create the tooltip folder
$ mkdir tooltip

# Go to the Tooltip folder
$ cd tooltip

Create the Tooltip component
$ ng generate component tooltip

# create tooltip directive
$ ng generate directive tooltip
Copy the code

After executing the command line above, you should have the following file directory structure for app/directive/tooltip:

│ ├─ user-list.com.html // Page │ ├─ user-list.com.scss // Page unique Style │ ├─ User-list.com ponent. Spec. Ts / / test file │ └ ─ ─ user-list.com ponent. Ts / / javascript files ├ ─ ─ tooltip. Directive. Spec. Ts / / test file ├ ─ └─ tooltip. DirectiveCopy the code

Well, HERE I put the component on the same level as the tooltip, mainly for ease of management. Of course, this varies from person to person, but you can put it in the public Components folder.

Write the Tooltip component

In the HTML file, there are:

<div class="caret"></div>
<div class="tooltip-content">{{data.content}}</div>
Copy the code

In the style file.scss, there are:

$black: # 000000;
$white: #ffffff;
$caret-size: 6px;
$tooltip-bg: transparentize($black.0.25); "// Transparentize is the syntax of sass
$grid-gutter-width: 30px;
$body-bg-color: $white;
$app-anim-time: 200ms;
$app-anim-curve: ease-out;
$std-border-radius: 5px;
$zindex-max: 100;

// :host pseudo-class selector that styles the component element itself
:host {
  position: fixed;
  padding: $grid-gutter-width/3 $grid-gutter-width/2;
  background-color: $tooltip-bg;
  color: $body-bg-color;
  opacity: 0;
  transition: all $app-anim-time $app-anim-curve;
  text-align: center;
  border-radius: $std-border-radius;
  z-index: $zindex-max;
}

.caret { / / to take off the character
  width: 0;
  height: 0;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-bottom: 6px solid $tooltip-bg;
  position: absolute;
  top: -$caret-size;
  left: 50%;
  margin-left: -$caret-size/2;
  border-bottom-color: $tooltip-bg;
}
Copy the code

Well, CSS is an amazing thing, and there will be an article about sass later…

Then, in the javascript file tooltip.component.ts, the content is as follows:

import { 
  Component, 
  ElementRef, // Element pointing
  HostBinding, 
  OnDestroy, 
  OnInit 
} from '@angular/core';

@Component({
  selector: 'app-tooltip'.// An identifier that indicates the name of my component, app-tooltip
  templateUrl: './tooltip.component.html'.// The skeleton of this component
  styleUrls: ['./tooltip.component.scss'] // Private style for this component
})
export class TooltipComponent implements OnInit {

  public data: any; // Assign a value to directive
  private displayTimeOut:any;

  // The component's own host is bound to the associated decorator
  @HostBinding('style.top') hostStyleTop! :string;
  @HostBinding('style.left') hostStyleLeft! :string;
  @HostBinding('style.opacity') hostStyleOpacity! :string;

  constructor(
    private elementRef: ElementRef
  ) { }

  ngOnInit(): void {
    this.hostStyleTop = this.data.elementPosition.bottom + 'px';

    if(this.displayTimeOut) {
      clearTimeout(this.displayTimeOut)
    }

    this.displayTimeOut = setTimeout((_ :any) = > {
      Left +.width of the target element - (tooltip.width/2)
      this.hostStyleLeft = this.data.elementPosition.left + this.data.element.clientWidth / 2 - this.elementRef.nativeElement.clientWidth / 2 + 'px'
      this.hostStyleOpacity = '1';
      this.hostStyleTop = this.data.elementPosition.bottom + 10 + 'px'
    }, 500)}// Component destruction
  ngOnDestroy() {
    // After the component is destroyed, clear the timer to prevent memory leaks
    if(this.displayTimeOut) {
      clearTimeout(this.displayTimeOut)
    }
  }
}
Copy the code

Write the tooltip directive

This is the focus of this article, specific instructions, I marked in the code

The related file tooltip.directive.ts reads as follows:

import { 
  ApplicationRef, // Global call detection
  ComponentFactoryResolver, // Create a component object
  ComponentRef, // Component instance associations and guidance to elements created by ComponentFactory
  Directive, ElementRef, 
  EmbeddedViewRef, // EmbeddedViewRef inherits from ViewRef and is used to represent UI elements defined in the template element.
  HostListener, // DOM event listener
  Injector, // dependency injection
  Input 
} from '@angular/core';

import { TooltipComponent } from './tooltip/tooltip.component';

@Directive({
  selector: '[appTooltip]'
})
export class TooltipDirective {
  @Input("appTooltip") appTooltip! :string;

  privatecomponentRef! : ComponentRef<TooltipComponent>;// Get the relative position of the target element, such as left, right, top, bottom
  get elementPosition() {
    return this.elementRef.nativeElement.getBoundingClientRect(); 
  }

  constructor(
    protected elementRef: ElementRef,
    protected appRef: ApplicationRef,
    protected componentFactoryResolver: ComponentFactoryResolver,
    protected injector: Injector
  ){}/ / create a tooltip
  protected createTooltip() {
    this.componentRef = this.componentFactoryResolver
      .resolveComponentFactory(TooltipComponent) // Bind the Tooltip component
      .create(this.injector);

    this.componentRef.instance.data = { // Bind data
      content: this.appTooltip,
      element: this.elementRef.nativeElement,
      elementPosition: this.elementPosition
    }

    this.appRef.attachView(this.componentRef.hostView); // Add a view
    const domElem = (this.componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
    document.body.appendChild(domElem);
  }
  
  / / delete the tooltip
  protected destroyTooltip() {
    if(this.componentRef) {
      this.appRef.detachView(this.componentRef.hostView); // Remove the view
      this.componentRef.destroy(); }}// Listen for mouse movement
  @HostListener('mouseover')
  OnEnter() {
    this.createTooltip();
  }
    
  // Listen for mouse movement out
  @HostListener('mouseout')
  OnOut() {
    this.destroyTooltip(); }}Copy the code

At this point, 99% of the functionality is complete, so let’s call it from the page.

Call on page

We added the following at user-list.component.html:

<p style="margin-top: 100px;">
  <! -- [appTooltip]="'Hello Jimmy'"
  <span 
    [appTooltip] ="'Hello Jimmy'" 
    style="margin-left: 200px; width: 160px; text-align: center; padding: 20px 0; display: inline-block; border: 1px solid #999;"
  >Jimmy</span>
</p>
Copy the code

TooltipDirective is declared in app.module.ts and can be invoked directly. The current results are as follows:

We implemented a bottom-centered display of tooltip, which is the bottom property of tooltip in frameworks like Angular Ant Design. Other attributes can be extended if the reader is interested.

At this point, we can very good maintenance of their own command file.

【 the 】 ✅