Angular button directive incorrectly appending child element

270 views Asked by At

I'm using this loading directive for a button. My problem is when using the directive it appends the progress loader below the button, not inside of it.

I've console logged the this.elementRef.nativeElement and it returns the correct button element.

button-loader.directive.ts

import { Directive, ElementRef, Input, ViewContainerRef, Renderer2 } from '@angular/core';
import { MatButton } from '@angular/material/button';
import { MatProgressBar } from '@angular/material/progress-bar';

@Directive({
  selector: '[buttonLoader]'
})
export class ButtonLoaderDirective {
  progressElement: any;

  @Input() set buttonLoader(value: boolean) {
    this.toggle(value);
  }

  constructor(
    private viewContainerRef: ViewContainerRef, 
    private matButton: MatButton, 
    private renderer: Renderer2, 
    private elementRef: ElementRef) {
    this.loadComponent();
  }

  loadComponent() {
    this.viewContainerRef.clear();
    
    // Create Component
    const matProgress = this.viewContainerRef.createComponent(MatProgressBar);
    
    matProgress.instance.mode = 'indeterminate';
    
    // Move it
    this.progressElement = matProgress.injector.get(MatProgressBar)._elementRef.nativeElement
    
    this.renderer.appendChild(this.elementRef.nativeElement, this.progressElement);


    // Add custom class
    this.elementRef.nativeElement.classList.add('mat-load-button');
  }

  toggle(condition: boolean) {
    condition ? this.show() : this.hide()
  }

  show() {
    this.progressElement.style.opacity = '0.7';
    this.matButton.disabled = true;
  }

  hide() {
    this.progressElement.style.opacity = '0';
    this.matButton.disabled = false;
  }

}

HTML

<button 
    [buttonLoader]="true"
    mat-raised-button 
    color="primary"
>
Save
</button>

Currently how it looks

enter image description here

enter image description here

Here's how I want it to look

enter image description here

enter image description here

1

There are 1 answers

0
Flo On BEST ANSWER

Your directive works. The progressbar has the right "parent". I only have modified the progressbar style with position: absolute; and the current position + width:

Updated directive

import { Directive, ElementRef, Input, ViewContainerRef, Renderer2 } from '@angular/core';
import { MatButton } from '@angular/material/button';
import { MatProgressBar } from '@angular/material/progress-bar';

@Directive({
  selector: '[buttonLoader]'
})
export class ButtonLoaderDirective {
  progressElement: any;

  @Input() set buttonLoader(value: boolean) {
    this.toggle(value);
  }

  constructor(
    private viewContainerRef: ViewContainerRef, 
    private matButton: MatButton, 
    private renderer: Renderer2, 
    private elementRef: ElementRef) {
    this.loadComponent();
  }

  loadComponent() {
    this.viewContainerRef.clear();
    
    // Create Component
    const matProgress = this.viewContainerRef.createComponent(MatProgressBar);
    
    matProgress.instance.mode = 'indeterminate';
    
    // Move it
    this.progressElement = matProgress.injector.get(MatProgressBar)._elementRef.nativeElement

    this.renderer.appendChild(this.elementRef.nativeElement, this.progressElement);


    // Add custom class
    this.elementRef.nativeElement.classList.add('mat-load-button');
  }

  toggle(condition: boolean) {
    condition ? this.show() : this.hide()
  }

  show() {
    this.progressElement.style.opacity = '0.7';
    this.progressElement.style.position = "absolute"
    this.matButton.disabled = true;
    this.progressElement.style.bottom = "10px";
    this.progressElement.style.width = "calc(100% - 10px)"

  }

  hide() {
    this.progressElement.style.opacity = '0';
    this.matButton.disabled = false;
  }
}

HTML

  <button
    style="height: 80px"
    mat-raised-button
    color="primary"
    [buttonLoader]="true"
  >
    My Button
  </button>

Here is the complete Stackblitz example.

Here the result:

enter image description here