简体   繁体   中英

How to get element reference in Angular template instead of component reference

Consider the following template:

<my-component #ref></my-component>
<my-comp-2 [maxWidth]="ref.clientWidth"></my-comp-2>

My component doesn't have a .clientWidth property on it, but the element itself that hosts my component does.

Is there a name I could use or some other similar solution for getting a reference to the element itself in the HTML alone? For instance, I would like to do something like this:

<my-component #ref="element"></my-component>

The problem is that there is no directive with the exportAs option named "element". Nor is there any built-in equivalent documented on the Angular site.

I am aware that I could add clientWidth as a property, and that I could get a reference to the element within <my-component> class via ElementRef<HTMLElement> and dependency injection, but I would like a solution that involves HTML alone. Does such a solution exist?

I feel that your answer is the correct, but as curiosity , you can make a hard-work-around: create a directive like

@Directive({
  selector: '[element-directive]',
  exportAs: 'ngDirective',
})
export class MyDirective {
  constructor(public elementRef: ElementRef){}
}

And use

<my-component element-directive #ref="ngDirective">
</my-component>
<my-comp-2 [style.max-width]="ref.elementRef.nativeElement.offsetWidth+'px'">
</my-comp-2>

The other way, as you indicate, is in constructor of my-component, inject ElementRef and make it public

constructor(public elementRef:ElementRef){}

Then, you can use

<my-comp-2 [style.max-width]="ref.elementRef.nativeElement.offsetWidth+'px'">
</my-comp-2>

Or you can create any function in my-component that return what do you want and call this function

NOTE: I use style.max-width, I don't know if your my-comp2 has an input or not

The DirectiveBinder class in the Angular compiler package appears to treat any non-named template reference as a reference to the component (if it is one) or the element (if it's not).

The relevant code is here:

  node.references.forEach(ref => {
    let dirTarget: DirectiveT|null = null;

    // If the reference expression is empty, then it matches the "primary" directive on the node
    // (if there is one). Otherwise it matches the host node itself (either an element or
    // <ng-template> node).
    if (ref.value.trim() === '') {
      // This could be a reference to a component if there is one.
      dirTarget = directives.find(dir => dir.isComponent) || null;
    } else {
      // This should be a reference to a directive exported via exportAs.
      dirTarget =
          directives.find(
              dir => dir.exportAs !== null && dir.exportAs.some(value => value === ref.value)) ||
          null;
      // Check if a matching directive was found.
      if (dirTarget === null) {
        // No matching directive was found - this reference points to an unknown target. Leave it
        // unmapped.
        return;
      }
    }

    if (dirTarget !== null) {
      // This reference points to a directive.
      this.references.set(ref, {directive: dirTarget, node});
    } else {
      // This reference points to the node itself.
      this.references.set(ref, node);
    }
  });

The first if branch is when no name is given (ie #ref or #ref="" ) and the else loops through any directives on the element being checked. Above this shows that no directives is a possibility, suggesting that there isn't some place where a special built-in "element" directive is being added.

Conclusion 1: If it's a component and there is no name in the template reference variable, then it will always refer to the component.

Conclusion 2: There are no special built-in directives in every case. Exceptions may exist for some standard HTML elements (eg <input> ), but that doesn't help us here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM