简体   繁体   中英

Manipulating a component's DOM elements in Angular

I am new to angular and I am trying to manipulate an instance of a component's html template based on that instance's input data. I want to take an integer value and produce the same number of stars (as the html entity &#9733) as you would see in a star rating system. I have a parent component "RatingList" that dynamically produces a "RatingCard" which contains the star rating (see photo for example). I am able to dynamically create the "RatingCard" and during ngAfterViewInit , I am trying to create the star rating. I access the element where I want to put the stars by using selectRootElement but it seems to only grab the first instance of a "RatingCard" and then adds all subsequent instances to the star ratings of that instance.

I am wondering what is the proper way to find a specific html tag in an instance of a RatingCard and then update it. I have tried declaring a variable using ViewChild but that does not seem to work. I am also wondering how to properly insert the html entity for a star. Thank you for considering this!

I've removed some code for clarity.

rating-list.component.ts

import {Component, Input, OnInit, ComponentFactoryResolver, OnDestroy, ViewContainerRef, Type} from "@angular/core";
import { RatingCardComponent} from "../rating-card/rating-card.component"

let titles = ["Road to Perdition", "Cool Hand Luke"]
let ratings =  [7, 4];
@Component({
  selector: 'app-rating-list',
  template: '<ng-template appRatingHost></ng-template>'
})
export class RatingListComponent implements OnInit {

  constructor(private vf:ViewContainerRef, private componentFactoryResolver : ComponentFactoryResolver) {}

  ngOnInit(): void {
    this.loadComponents();
  }

  loadComponents() {

    for (let index = 0; index < 2; index++) {
      const componentFactory = 
 this.componentFactoryResolver.resolveComponentFactory(RatingCardComponent);

      const componentRef = this.vf.createComponent<RatingCardComponent>(componentFactory);

      const data = {imgUrl : urls[index], title : titles[index], rating : ratings[index]};

      componentRef.instance.data = data;
      
    }
  }

rating-card.component.ts


import { Component, ElementRef, OnInit, Renderer2, ViewChild } from '@angular/core';


@Component({
  selector: 'app-rating-card',
  templateUrl: './rating-card.component.html',
  styleUrls: ['./rating-card.component.css']
})
export class RatingCardComponent implements OnInit {

  data : any;

  @ViewChild('#rating-header') rating_header? : ElementRef;

  constructor(private renderer : Renderer2, private el : ElementRef) { }



  ngOnInit(): void {
      
  }

  ngAfterViewInit()
  {
    this.setupRating(this.data.rating)
  }



  setupRating(size : Number) : void {
    for (let index = 0; index < size; index++) {
      let starContainer = this.renderer.createElement('span');
      let text = this.renderer.createText("&#9734;");
      
      this.renderer.addClass(starContainer, 'gold_full_star');
     
      this.renderer.appendChild(starContainer, text);

      const rating_header = this.renderer.selectRootElement("#rating-header", true);

      this.renderer.appendChild(rating_header, starContainer);
    }
  }

}

rating-card.component.html


<div class="card" tabindex="0">
        <img class="movieimg" height=96x width=96px alt="" src={{data.imgUrl}}/>
        <h3 class="card-title">{{data.title}}</h3>
        <h4 class="card-subtitle" id="rating-header">Rating:{{data.rating}}</h4>
        <p class="card-text">This is where I write my review ... ?</p>
    </div>

Image of what is currently displayed

why don´t you just create a star-rating.component and do the stars with an *ngFor loop using angular syntax instead of messing around with underlying dom structure?

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