简体   繁体   中英

canvas not displaying in ng-template in Angular

I'm using Angular 8

I have a canvas element which has to be displayed in different child components inside the parent component but the data on it should be same.

To resolve this situation, I used ng-content in the child components like

Component A and B has HTML contains

<div class="child">
  <ng-content select=["canvasPreview]"></ng-content>
</div>

And ParentComponent has

 <mat-horizontal-stepper labelPosition="bottom" #stepper (selectionChange)="onSelectionChange($event)">

  <mat-step>
      <ng-template matStepLabel>Upload Image</ng-template>

      <app-upload-background-image
        [(previewImage)]="previewImage"
        (previewImageChange)="onPreviewImageChange($event)">
      </app-upload-background-image>

  </mat-step>

  <mat-step>
      <ng-template matStepLabel>Place Canvas A</ng-template>

      <app-a>
        <div canvasPreview *ngTemplateOutlet="canvas"></div>
      </app-a>
  </mat-step>

  <mat-step>
    <ng-template matStepLabel>Design Canvas B</ng-template>

    <app-b>
      <div canvasPreview *ngTemplateOutlet="canvas"></div>
    </app-b>
  </mat-step>

</mat-horizontal-stepper>

<ng-template #canvas>
   <app-canvas-child></app-canvas-child>
</ng-template>

The app-canvas-child component has the canvas element

canvas-child.component.html

<div class="title">Canvas Success</div>

<canvas height="400" width="500">

But in the Parent component, it displays Canvas Success title from the app-canvas-child component, but the canvas area is blank. Same using in the parent component directly (outside ng-template) works fine and displays the canvas.

I think this problem occurs, because angular cloning elements for content-projections. If a canvas-node is cloned its context it lost . In your case you have to provide the canvas-context of the parent-component.

stackblitz: https://stackblitz.com/edit/canvas-cloning-angular

AppComponent:

import { Component, ViewChild, TemplateRef,ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  @ViewChild('c',{static:false}) canvas;
  ctx

  constructor(private cdRef:ChangeDetectorRef) {

  }

  ngAfterViewInit() {
    const c = this.canvas.nativeElement
    this.ctx = c.getContext("2d");
    this.ctx.fillStyle = "#FF0000";
    this.ctx.fillRect(0, 0, 150, 75);
    this.cdRef.detectChanges();
  }

  change() {
    console.log("ADS")
    this.ctx.fillStyle = "#FFff00";
    this.ctx.fillRect(0, 0, 150, 75);
    this.canvas = { ... this.canvas }
  }
}

AppComponent-tpl:

<h1>In Parent:</h1>
<canvas #c width="200" height="100"></canvas>

<child [canvasAAA]="canvas"></child>
<child [canvasAAA]="canvas"></child>
<child [canvasAAA]="canvas"></child>
<button (click)="change()">change</button>

ChildComponent:

import { Component, Input, ViewChild } from '@angular/core';

@Component({
  selector: 'child',
  template: `<h2>In Child</h2><canvas #c width="200" height="100"></canvas><hr>`,
})
export class ChildComponent  {
  @Input() canvasAAA;
  @ViewChild('c',{static:false}) c;

  ngOnChanges(){
    if(!this.c || !this.canvasAAA){
      return;
    }
    console.log(this.canvasAAA)
    var context = this.c.nativeElement.getContext('2d');

    //set dimensions
    this.c.nativeElement.width = this.canvasAAA.nativeElement.width;
    this.c.nativeElement.height = this.canvasAAA.nativeElement.height;

    //apply the old canvas to the new one
    context.drawImage(this.canvasAAA.nativeElement, 0, 0);

  }
}

I think you'll have to use ngProjectAs . I've written anarticle on it.

You should modify your code like this:

  <mat-step>
      <ng-template matStepLabel>Place Canvas A</ng-template>

      <app-a>
        <div ngProjectAs="[canvasPreview]" *ngTemplateOutlet="canvas"></div>
      </app-a>
  </mat-step>

  <mat-step>
    <ng-template matStepLabel>Design Canvas B</ng-template>

    <app-b>
      <div ngProjectAs="[canvasPreview]" *ngTemplateOutlet="canvas"></div>
    </app-b>
  </mat-step>

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