Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
244 views
in Technique[技术] by (71.8m points)

angular - Get the original / raw template value of ng-content

Is it possible to get the pre-processed value of ng-content? I am building design-system docs and want to display the example code without repeating myself

html:

<tr>
  <td #contentEl>
    <ng-content #projected></ng-content>
  </td>
  <td>
    <mat-icon (click)="copyTagToClipboard()">content_paste</mat-icon>
  </td>
  <td>
    <pre>{{ contentEl.innerHTML }}</pre>
  </td>
</tr>

typescript

export class CodeExampleComponent implements OnInit, AfterContentInit {
  @ViewChild('contentEl') contentEl: HTMLTableCellElement;
  @ContentChild('template') template;
  @ViewChild('projected', { read: TemplateRef, static: true }) content;

  constructor() {}

  ngOnInit() {
    console.log(this.content);
  }

  ngAfterContentInit(): void {
    console.log(this.template);
  }
  
  copyTagToClipboard() {
    if (!this.contentEl) return;
    copyToClipboard(this.contentEl.innerHTML);
  }
}

Usage:

  <app-code-example>
    <template #template><app-footnote>Footnote</app-footnote></template>
  </app-code-example>

All I can ever get is the angular rendered contents of the ng-content/template, not the original raw template.

question from:https://stackoverflow.com/questions/65645314/get-the-original-raw-template-value-of-ng-content

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This doesn't necessarily answer your question about getting the pre-processed HTML from ng-content. However this approach can be used to solve your issue about displaying the HTML as an example. You can import the raw html as a string and use it as a variable. What I like to do is then create a component or multiple components that demonstrates usage of some component I'm documenting.

This is kind of a lot, so I put it all in a StackBlitz to try and demonstrate.

Create a file right in the src directory called typings.d.ts that allows us to import html files as text.

declare module "*.html" {
  const content: string;
  export default content;
}

Create an abstract class that all our example component need to implement. We need it to be abstract because we're going to be using QueryList later.

export abstract class Example {
  templateText: string; //the raw html to display 
}

Create a example wrapper component that displays the live example, the raw html and has your copy button

import { Component, ContentChildren, Input, QueryList } from "@angular/core";
import { Example } from "../example";

@Component({
  selector: "app-example",
  template: `
    <div class="wrapper">
        <h1>{{label}}</h1>
        <ng-content></ng-content>
    
        <br />
        <button (click)="copyTagToClipboard()">Copy Content</button>
    
        <div>
            <pre>{{ example.templateText }}</pre>
        </div>
    </div>
  `
})
export class ExampleComponent{
  @Input() label: string; 
  
  @ContentChildren(Example) items: QueryList<Example>;
  example: Example;

  ngAfterContentInit(): void {
    //grab the first thing that implements the "Example" interface
    //hypothetically this component could be re-worked to display multiple examples!
    this.example = this.items.toArray()[0];    
  }

  copyTagToClipboard() {
    alert(this.example.templateText);
  }
}

Build a component that demonstrates how to use whatever component you are documenting. Note how we import the html file as a variable and use it as an attribute of the component, satisfying the interface. Don't forget to set up the providers so QueryList can pick up on the component. You can then build as many of these examples as you need, perhaps a different component per use case.

import { Component, TemplateRef, ViewChild } from "@angular/core";
import { Example } from "../example";

// See typings.d.ts, which sets up the module that allows us to do this
import * as template from "./my-component-example.component.html";
// or const template = `<app-my-component [label]="myLabelValue"></app-my-component>`;

@Component({
  selector: "app-my-component-example",
  template,
  styleUrls: ["./my-component-example.component.css"],

  //this is so the QueryList works in the example wrapper
  providers: [{ provide: Example, useExisting: MyComponentExampleComponent }]
})
export class MyComponentExampleComponent implements Example {
  myLabelValue = "Test Label!!";
  templateText = template.default;
}

Lastly, put it all together

<app-example label="Basic Example">
  <app-my-component-example></app-my-component-example>
</app-example>

I feel like with this approach there's a lot of flexibility in you how create each example.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...