I've have a requirement to download content from a server and integrate the content into my Nativescript/Angular2 app. The content provider would like to have the ability to format the text. I've worked with both HtmlView and WebView and they have some limitations.
WebView can't dynamically grow to fit the size of the content in a StackLayout for example. And it creates a scrolled area which doesn't fit the user experience we want to provide.
HtmlView has very limited support for HTML/CSS formatting particularly on Android.
<font color='green'>
for example doesn't work!
So I've started looking into generating Angular2 components dynamically. That is download the template from the server. I've been following the discussion in the SO Answer and have had some success with it. The UI is rendered from a simple string provided at runtime, yea! The sample project can be found on github, dynamic-demo.
To do this I've updated the NG template project like this:
@Component({
selector: "my-app",
templateUrl: "app.component.html",
})
export class AppComponent implements AfterViewInit {
@ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;
constructor(
@Inject('DynamicComponent') private _dynamicComponent: DynamicComponent
){};
ngAfterViewInit() {
this._dynamicComponent.addComponent(
this.container,
` <Label text="Hello, World!" class="h1 text-center"> </Label>
<Button text="Tap Again" (tap)="onTap()" class="btn btn-primary btn-active"> </Button>
`
)
}
public counter: number = 16;
public get message(): string {
if (this.counter > 0) {
return this.counter + " taps left";
} else {
return "Hoorraaay! \nYou are ready to start building!";
}
}
public onTap() {
this.counter--;
}
}
The heart of the enhancement is this DynamicComponent class I added:
import { Injectable, Compiler, Component, NgModule, ViewContainerRef} from '@angular/core'
@Injectable()
export class DynamicComponent {
constructor(private compiler: Compiler) {}
public addComponent(container: ViewContainerRef, template: string) {
@Component({template: template})
class TemplateComponent {
onTap(args) {
console.log('onTap()');
}
}
@NgModule({declarations: [TemplateComponent]})
class TemplateModule {}
const mod = this.compiler.compileModuleAndAllComponentsSync(TemplateModule);
const factory = mod.componentFactories.filter((comp) =>
comp.componentType === TemplateComponent
);
const component = container.createComponent(factory[0]);
}
}
I would like to get general feedback on my approach.
- Will this work?
- Do I need to worry about the issues of the larger answer in the original StackOverflow discussions?
- How can I set it up so I can provide that tap action functions as inputs to the DynamicClass and not imbedded them in the class like I've done with
with
onTap()
?