0

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.

  1. 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.

  2. 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. enter image description here

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.

  1. Will this work?
  2. Do I need to worry about the issues of the larger answer in the original StackOverflow discussions?
  3. 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()?
1
  • Can we connect it to formGroup?? Commented Apr 30, 2018 at 10:44

1 Answer 1

1

Here is a solution to my question 3:

ngAfterViewInit() {
    var component = <any> 
        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>  
         ` );

    component.prototype.onTap = () => {
        this.counter++;
    } 
}

I update addComponent to return the dynamically created TemplateComponent class then I add a function to the object as I would in JS. Kinda ugly but it works.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.