【问题标题】:Loading external Templates加载外部模板
【发布时间】:2019-09-02 19:21:49
【问题描述】:

我遇到了以下问题:

我必须将外部模板加载到我的 Angular 应用程序中

这些模板的 URL 存储在数据库中

有一个模板网址:

  • 标题
  • 正文(包含内容 div)
  • 页脚

正文模板包含一个

<div id="content"></div>

到这个带有 ID 的 div 中,应该加载我的 Apps Angular 内容。

我目前的做法:

在我的 AppComponent onInit 中,我正在从数据库中加载 URL,并通过另一个 http GET 调用检索这些 URL 我正在展示一个微调器,直到所有内容都加载完毕。

我发现加载外部模板的唯一方法是 [innerHTML] 与 DomSanitizers bypassSecurity 一起加载模板,然后在我的组件中使用 Id 选择器

<html>
  <ng-container [innerHTML]='header | safeHtml'>
  <ng-container [innerHTML]='body | safeHtml'>
  <ng-container [innerHTML]='footer | safeHtml'>
</html>

然后我的组件将通过 Id 选择器插入其内容

@Component({ selector: '[id=content]', })

这是一种可行的方法,但正如您可以想象的那样,它的性能不是很好,而且可能不是最好的方法。选择器也不起作用,我的组件不在模板的 div 内

还有其他方法可以完成这个场景吗?

目前使用 index.jsp 导入这些模板,现在另一个想法是将我的 angular.json 中的 index.html 更改为单独的 index.jsp 以使构建部分变得更容易,但问题是一切开发时丢失,因为 webpack 无法处理 .jsp 文件。

【问题讨论】:

  • 您有什么理由要以如此复杂和不安全的方式加载模板?
  • 嗯,目前是这样完成的,模板由外部公司提供,现在在切换到 Angular 之后,我们正在尝试移植这种方法。原因是这些模板由该公司提供主题,并由许多不同的应用程序导入。由于 Header 还包含可以远程更改应用程序的样式。当前 index.jsp 只是导入完美工作的模板,这也应该与 angular 一起使用

标签: angular


【解决方案1】:

我能想到的唯一可能的方法是你必须使用ng-template。您可以根据后端发送的不同响应切换模板,或者创建更好的不同组件

<ng-template [ngIf]="hero">
  <div class="name">{{hero.name}}</div>
</ng-template>

【讨论】:

  • 嘿,谢谢您的回答,您有没有使用 的示例?知道如何让后端响应字符串中的选择器正常工作吗?
【解决方案2】:

经过几天的挖掘,我终于找到了一个可行的解决方案。

基本上我是通过 http.get 加载模板,添加远程 Head 并在运行时使用 body 生成一个新的动态组件。

现在它可以工作了,我将创建一个从数据库获取 url 的服务并将模板字符串返回给我,因此我只需要执行 1 个请求,我可以将其移至服务。

有一个小问题,远程头附带的样式和脚本在添加到主头后需要一些时间来加载,所以我不得不展示微调器以避免不规则的元素。

export class AppComponent {

    @ViewChild('container', {read: ViewContainerRef, static: false})
        container: ViewContainerRef;
        private componentRef: ComponentRef<{}>;

        constructor(private httpStatus: HTTPStatus,
                          private spinner: NgxSpinnerService,
                          private http: HttpClient,
                          private injectorService: InjectorService) {

        spinner.show();

        http.get('https://somedomain.com/header.php', {responseType: 'text'}).subscribe((header: string) => {
               this.injectorService.injectHeader(header);
        }, error => {
                console.log('error loading header');
        }, () =>  {
                http.get('https://somedomain.com/body.html', {responseType: 'text'}).subscribe((body: string) => {
                    this.injectorService.compileTemplate(this.componentRef, this.container, body);
                });
            });
        }
    }

app.component.html

 <div #container></div>

injector.service.ts

    @Injectable()
    export class InjectorService {


    constructor(private componentFactoryResolver: ComponentFactoryResolver,
                private compiler: Compiler) {}

    public injectHeader(includes: string): void {
        let head = document.head.innerHTML;
        head = head.concat(includes);
        document.head.innerHTML = head;
    }

    public compileTemplate(componentRef: ComponentRef<{}>, container: ViewContainerRef, html: string) {
        const metadata = {
            selector: 'runtime-sample',
            template: html
        };

        const factory = this.createComponentFactorySync(this.compiler, metadata, DynamicComponent);

        if (componentRef) {
            componentRef.destroy();
            componentRef = null;
        }

        componentRef = container.createComponent(factory);

    }

    private createComponentFactorySync(compiler: Compiler, metadata: Component, componentClass: any): ComponentFactory<any> {
        const cmpClass = componentClass || DynamicComponent;
        const decoratedCmp = Component(metadata)(cmpClass);
        @NgModule({ imports: [CommonModule, FormsModule], declarations: [ContentComponent, FilterPipe, decoratedCmp] })
        class RuntimeComponentModule { }

        const module: ModuleWithComponentFactories<any> = compiler.compileModuleAndAllComponentsSync(RuntimeComponentModule);
        return module.componentFactories.find(f => f.componentType === decoratedCmp);
    }
}

由于我加载的正文包含一个

<div id="content">

在我的 ContentComponent 中我可以使用

selector: '[id=content]'

将我的 Angular 应用加载到远程 Body

【讨论】:

    猜你喜欢
    • 2015-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-28
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多