且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

根据要求动态注入HTML和CSS

更新时间:2023-02-05 21:57:40

我已经找到了解决该问题的方法.感谢不和谐服务器"The Coding Den"中的某人,他给我发了消息,并给了我一个在Github上动态加载组件模板.滚动浏览这篇长文章后,我发现了对Alarm9k的回答.这是我用来创建组件的方式,该组件可以通过服务器请求根据给定的ID显示不同的模板,我还添加了一些注释来对其进行解释.

I have found the solution to this subject. Thanks to someone in the discord server "The Coding Den", he messaged me about this and give me a link to Dynamically load template for a component on Github. After scrolling through this long post I found the answer of Alarm9k. This is how I used it to create a component that could display different templates based on a given id through a server request, I have also added some comments to explain it.

import { Component, AfterViewInit, Compiler, NgModule, ViewChild, ViewContainerRef, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BookingService } from 'src/app/services/booking.service';
import { ApplicationModel } from 'src/app/models/application.model';
import { Booking } from 'src/app/models/vo/booking';
import { Subscription } from 'rxjs';
import { SplitStringPipe } from '../../utils/split-string.pipe';
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { BrowserModule } from '@angular/platform-browser';

@Component({
    selector: 'app-bookings-template',
    templateUrl: './bookings-template.component.html',
    styleUrls: ['./bookings-template.component.css']
})
export class BookingsTemplateComponent implements AfterViewInit {

    public template: string;
    public date: Date;
    public locale: string;
    public id: string;

    @ViewChild('container', { read: ViewContainerRef, static: false }) container: ViewContainerRef;

    constructor(private compiler: Compiler, private bs: BookingService, private apm: ApplicationModel) { }

    ngAfterViewInit() {
        // Must clear cache.
        this.compiler.clearCache();
        // fill in template from server request
        this.template = "<div class="test">{{test}}</div>;
        var styles = ".test{color:red}";
        // Define the component using Component decorator.
        const component = Component({
            template: this.template + "<div>Hard Coded html for error checks and loading spinner</div>",
            styles: [styles]
        })(class implements OnInit {
            //example properties
            public date: Date;
            public bookings: Array<Booking>;
            public isLoading: boolean = true;
            public hasError: boolean = false;
            public errorMessage: string;
            public errorMessageSub: Subscription;
            public bs: BookingService;
            public apm: ApplicationModel;
            // Do not pass any parameters in the constructor or it will break!
            // Instead pass it within the factory method down below as a property!
            constructor() {
                // refresh template every minute
                setInterval(() => {
                    this.ngOnInit();
                }, 60000);
                // refresh date every second
                setInterval(() => {
                    this.date = new Date();
                }, 1000);
            }

            ngOnInit() {
                // get data to fill in template
            }
            ngOnDestroy() {
                //remove error subscription
                this.errorMessageSub.unsubscribe();
            }
        });

        // Define the module using NgModule decorator.
        //Modules can be changed based on your needs
        const module = NgModule({
            imports: [
                CommonModule,
                BrowserAnimationsModule,
                BrowserModule,
                HttpClientModule],
            declarations: [component, SplitStringPipe],
            providers: [BookingService]
        })(class { });

        // Asynchronously (recommended) compile the module and the component.
        this.compiler.compileModuleAndAllComponentsAsync(module)
            .then(factories => {
                // Get the component factory.
                const componentFactory = factories.componentFactories[0];
                // Create the component and add to the view.
                const componentRef = this.container.createComponent(componentFactory);
                // pass parameters that would go in the constructor as properties
                // subscriptions should also work.
                componentRef.instance.bs = this.bs;
                componentRef.instance.apm = this.apm;
                componentRef.instance.errorMessageSub = this.apm.getMessageError().subscribe(me => componentRef.instance.errorMessage = me);
            });
    }

}

BookingsTemplateComponent充当匿名组件类的父级,该匿名组件类充当子级.这样,由于@ViewChild可以将子级添加到父级,其中@ViewChild指定了容器名称并与父级html id匹配: <div #container></div>(在这种情况下).

The BookingsTemplateComponent acts as the parent of the anonymous component class which acts as the child. This way the child can be added to the parent thanks to @ViewChild where the container name is specified and matches with the parent html id: <div #container></div> (in this case).

您还需要在应用模块中添加一些内容:

You will also need to add some things to the app module:

import { NgModule, CompilerFactory, Compiler, COMPILER_OPTIONS } from '@angular/core';
import { JitCompilerFactory } from '@angular/platform-browser-dynamic';
import { CommonModule } from '@angular/common';

export function createCompiler(compilerFactory: CompilerFactory) {
    return compilerFactory.createCompiler();
}
@NgModule({
    declarations: [
        // components and pipes
        ...
    ],
    imports: [
        CommonModule, // required
        ... //other modules
    ],
    providers: [
        // different services
        ...,
        // these are need to add the compiler manually to the project
        { provide: COMPILER_OPTIONS, useValue: {}, multi: true },
        { provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS] },
        { provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] }
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

警告:

最重要的因素是您不能在生产模式下构建项目.这样做的原因是因为JIT编译不起作用,并且您会收到以下错误: 这是因为即使您尝试手动添加,编译器也不包含在生产环境中.

WARNING:

The most important factor of this is that you cannot build the project in production mode. The reason for this is because JIT compilation doesn't work and you will get the following error: This is because the angular compiler is not included in the production environment, even when you try to add it manually.