根据要求动态注入HTML和CSS [英] Dynamically inject HTML and CSS on request

查看:54
本文介绍了根据要求动态注入HTML和CSS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我一直在研究如何从服务器加载CSS和HTML.

So I have been looking around on how to load CSS and HTML from the server.

我想要实现的是请求显示某个模板,该模板将HTML和CSS发送到网站,然后将其与一些用户定义的样式(例如颜色)一起加载

What I want to achieve is to request a certain template to be displayed which sends the HTML and CSS to the website and loads it in together with some user-defined styles like colour

到目前为止,我能够使用以下方式注入HTML:

So far I was able to inject HTML using:

<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);
    }

}

我从不同的帖子和博客中看到过(谢谢).

Which I have seen from different posts and blogs (thank you for that).

我一直在构建的HTML就像是一种魅力:

The HTML I have been building works like a charm:

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是完整模板的一部分. 所以我想做的就是通过使用变量来使用样式.

This HTML is a part of the complete template. So what I would like to do is to use styles on this by using variables.

所以我尝试的是制作一个样式对象:

So what I have tried is to make a style object:

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代替,但仍然没有成功.

I have added the style object to the template by using [ngStyle]='style.template', for some reason the style didn't get loaded, so I tried to use camelCasing instead but still no success.

那么有人知道如何在这种情况下使用CSS并最终使用用户定义的样式吗?

So does someone know how to get the CSS to work in this case, and eventually use user-defined styles?

谢谢.

我还在app.module.ts中包括了Sanitize管道:

I have also included the Sanitize pipe in the app.module.ts:

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

(对于那些想知道的人)

(for those who were wondering)

因此,我一直在尝试使用这些模板来实现以下目的:

So I have been working out what I kinda want to have with these templates:

用户可以在要显示来自Office 365的预订的位置上注册多个设备.用户可以以两种方式设置模板,但这无关紧要.当用户想要显示某个设备的模板时,他们转到/device/:deviceid/template/:templateid. 这样,组件将加载到该设备的模板中. 因此,首先我们加载设备设置,其中包含模板的用户样式.然后,我们从office365加载必须在模板中显示的数据,最后以模板样式加载到模板中. 因此,将有3个请求到服务器. 设备设置-数据Office365-模板

A user can register multiple devices of where they want to display the bookings from office 365. A user can setup templates in 2 ways, but this does not matter. When a user wants to display the template for a certain device they go to /device/:deviceid/template/:templateid. This way the component will load in the template of that device. So first we load in the device settings which contains the user styles for the template. Afterwards, we load in the data from office365 that has to be displayed in the template and finally load in the template with the template styles. So there will be 3 requests to the server. DeviceSettings -- Data Office365 -- Template

到目前为止,我已经能够加载数据并将其放置在模板中,但是该模板在本地可用,而不是在服务器上可用. 我想要从服务器请求模板的原因是,将有一个管理门户,将在这些门户中进行模板的创建和管理. 这些模板将具有名称,HTML和CSS.

So far I have been able to load in the data and place this in the template, but the template was available locally and not from the server. The reason why I want to have the templates to be requested from the server is that there will be an admin portal where those templates will be made and managed. These templates will have a name, the HTML and the CSS.

推荐答案

我已经找到了解决该问题的方法.感谢不和谐服务器"The Coding Den"中的某人,他给我发了消息,并给了我一个对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.

这篇关于根据要求动态注入HTML和CSS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆