リクエストに応じてHTMLとCSSを動的に挿入する

2020-02-24 javascript html css angular

そのため、サーバーからCSSとHTMLをロードする方法を検討してきました。

私が達成したいのは、HTMLとCSSをWebサイトに送信し、色などのいくつかのユーザー定義スタイルと一緒にロードする特定のテンプレートを表示するように要求することです。

これまでのところ、私はHTMLを注入することができました:

<div [innerHTML]="template | sanitizeHtml"></div>

そして

import { Pipe, PipeTransform, SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({
    name: 'sanitizeHtml'
})
export class SanitizeHtmlPipe implements PipeTransform {

    constructor(private sanitizer: DomSanitizer) { }
    transform(value: any): any {
        return this.sanitizer.bypassSecurityTrustHtml(value);
    }

}

私はさまざまな投稿やブログから見てきました(ありがとうございます)。

私が構築しているHTMLは魅力のように機能します。

this.template = "<div class='template' style='width: 1080px; height: 1920px; background-color: #212121;'><div class='clr-row' style='padding:45px 0px 10px 25px; position: relative; width: inherit;'><div class='clr-col-5'><div style='width: 230px; height: 60px; background-image: url(*LINK_TO_IMAGE*); background-repeat: no-repeat; float: left;'></div></div></div></div>"

このHTMLは完全なテンプレートの一部です。 だから私がしたいのは、変数を使用してこれにスタイルを使用することです。

だから私が試したのはスタイルオブジェクトを作ることです:

public style: {};
public template: string;
ngOnInit(){
    this.style = {
        template: {
            "color": "#D8B088",
        }
    }
    this.template = "<div [ngStyle]='style.template' class='template' style='width: 1080px; height: 1920px; background-color: #212121;'><div class='clr-row' style='padding:45px 0px 10px 25px; position: relative; width: inherit;'><div class='clr-col-5'><div style='width: 230px; height: 60px; background-image: url(*LINK_TO_IMAGE*); background-repeat: no-repeat; float: left;'></div></div></div></div>"
}

[ngStyle] = 'style.template'を使用してスタイルオブジェクトをテンプレートに追加しました。何らかの理由でスタイルが読み込まれなかったため、代わりにcamelCasingを使用しようとしましたが、まだ成功しません。

では、誰かがこの場合にCSSを機能させ、最終的にユーザー定義のスタイルを使用する方法を知っていますか?

前もって感謝します。

編集1:

app.module.tsにサニタイズパイプも含めました。

@NgModule({
    declarations: [
        ...,
        SanitizeHtmlPipe
    ],
    ...
});

(疑問に思っていた方)

編集2:

だから私はこれらのテンプレートでちょっとしたいものを考えています:

ユーザーはOffice 365から予約を表示したい場所の複数のデバイスを登録できます。ユーザーは2つの方法でテンプレートを設定できますが、これは重要ではありません。ユーザーが特定のデバイスのテンプレートを表示したい場合、/ device /:deviceid / template /:templateidに移動します。 これにより、コンポーネントがそのデバイスのテンプレートに読み込まれます。 したがって、最初に、テンプレートのユーザースタイルを含むデバイス設定を読み込みます。その後、テンプレートに表示する必要があるoffice365からデータを読み込み、最後にテンプレートスタイルを使用してテンプレートを読み込みます。 したがって、サーバーへの要求は3つになります。 DeviceSettings-データOffice365-テンプレート

これまでのところ、データを読み込んでテンプレートに配置することができましたが、テンプレートはサーバーからではなくローカルで使用できました。 テンプレートをサーバーからリクエストしてもらいたいのは、これらのテンプレートが作成および管理される管理ポータルがあるためです。 これらのテンプレートには、名前、HTML、CSSがあります。

Answers

[ngStyle]されたHTMLで[ngStyle]を使用する代わりに、 [ngStyle]されたHTMLが挿入されるdom要素のクラスを変更するだけです。

<div [ngClass]="templateClass" [innerHTML]="templateHtml"></div>

このようにして、コードはより読みやすくなり、スタイルコードはHTMLから分離されます。

テンプレートのCssは次のようになります。

.template-class-1 {
    background-color: #f44336;
}
.template-class-2 {
    background-color: #4caf50;
}

テンプレートの大きな違いについては、Angular CDKポータルを使用できます: https : //material.angular.io/cdk/portal/overview

ここに例: https : //stackblitz.com/angular/mkvvyvgqxox?file=src%2Fapp%2Fcdk-portal-overview-example.ts

この問題の解決策を見つけました。 discordサーバー "The Coding Den"の誰かのおかげで、彼はこれについて私にメッセージを送り、Github上のコンポーネントのテンプレート動的にロードするためのリンクをくれました。この長い投稿をスクロールした後、Alarm9k答えを見つけました。これは、サーバーリクエストを介して特定のIDに基づいてさまざまなテンプレートを表示できるコンポーネントを作成するために使用した方法です。また、それを説明するコメントも追加しました。

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は、子として機能する匿名コンポーネントクラスの親として機能します。このように、コンテナ名が指定され、親のHTML IDと一致する@ViewChildのおかげで、子を親に追加できます。 <div #container></div> (この場合)。

また、アプリモジュールに次のものを追加する必要があります。

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コンパイルが機能せず、次のエラーが発生するためです。 Angular JITコンパイルが失敗しました: '@ angular / compiler'がロードされていません これは、手動で追加しようとした場合でも、本番環境に角度コンパイラが含まれていないためです。

Related