The goal of this code is to dynamically generate ng-containers that generate buttons with classes that either is active or inactive depending on a user's permissions list. Due to limitations currently, I can not retrieve the permissions list and need to create the buttons before the permissions list is pulled from the user token.
I am trying to create buttons on the OnInit() for the component, which has a series of ng-templates that are chosen between via ngIf directives according to the users permissions map which is stored locally.
I have looked around and understand that directives need to be compiled, but was wondering if there are any tricks or help I can be pointed to as my search has only pulled up common references to it not being possible or tricks that require already generating part of the html.
component.ts
import { KeyValuePipe } from '@angular/common';
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute, Route } from '@angular/router';
import { createPopper } from '@popperjs/core';
import * as libs from '../../../../assets/jsonFiles/libs.json';
@Component({
selector: 'app-libs-view',
encapsulation: ViewEncapsulation.None,
templateUrl: './libs-view.component.html',
styleUrls: ['./libs-view.component.css']
})
export class LibsViewComponent implements OnInit {
hasLibraryAccess = new Map<String, boolean>();
constructor(route: ActivatedRoute) { }
ngOnInit(): void {
this.formatLibraryButtons()
}
formatLibraryButtons() {
let btnLayoutHlpr = 0;
// hard coded for now to test the original 12 buttons
// should read json and get each library, and create a button correctly for it
for (let eachLib in Libs) {
let lib = Libs[eachLib].Name
console.log(lib)
// https://www.typescriptlang.org/docs/handbook/dom-manipulation.html
if (btnLayoutHlpr < 2) {
const btnGrp = document.getElementById("btnGrp1");
//this.createButton(btnGrp!, lib)
++btnLayoutHlpr;
} else if (btnLayoutHlpr < 4) {
const btnGrp = document.getElementById("btnGrp2");
//this.createButton(btnGrp!, lib)
++btnLayoutHlpr
} else if (btnLayoutHlpr < 6) {
const btnGrp = document.getElementById("btnGrp3");
//this.createButton(btnGrp!, lib)
++btnLayoutHlpr
} else if (btnLayoutHlpr < 9) {
const btnGrp = document.getElementById("btnGrp4");
//this.createButton(btnGrp!, lib)
++btnLayoutHlpr
} else if (btnLayoutHlpr < 12) {
const btnGrp = document.getElementById("btnGrp5");
//this.createButton(btnGrp!, lib)
++btnLayoutHlpr
} else {
//console.log("check")
++btnLayoutHlpr
}
// setting all to true for dev purposes
this.hasLibraryAccess.set(lib, true); all library names must start lowercase or angular's auto-sort method messes up btn placement
}
console.log("Button creation complete")
console.log("Library Access Map Created")
}
createButton(btnGrp : Element, lib: string) {
// create ng-content div to hold logic for if library is accessible
const ngCont = document.createElement("ng-container")
// create ngIf for checking if customer has access to library
const ngIf = document.createElement("div")
//ngIf add ngIf to the div such that ngIf=libraryAccess.value | then libAccessTrue else libAccessFalse
ngCont.appendChild(ngIf)
// create first template to add library access button
const ngTemp = document.createElement("ng-template")
//ngTemp.add add #LibraryAccessTrue
// create div wrapper for btn
const divWrapper = document.createElement("div")
divWrapper.style.marginLeft = "1 px";
// create accessible btn and add it to divWrapper and add divWrp to template
const libBtn = document.createElement("a");
libBtn.classList.add('hexagon', 'd-flex', 'align-self-center');
libBtn.textContent = lib;
divWrapper.appendChild(libBtn)
ngTemp.appendChild(divWrapper)
// add first template for accessible library button to ng-content
ngCont.appendChild(ngTemp);
// create second template to add library access button
const ngTemp2 = document.createElement("ng-template")
//ngTemp.add add #LibraryAccessTrue
// create second div wrapper for btn
const divWrapper2 = document.createElement("div")
divWrapper2.style.marginLeft = "1 px";
// create disabled btn and add it to its divWrapper then to template
const libBtn2 = document.createElement("a");
libBtn2.classList.add('hexagon-disabled', 'd-flex', 'align-self-center');
libBtn2.textContent = lib;
divWrapper2.appendChild(libBtn2)
ngTemp2.appendChild(divWrapper2)
// add second template for disabled library button to ng-content
ngCont.appendChild(ngTemp2);
// add the entire ng-content div to the button group
btnGrp?.appendChild(ngCont);
}
}
component.html
<div class="d-flex">
<div class="container parent-hexagon">
<div class="d-inline-block" style="margin-left: 8%; width: 80%">
<div id="btnGrp1" class="btn-toolbar">
<div *ngFor="let libraryAccess of hasLibraryAccess | keyvalue">
</div>
</div>
<div id="btnGrp2" class="btn-toolbar" style="margin-left: 12%">
<div *ngFor="let libraryAccess of hasLibraryAccess | keyvalue">
</div>
</div>
<div id="btnGrp3" class="btn-toolbar">
<div *ngFor="let libraryAccess of hasLibraryAccess | keyvalue">
</div>
</div>
<div id="btnGrp4" class="btn-toolbar" style="margin-left: 12%">
<div *ngFor="let libraryAccess of hasLibraryAccess | keyvalue">
</div>
</div>
<div id="btnGrp5" class="btn-toolbar" style="margin-left: 24.25%">
<div *ngFor="let libraryAccess of hasLibraryAccess | keyvalue">
</div>
</div>
</div>
</div>
</div>
component.css
.parent-hexagon {
max-width: 90%;
width: 40vw;
height: 42vh;
background: green;
position: absolute;
z-index: 0;
}
.parent-hexagon::before {
content: "";
position: absolute;
top: -20vh;
left: 0;
width: 0;
height: 0;
border-left: 20vw solid transparent;
border-right: 20vw solid transparent;
border-bottom: 20vh solid green;
}
.parent-hexagon::after {
content: "";
position: absolute;
bottom: -25vh;
left: 0;
width: 0;
height: 0;
border-left: 20vw solid transparent;
border-right: 20vw solid transparent;
border-top: 25vh solid green;
}
.hexagon {
width: 7.5vw;
min-width: 100%;
max-width: 100%;
height: 8.5vh;
color: black;
font-size: 90%;
justify-content: center;
text-align: center;
text-decoration: none;
background: #bfe8f7;
position: relative;
z-index: 1;
margin-bottom: 28.865px;
}
.hexagon::before {
content: "";
position: absolute;
top: -28.8675px;
left: 0;
width: 0;
height: 0;
border-left: 3.75vw solid transparent;
border-right: 3.75vw solid transparent;
border-bottom: 28.8675px solid #bfe8f7;
}
.hexagon::after {
content: "";
position: absolute;
bottom: -28.8675px;
left: 0;
width: 0;
height: 0;
border-left: 3.75vw solid transparent;
border-right: 3.75vw solid transparent;
border-top: 28.8675px solid #bfe8f7;
}
.hexagon:hover {
background: #7fd1ef;
z-index: 2;
transform: scale(1.15)
}
.hexagon:hover:before {
content: "";
position: absolute;
top: -28.8675px;
left: 0;
width: 0;
height: 0;
border-left: 3.75vw solid transparent;
border-right: 3.75vw solid transparent;
border-bottom: 29.8675px solid #7fd1ef;
}
.hexagon:hover:after {
content: "";
position: absolute;
bottom: -28.8675px;
left: 0;
width: 0;
height: 0;
border-left: 3.75vw solid transparent;
border-right: 3.75vw solid transparent;
border-top: 29.8675px solid #7fd1ef;
}
.hexagon-disabled {
width: 7.5vw;
height: 8.5vh;
color: black;
font-size: 90%;
justify-content: center;
text-align: center;
text-decoration: none;
background: #caced0;
position: relative;
z-index: 1;
margin-bottom: 28.865px;
}
.hexagon-disabled::before {
content: "";
position: absolute;
top: -28.8675px;
left: 0;
width: 0;
height: 0;
border-left: 3.75vw solid transparent;
border-right: 3.75vw solid transparent;
border-bottom: 28.8675px solid #caced0;
}
.hexagon-disabled::after {
content: "";
position: absolute;
bottom: -28.8675px;
left: 0;
width: 0;
height: 0;
border-left: 3.75vw solid transparent;
border-right: 3.75vw solid transparent;
border-top: 28.8675px solid #caced0;
}
.hexagon-disabled:hover {
background: #caced0;
z-index: 2;
transform: scale(1.15)
}
.hexagon-disabled:hover:before {
content: "";
position: absolute;
top: -28.8675px;
left: 0;
width: 0;
height: 0;
border-left: 3.75vw solid transparent;
border-right: 3.75vw solid transparent;
border-bottom: 29.8675px solid #caced0;
}
.hexagon-disabled:hover:after {
content: "";
position: absolute;
bottom: -28.8675px;
left: 0;
width: 0;
height: 0;
border-left: 3.75vw solid transparent;
border-right: 3.75vw solid transparent;
border-top: 29.8675px solid #caced0;
}
As shown above, the issue is the html is pretty sparse beyond setting up the button groups and the ngFor directives to iterate the libraryAccessPermissions map that tells the ng-containers being dynamically created which ng-template to show. If I could get the permissions, I would forgo the ngIf and just generate the buttons with css classes dependent on their permissions. But since they won't, for project reasons, be given till after the components Init(), I have to create templates and a permission map to track and properly show buttons.
Any help on how to generate these buttons would be welcome and grateful for.