Is there a way to get the HTML template for the Angular * component?

I am trying to create a library of common Angular components for use in several different web projects. Along with a library of common components, I am trying to create a web project that contains and displays all of these components and code examples on how to use them.

As you can see from other queries related to the same issue, in order to display HTML code on a web page in <pre> or <code> tags, some aspects of these HTML fragments must have HTML encoded characters (i.e. > must be &gt; , < must be &lt; ). The need to make these changes manually from the source code can be quite burdensome and tedious.

I would like to find a way to read the HTML template for this component, make some text replacements necessary, and then set this value for the property that will be displayed in the view. I saw other similar SO questions that have a different and insufficient answer, for example.

If I have foo.component.ts as follows:

 import { Component } from '@angular/core'; @Component({ selector: 'foo', template: ` <div class="foo"> <div class="content"> <ng-content select="[top-content]"></ng-content> </div> <div class="extra content"> <ng-content select="[bottom-content]"></ng-content> </div> </div> ` }) export class FooComponent {} 

I want to create display-foo.component.ts with something like this:

 import { Component } from '@angular/core'; import { FooComponent } from './foo.component'; @Component({ selector: 'display-foo', template: ` <pre class="example-code"> <code> {{encodedExampleHtml}} </code> </pre> <foo> <div top-content>TOP</div> <div bottom-content>BOTTOM</div> </foo> ` }) export class DisplayFooComponent { encodedExampleHtml: string; constructor() { this.encodedExampleHtml = new FooComponent().template.replace('<', '&lt;').replace('>', '&gt;'); } } 

Essentially, this would make the template in the user interface for the next developer see and understand how to use it, as well as the actual visualized element of this type of component, and also display how the component would look when used in a real application.

The part of DisplayFooComponent that I cannot understand how to work is the line this.encodedExampleHtml = new FooComponent().template.replace('<', '&lt;').replace('>', '&gt;'); . Take this as pseudo-code for what I would like to do, because the Angular component object does not have a template property and as since I do not see any property that the template provides for this component.

Is there a way to use the Angular structure to get the HTML template for the component? Again I don't want interpolated content with replaceable expressions, but the actual raw HTML template that is associated with the element, either using the decorator property template or its templateUrl property?

+1
source share
2 answers

You can try using a special function to get annotations:

annotation.ts

 declare let Reflect: any; export function getAnnotation(typeOrFunc: Type<any>): any[]|null { // Prefer the direct API. if ((<any>typeOrFunc).annotations) { let annotations = (<any>typeOrFunc).annotations; if (typeof annotations === 'function' && annotations.annotations) { annotations = annotations.annotations; } return annotations[0]; } // API of tsickle for lowering decorators to properties on the class. if ((<any>typeOrFunc).decorators) { return convertTsickleDecoratorIntoMetadata((<any>typeOrFunc).decorators)[0]; } // API for metadata created by invoking the decorators. if (Reflect && Reflect.getOwnMetadata) { return Reflect.getOwnMetadata('annotations', typeOrFunc)[0]; } return null; } function convertTsickleDecoratorIntoMetadata(decoratorInvocations: any[]): any[] { if (!decoratorInvocations) { return []; } return decoratorInvocations.map(decoratorInvocation => { const decoratorType = decoratorInvocation.type; const annotationCls = decoratorType.annotationCls; const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : []; return new annotationCls(...annotationArgs); }); } 

and then

 this.encodedExampleHtml = getAnnotation(FooComponent).template; 

Plunger example

see also

+3
source

yurzui's answer works fine for Angular 4.4.2, but not for 5.0.2. The annotation mechanism has changed: a property is used to store metadata instead of Reflect.defineMetadata (). Since it is not documented, it can only be found in code:

 const /** @type {?} */ TypeDecorator = (function TypeDecorator(cls) { const /** @type {?} */ annotations = Reflect.getOwnMetadata('annotations', cls) || []; annotations.push(annotationInstance); Reflect.defineMetadata('annotations', annotations, cls); return cls; }); 

in Angular 4.4.2 ( @angular/core/@angular/core.js , l.356) to

 const ANNOTATIONS = '__annotations__'; const /** @type {?} */ TypeDecorator = /** @type {?} */ (function TypeDecorator(cls) { // Use of Object.defineProperty is important since it creates non-enumerable property which // prevents the property is copied during subclassing. const /** @type {?} */ annotations = cls.hasOwnProperty(ANNOTATIONS) ? (/** @type {?} */ (cls))[ANNOTATIONS] : Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS]; annotations.push(annotationInstance); return cls; }); 

in Angular 5.0.2 ( @angular/core/esm2015/core.js , l.96).

Updated code to access metadata, for example. template:

 import 'reflect-metadata'; export function getAnnotation(typeOrFunc: Type<any>): any[]|null { // Prefer the direct API. if ((<any>typeOrFunc)['__annotations__']) { return (<any>typeOrFunc)['__annotations__'][0]; } // API of tsickle for lowering decorators to properties on the class. if ((<any>typeOrFunc).decorators) { return convertTsickleDecoratorIntoMetadata((<any>typeOrFunc).decorators)[0]; } // API for metadata created by invoking the decorators. if (Reflect && Reflect.getOwnMetadata) { return Reflect.getOwnMetadata('annotations', typeOrFunc)[0]; } return null; } function convertTsickleDecoratorIntoMetadata(decoratorInvocations: any[]): any[] { if (!decoratorInvocations) { return []; } return decoratorInvocations.map(decoratorInvocation => { const decoratorType = decoratorInvocation.type; const annotationCls = decoratorType.annotationCls; const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : []; return new annotationCls(...annotationArgs); }); } 
0
source

Source: https://habr.com/ru/post/1260168/


All Articles