I have a special project and I haven't been able to find any information on how I can achieve this.
So on this website companies can register and login. When a company is logged in they have an overview of devices and groups where devices can be divided in different groups for easy recognition. Now the hard part of the website is template management. Each device will display a template which could be a general specified template, a template that was assigned to a specific group or to an individual device. The templates that are chosen are either standard provided templates, custom templates made by the company or custom templates tailored by me. (The last 2 options are only visible for the company itself)
The main reason for this is to display different templates with that I mean structural differences like a table, cards and even custom structures.
So at the moment I am able to display templates based on the id of the company. These templates are integrated within the angular app. So now it kinda looks like this (its just a small example):
this.companyName = this.route.snapshot.params['company'];
if(this.companyName == "Google"){
this.template = `<div [ngStyle]="{'border-left':(tr.state=='busy')?'10px solid #D4061C':'10px solid #2CC52E'}">{{data}}</div>`;
this.styles = "div{color: red}";
}
What happens afterwards is the creation of a component on the fly by keeping the compiler in the build. So this means that this project cannot be build in production mode as the compiler is required. Which means that deploying the project is awful because the code is visible in the browser and the size is much larger so it takes too much time to load everything in. I kinda want to step away from this method and use something else which is easier to use
So what I want to know is:
- is it possible to load in html from either data in the database or from HTML files.
- is this possible by using any other library with Angular.
- is there a way to create an overview of templates that I offer to companies that displays a preview of that template as well?
- Is there a way to retrieve the ip and mac address of the device that is displaying the template.
If it isn't possible to use Angular for this what environment like language, frameworks, etc. do you advise to use instead?
If more information is required don't hesitate to ask away!
Thanks in Advance!
Edit 1:
I have tried to use [innerHTML] to load in the template but this doesn't work properly with data binding or data interpolation strings.
I'll give you an example of HTML I would like to load in:
<div class='exellys' style='width: 1080px ;height: 1920px;background-color: #212121;'>
<div class='clr-row' style='padding:45px 0px 10px 25px; position: relative; width: inherit; height: 115px;'>
<div class='clr-col-5' style='float: left;'>
<div style='width: 230px; height: 60px; background: url(/assets/exellys/exellys.png); background: url(https://www.exellys.com/App_SkinMaster/images/sprite-new.svg), linear-gradient(transparent, transparent); background-repeat: no-repeat; float: left;'></div>
</div>
<div class='clr-col-7' style='padding-top: 10px; float: right;'>
<div class='exellys medium' style='text-align: right;'>{{date | date: 'EEEE d MMMM y'}}</div>
</div>
</div>
<div class='clr-row' style='position: relative; width: inherit;'>
<div class='exellys medium' style='width: inherit;padding-right:10px; text-align: right;'>{{date | date: 'HH:mm'}}</div>
</div>
<div class='clr-row' style='position: relative; width: inherit;'>
<div class='exellys large' style='padding-top: 150px; width: inherit; text-align: center; font-weight: bold;'>WELCOME TO EXELLYS</div>
</div>
<div class='clr-row' style='position: relative; width: inherit;'>
<div class='exellys medium-large' style='padding-top: 75px; width: inherit; text-align: center;'>Training Schedule</div>
</div>
<div class='clr-row' style='position: relative; width: inherit;'>
<table class='table table-noborder exellys' style='table-layout: fixed; padding: 100px 20px 0px 35px;'>
<thead>
<tr>
<th class='left exellys hcell' style='font-weight: bold; font-size: 37px; width: 15%; padding-left: 0px;'>HOUR</th>
<th class='left exellys hcell' style='font-weight: bold; font-size: 37px; width: 40%;'>ROOM</th>
<th class='left exellys hcell' style='font-weight: bold; font-size: 37px;'>SUBJECT</th>
</tr>
</thead>
</table>
<table class='table table-noborder exellys' style='table-layout: fixed; border-collapse: separate; border-spacing: 0 5px; padding: 0px 20px 0px 35px; margin-top:0px;'>
<tbody style='padding-left: 0px;'>
<tr *ngFor='let tr of bookings'>
<td class='left exellys dcell' style='font-size: 37px; padding-left: 10px; width: 15%;' [ngStyle]="{'border-left': (tr.state=='busy')? '10px solid #D4061C' : '10px solid #2CC52E'}">{{tr.localeStart | date: 'HH:mm'}}</td>
<td class='left exellys dcell' style='font-size: 37px; width: 40%;' [innerHTML]="tr.scheduleLocation"></td>
<td class='left exellys dcell' style='font-size: 37px;'>{{tr.subject}}</td>
</tr>
</tbody>
</table>
</div>
</div>
Next to this HTML I am also loading following styles:
.main {
color: #b0943c;
font-family: 'Omnes-Medium', Helvetica, sans-serif;
width: 1080px;
height: 1920px;
background-color: #212121;
}
.exellys {
color: #b0943c;
}
.exellys.medium {
font-size: 43px;
font-family: 'Omnes-Regular', Helvetica, sans-serif;
}
.exellys.medium-large {
font-size: 55px;
}
.exellys.large {
font-family: 'Refrigerator-Deluxe-Regular', Helvetica, sans-serif;
font-size: 75px;
}
.exellys.dcell {
line-height: 45px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 0px;
}
.exellys.hcell {
padding: 0px 0px 20px 0px;
}
table.table.table-noborder th {
border-bottom: 5px solid #996633;
}
table td {
border-top: 2px dashed #996633;
}
Entering this kind of template can easily generate issues especially in innerHTML because of XSS protection. So I would like to know whether there is a different solution to this since there might be hundreds of customers with hundreds of different templates.
An example how a template could look like:
EDIT 2:
What I mean with:
is this possible by using any other library with Angular.
is if it is not possible to achieve this using standard methods are there any libraries to could enable me to achieve this anyways.
EDIT 3:
So the idea of a template suggestion system is really nice, but the customer wants to create it and add it directly without other customers to see this.
This way I need to be able to save HTML files in the backend (whether it are templates or full pages doesn't matter) and load it inside of the angular application.
For as far as I am understanding all the answers below this will not be possible in Angular.
My question now is in which environment or language can I achieve this template mechanism? Or is there still a unknown method that is safe to use for production in Angular?
Thanks in advance!
Update 15/12/2020:
After implementing Owen Kelvins idea, I have found a few issues with this. Using ngFor loops to loop over data doesn't work. Also adding pipelines inside of the interpolation strings do not work.
To solve the pipeline issue you can solve this by making changes to the prev.toString() line:
templateString$ = combineLatest([this.templatingInfo$, this.template$]).pipe(
map(([info, template]) =>
Object.entries(info).reduce((prev, next) => {
var value = next[1].toString();
var pipe = "";
var pipevalue = "";
var match = prev.toString().match(new RegExp(`{{\\s${next[0]}\\s(\\|\\s\\w*\\:\\s\\'\.*\\'\\s)+}}`));
if (match != null) {
pipe = match[1].substring(2);
if (pipe.split(":")[0] == "date") {
pipevalue = pipe.substr(5).replace(/['"]/g, "");
value = formatDate(value, pipevalue, this.locale);
return prev.toString().replace(new RegExp(`{{\\s${next[0]}\\s(\\|\\s\\w*\\:\\s\\'\.*\\'\\s)+}}`), formatDate(next[1].toString(), pipe.substring(5).replace(/['"]+/g, ""), this.locale));
}
}
return prev.toString().replace(new RegExp(`{{\\s${next[0]}\\s}}`), next[1].toString());
}, template)
),
map(template => this._sanitizer.bypassSecurityTrustHtml(template))
);
Ofcourse this method doesn't work completely as in some cases it still doesn't display it correctly. Like when you have: <div>{{date | date: 'EEEE d MMMM y' }} - {{date | date: 'HH:mm' }}</div>
, as in this case only the first one would be correct.
I would like to know how I could fix both the ngFor loop as the pipeline issue.
Thanks in Advance!