Home > Back-end >  How to modify auto-generated <svg> from angular material
How to modify auto-generated <svg> from angular material

Time:11-28

I am using the < mat-progress-bar > like this:

<mat-progress-bar
        name="label"
        mode="buffer"
        [value]="percentage"
        [bufferValue]="percentage   10"
      >
</mat-progress-bar>

And it generates the following html:

<svg width="100%" height="4" focusable="false" >
    <defs>
      <pattern x="4" y="0" width="20" height="4" patternUnits="userSpaceOnUse" id="mat-progress-bar-82">
        <circle cx="2" cy="2" r="2"></circle>
      </pattern>
    </defs>
    <rect width="100%" height="100%" fill="url(whatever)"></rect>
</svg>

The thing is.. I want to modify the attributes width & r, for that, i wrote something like:

const patterns = document.getElementsByTagName("pattern")
this.renderer.setAttribute(patterns[0],"width",this.width);

which works BUT, angular itself, somehow, replaces the attributes to its defult value after one "tick"

My question is.. how can I bind width & r attributes from that auto-generared svg? or event prevent Angular from updating the attributes

I'm looking for something like:

<mat-progress-bar 
        ...
        [attr.svg.defs.pattern.width] = "width"
></mat-progress-bar>

I also try to extend matProgressBar but I don't know where this attributes values are set.

I can't found anything related

UPDATE It works as expected in stackblitz, now I'm more lost than before

@Component({
  selector: 'progress-bar-configurable-example',
  template: `
      <mat-progress-bar
      
      [mode]="'buffer'"
      [value]="value"
      [bufferValue]="value   10"
    >
  </mat-progress-bar>`,
  styleUrls: ['progress-bar-configurable-example.css'],
})
export class ProgressBarConfigurableExample implements AfterViewInit {

  value = 50;
  bufferValue = 70;

  constructor(private renderer: Renderer2){}

  ngAfterViewInit(): void {
    const patterns = document.getElementsByTagName("pattern")
    this.renderer.setAttribute(patterns[0],"width","30");

    setTimeout( ()=> this.value = this.value 20 , 1000)
    }
}

CodePudding user response:

Okay, I found the problem. The *ngFor updates < mat-progress-bar > and i was setting its attributes just in onAfterViewInit. The fix is something like

@Component({
  selector: 'progress-bar-configurable-example',
  template: `
    <div #progressBars *ngFor="let o of bars">
      <mat-progress-bar
      
      [mode]="'buffer'"
      [value]="value"
      [bufferValue]="value   10"
    >
  </mat-progress-bar>
  <br/>
  </div>`,
  styleUrls: ['progress-bar-configurable-example.css'],
})
export class ProgressBarConfigurableExample
  implements AfterViewInit
{
  value = 10;
  bufferValue = 70;
  bars = [{}, {}];
  @ViewChildren('progressBars') progressBars: any;

  constructor(private renderer: Renderer2) {}

  ngAfterViewInit(): void {

    this.progressBars.changes.subscribe(t => {
      const patterns = document.getElementsByTagName('pattern');
      this.renderer.setAttribute(patterns[0], 'width', '30');
    })
  }
}

As you can see the key thing is to subscribe to changes in @ViewChildren and setting the attributes again.

Thanks

  • Related