Willem van der Veen
Willem van der Veen

Reputation: 36620

Writing custom directive for adjusting height

I'm trying to write a appHeaderResize directive which measures both the height of the <app-online-header> component and the <app-navigation> component. Here is the code:

  <div class="sticky" appHeaderResize>
    <app-online-header></app-online-header>
    <app-navigation></app-navigation>
  </div>

However I'm stuck at how can I access the height of the two components in the directive. How can I access the height from these components from the directive?

Upvotes: 0

Views: 1400

Answers (1)

vince
vince

Reputation: 8306

If you only need the height of the DOM element in your directive, you can inject the ElementRef and use it to query the DOM children. Then using Renderer2, you can set styles, attributes, etc for the elements or access their properties:

@Directive({
  selector: '[appHeaderResize]'
})
export class AppHeaderResizeDirective  {
  constructor(
    private el: ElementRef,
    private renderer: Renderer2
  ) {}

  ngAfterViewInit() {
    const arr = Array.from(this.el.nativeElement.childNodes);
    const appHeader = arr.find(node => node.tagName === 'APP-HEADER');
    this.renderer.setStyle(appHeader, 'display', 'block');
    this.renderer.setStyle(appHeader, 'color', 'red');
    this.renderer.setStyle(appHeader, 'border', '2px solid red');
    this.renderer.setStyle(appHeader, 'height', '200px');
    this.renderer.setStyle(appHeader, 'width', '200px');

    console.log(appHeader.style.height); // 200px
  }
}

(Note: there are other ways to get the node you want besides looking it up based on the tagName (and those ways don't depend on string pattern matching xD). I just used that approach for proof of concept.)

However, if you want to get the component itself, you'll need to use ViewChild and nest your elements in a real component.

@Component({
  selector: 'app-header-resize',
  template: `
  <app-header></app-header>
  `
})
export class AppHeaderResizeComponent implements AfterViewInit {
  @ViewChild(AppHeaderComponent) appHeader: AppHeaderComponent;
  @ViewChild(AppHeaderComponent, {read: ElementRef}) appEl: ElementRef;

  constructor(private renderer: Renderer2) {}

  ngAfterViewInit() {
    console.log(this.appHeader);
    const height = this.appHeader.height + 'px';
    this.renderer.addClass(this.appEl.nativeElement, 'square');
    this.renderer.setStyle(this.appEl.nativeElement, 'display', 'block');
    this.renderer.setStyle(this.appEl.nativeElement, 'height', height);
    this.renderer.setStyle(this.appEl.nativeElement, 'border', '2px solid blue');
  }
}

Here is a working app with both approaches: https://stackblitz.com/edit/app-header-child.

Upvotes: 3

Related Questions