Home > Back-end >  Multiple instances of component causing issues when referencing DOM elements - Angular
Multiple instances of component causing issues when referencing DOM elements - Angular

Time:10-02

I created a header that reveals a shape while scrolling down the page. This worked exactly as planned however when using multiple instances of the same component (for multiple headers) all instances take on the values of the first instance.

Presumably this is because I am using GetElementById() and with multiple instances there are now multiple divs with the same ID. The way I am binding the style may also be causing similar issues.

How can I get each script to access only the DOM element within its own component and how can I dynamically set the style for those elements?

app.comonent.html

<div >
    <div >
        <app-title></app-title>
    </div>
</div>
<div >
    <div >
        <app-title></app-title>
    </div>
</div>

title.component.html

<div >
    <div >
        <span >Unity Projects</span>
        <div [style]="polygonDivStyle">
            <div  id="unityTitle"  [style]="unityClipPath">
                <svg id="triangle" width="320" height="320">
                    <polygon points="155, 30  280, 280 30, 280" stroke-width="30" stroke="#FF6EFF" fill="none" />
                </svg>
            </div>
        </div>
    </div>
</div>

title.component.ts

import { Component, OnInit, HostListener} from '@angular/core';

@Component({
  selector: 'app-title',
  templateUrl: './title.component.html',
  styleUrls: ['./title.component.css']
})

export class TitleComponent implements OnInit {
  contactClipPath!: string;
  contactTitle!: HTMLDivElement | null;
  unityClipPath!: string;
  unityTitle!: HTMLDivElement | null;
  polygonDivStyle!: string;
  
  constructor() { }
  ngOnInit(): void {
    this.unityClipPath = `-webkit-clip-path: polygon(0% 0%);`;
    this.unityTitle = document.getElementById('unityTitle') as HTMLDivElement| null
    this.RadialReveal(this.unityTitle, this.unityClipPath);
    this.polygonDivStyle = "";

  }
   @HostListener('window:scroll', ['$event'])
   onScroll(event:Event){
    this.RadialReveal(this.unityTitle, this.unityClipPath);
   }

  RadialReveal(clip:HTMLDivElement | null, clipPath:string) {
    let top = clip?.getBoundingClientRect().top;
    let scrollPercent = 0;
    if(top && visualViewport)
      scrollPercent= ((top / visualViewport.height) * 300 -100);
    if (clip != null && scrollPercent > 1 && scrollPercent < 100) {
      this.polygonDivStyle = '';
      let scrollOpposite = 100 - scrollPercent;
      if(scrollOpposite >= 0 && scrollOpposite < 33)
      {
        clipPath = `-webkit-clip-path: polygon(0% ` [scrollPercent-67] `% ,50% 33%, 0% 33%, 0% 66%, 100% 66%, 100% ` [scrollOpposite 66] `%, 50% 66%, 0% 66%);`;
      }
      else if(scrollOpposite >= 33 && scrollOpposite < 66) 
      {
        clipPath = `-webkit-clip-path: polygon(0% 0%, ` [(scrollOpposite-34)*3] `% 0% ,50% 33%, 0% 33%, 0% 100%,  ` [(scrollPercent-34)*3] `% 100%, 50% 66%, 100% 66%, 100% 100%, 0% 100%);`;
      }
      else if(scrollOpposite >= 66 && scrollOpposite <= 100) 
      {
        clipPath = `-webkit-clip-path: polygon(0% 0%, 100% 0% , 100% ` [33-scrollPercent] `% ,50% 33%, 0% 33%, 0% ` [scrollPercent 66] `%,50% 66%, 100% 66%, 100% 100%, 0% 100%);`;
      }
    }
    else if(scrollPercent > 100)
    {
      clipPath = `-webkit-clip-path: polygon(0% 0%);`;
    }
    else if(scrollPercent < 1)
    {
      clipPath = `-webkit-clip-path: polygon(0% 0%, 100% 0% , 100% 33% ,50% 33%, 0% 33%, 0% 66%,50% 66%, 100% 66%, 100% 100%, 0% 100%);`;
      this.polygonDivStyle = 'filter: drop-shadow(10px 10px 200px #ff00ff) drop-shadow(-10px -10px 50px #ff00ff);'
      
      
    }
      this.unityClipPath = clipPath;
  }
  
}

CodePudding user response:

Instead of using getElementById within the title component try using @ViewChild

@Component({
  selector: 'app-title',
  templateUrl: './title.component.html',
  styleUrls: ['./title.component.css']
})

export class TitleComponent implements AfterViewInit {
    @ViewChild('unityTitle') unityTitle!: ElementRef;
    
    // your code goes here

  ngAfterViewInit(): void {
   // you can access the properties where you would normally do in elementRef
    this.unityTitle.nativeElement.style.color = '#FFFFFF';
    this.unityTitle.nativeElement.style.backgroundColor = '#5789D8';

  }
}

In your html. (Note the usage of html reference #unityTitle)

<div >
    <div >
        <span >Unity Projects</span>
        <div [style]="polygonDivStyle">
            <div #unityTitle  id="unityTitle"  [style]="unityClipPath">
                <svg id="triangle" width="320" height="320">
                    <polygon points="155, 30  280, 280 30, 280" stroke-width="30" stroke="#FF6EFF" fill="none" />
                </svg>
            </div>
        </div>
    </div>
</div>
  • Related