Reputation: 57
I want a template to be rendered on a button click within a element I have created that template as a seperate component (custom component) as it may be used multiple times. So when I click want this custom component to be compiled to return as a HTML String as I need to process something with the string and send the html string. Is it possible with angular.
Sample code (simply to explain my case)
import { templatecomponent } ./template.component
...
onButtonClick(): any
{
return compile(templatecomponent) // return the html from the template component
}
Upvotes: 4
Views: 7505
Reputation: 5728
I recently got into a situation where I need to parse the angular component's HTML as a string with all the bindings and stuff.
It seems Angular does not expose a method to get this done. Here is what I did to parse the component HTML as a string.
import {
Component,
ComponentFactory,
ComponentFactoryResolver,
ViewChild,
ViewContainerRef,
} from '@angular/core';
import { asyncScheduler } from 'rxjs';
import { PdfHtmlComponent } from './pdf-html.component';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
@ViewChild('pdfHtml', { read: ViewContainerRef }) container;
constructor(private resolver: ComponentFactoryResolver) {}
getPDFHtml() {
this.container.clear();
const factory: ComponentFactory<any> =
this.resolver.resolveComponentFactory(PdfHtmlComponent);
const componentRef = this.container.createComponent(factory);
componentRef.instance.title = 'Injected Title';
asyncScheduler.schedule(() => {
const htmlString = componentRef.location.nativeElement.innerHTML;
componentRef.destroy();
console.log('HTML STRING:', htmlString);
});
}
}
You can see the demo here https://parse-angular-component-html-as-string.stackblitz.io
or you can play with the code here https://stackblitz.com/edit/parse-angular-component-html-as-string?file=src/app/app.component.ts
Happy coding!!! 🎉🎉🎉
Upvotes: 1
Reputation: 54751
You can create a rendering component that will attach a view to it's own view, and then return the inner HTML.
The only issues is that the component must be rendered off page as the view has to be attached to the DOM, and you have to use a setTimeout()
to allow the child component time to finish rendering.
Alternatively, you can use a ngTemplate
reference instead of a component factory. The two are basically the same when you are attaching to a ViewContainerRef
.
Here is an example that I wrote, but I haven't tried it:
@Component({
selector: 'app-render',
template: '',
styles: [
'position: absolute',
'top: -99999',
'left: -99999'
],
exportAs: 'appRender'
})
export class RenderComponent {
constructor(private view: ViewContainerRef,
private el: ElementRef<HTMLElement>) { }
public function compile(factory: ComponentFactory<any>): Promise<string> {
return new Promise(resolver => {
this.view.createComponent(template);
setTimeout(() => {
resolver(this.el.nativeElement.innerHTML);
this.view.clear();
});
});
}
}
You have to add the <app-render>
component somewhere in your app, and then call compile(myComponent)
which returns a promise with the HTML as a string.
If your child component uses *ngIf
or *ngFor
then the duration of setTimeout()
needs to be increased, or you call multiple setTimeout()
functions. Either way, you need time for the HTML to be rendered by Angular.
It's not possible with a different approach to create synchronized function that yields HTML from a component as a string. Angular doesn't work that way.
Upvotes: 0
Reputation: 716
i think you can't just use it like above! You have selectors for the components and condition checks. You can use condition checking for click of the button if true your component will be called
Custom.component.ts
@Component({
selector: "custom-app",
template: `I am from custom component`,
style: ""
})
Calling.component.ts
@Component({
selector: "calling-app",
template: `<button (click)="customFn()">Show custom</button>
<custom-app *ngIf="isCustom"></custom-app>
`,
style: ""
})
export class CallingComponent{
isCustom: false
constructor(){}
customFn(){
this.isCustom = !this.isCustom
}
}
Don't forget to configure the modules
Upvotes: 3