Archive for the 'Web' Category

June 7th, 2022
8:32 am
Upgrading Angular & PrimeNG Microapps from V11 to V13

Posted under Angular & Knowledge Base & PrimeNG
Tags ,

Firstly I installed the latest current release of node under NVM. This was 18.2.0, so this was installed simply using “nvm install 18.2.0”. This is only needed once as it is global for any project/folder running under NVM.

I then followed the upgrade procedure for angular here. Upgrading is well documented and supported – you can pick any pair of versions along with some details of your app complexity/what you use, and get specific update help here.

I then updated the various dependent components. I needed to add the switches “–force –allow-dirty”. “–force” was to force the updates through even when there were dependency version issues – this would all come out in the wash when finished, it was just a question of the dependency update order which triggered this. “–allow-dirty” allowed the update to proceed even when there were pending git commits present. I am unsure why the process is so picky about this – I did not intend to commit after every individual update command, and did not see why there should be a warning about it. The following updates were done:

npm install primeng@13.4.1 –force –allow-dirty
npm install primeicons@5.0.0 –force –allow-dirty
npm install primeng@13.4.1 –force –allow-dirty
npm install primeflex@3.2.0 –force –allow-dirty
npm install jasmine-core@4.1.1 –force –allow-dirty
npm install @angular/cdk@13.3.7 –force –allow-dirty

for my chart microapp which uses the PrimeNG chart component and therefore chart.js, I had to upgrade chart.js to the latest 3.8.0 or builds won’t work:

npm install chart.js@3.8.0 –force –allow-dirty

I also with noted with charts that the styling changed – charts were too big for browser window and needed unwanted scrolling, so would need to look into styling issues on this. Also the growl when you click on chart points etc. has gone.
This is replaced with a hover “growl” next to where you hover over a point. I confirmed the behaviour change with the primeng showcase.

I also noted that @angular/cdk  slipped the net orignally and needed doing (even adding again) manually as listed above.

After all the updates as above I was able to build and run in the usual way.

Comments Off on Upgrading Angular & PrimeNG Microapps from V11 to V13

May 17th, 2022
4:26 pm
PHP Compilation issues with existing Salient wordpress theme

Posted under Knowledge Base & PHP & Wordpress

I hit an issue with the Salient Soft website whereby the PHP error log file used up all my available zen hosting disk space, and my email started to fail. It turned out that there were a number of php define statements in the code, where the actual define name was not quoted. in PHP 7.3, which I was using, this added a warning to the log, stating that this would not be supported in future versions and would fail.

I was surprised that the log had grown suddenly – whilst it did have entries going back a number of years, I suspected that the real culprit was likely a fairly recent server side change e.g. in the php version.

The original incorrect code and the corrected version are shown here for reference:

define (SSW_PHPTHUMB_DIR, “wp-content/phpThumb”);

define (‘SSW_PHPTHUMB_DIR’, “wp-content/phpThumb”);

I must say that it felt strange to have to quote the definition name in addition to the replacement string, but this was correct. In common with others who posted about this online, I elected to use a policy single quotes for the static definition names, and double quotes for other replacement and dynamic strings in the code. I fixed all of these, plus an additional string which should have been quoted in another expression, and everything was fine – all the errors disappeared.

I uploaded a zip of the fixed theme (with a new point version) and unzipped it manually. Whilst initially it appeared that WordPress did not recognise the uploaded theme, this was incorrect – it was actually in the list of themes when uploaded manually and unzipped into the themes directory along with all the others. I did briefly try the wordpress feature whereby you can upload a zip of a new theme and install it using wordpress, but wordpress complained about the writeability of its temporary chosen upload directory so I didn’t pursue this further and just did it all manually, which was fine.

I also hit a number of issues with eclipse for PHP 2022-03, as I had done previously here. My workspace got corrupted somehow causing eclipse errors that would not disappear even with a restart. It also refused to rename a subfolder (which I had renamed with the new theme version) for a while and I could not resolve this and so I had to delete and recreate it and then re-import the theme code from bitbucket. After this, and importing it as a general PHP project as before, it all resolved ok, and as before, I had no trouble importing from git directly into a subfolder of the workspace.

I have been having mouse/mouse driver issues whereby windows keeps interpreting a click as a double click or two successive single clicks which causes numerous issues all over the place, so this may have been partly to blame for php messing up and spitting at me in various ways. However, I do not believe this was the only problem, and am still of the opinion that this version of php has issues – I will keep an eye out for a new version to try, or may even wind back to an older one. I must say that the PHP integration with git/bitbucket did generally work well. Importing from bitbucket with the remote URI was easy, as was all the usual features like creating a new local branch from a newly created remote feature branch in bitbucket, and commiting all the code back, and pulling changes from develop for the final merge (which was done in bitbucket) etc.

After all this everything was fine with the website and theme.

Comments Off on PHP Compilation issues with existing Salient wordpress theme

May 16th, 2022
4:47 pm
Issues when upgrading Yoti PHP Identity API to use v3 of the Yoti PHP api

Posted under Knowledge Base & PHP
Tags ,

I was in the process of upgrading all aspects of the Microapps functionality to the latest versions, and in particular, was upgrading the Yoti SDK versions used as part of the Age Verification Microapp Identity API. I’ve already posted about the Java/Spring Boot issues I hit when upgrading the Java/Spring Boot Identity API. I also hit a couple of issues when upgrading the PHP version of the Identity API, which are detailed here as follows.

1/ To manage the PHP versions of the Yoti SDK, I was using PHP composer as detailed hereRather than complicate matters for such a simple demo API, as per the linked post, I elected to use a simple PHP project which was not integrated to Composer within PHP. Composer functions such as install or upate were performed separately on the command line.

When doing this upgrade, I was using a new PC and so had to check out the code from scratch from Bitbucket. As a policy I do not check in IDE related files (in this case, the PHP version of eclipse), as I wish to keep checked in source IDE agnostic. I therefore cloned the repository on the command line, in a folder under the eclipse workspace, and then tried to create this as an eclipse project from existing files. Whenever I attempted this initially, I got the error ‘Cannot create project content in workspace’. After investigation I found this stack overflow post here on the subject, which says in the comments that this is in fact a long standing eclipse issue. I was able to create a project from existing files in a folder outside the workspace, but eclipse refused to do this inside the workspace, which is strange. It was possible to create the project outside the workspace, then copy the folder into the workspace, and then import it as an existing project, i.e. with all the eclipse project files already present. This all seemed unnecessarily hard though and certainly appeared to be a bug as per the post.

2/ When creating/importing the new project into eclipse, on several occasions I hit an issue where the resulting code had compilation errors in eclipse relating to the composer include files. After investigating, it appeared that due to the way I was importing/creating, eclipse was trying to interpret the type of project (possibly as a composer one) and set some complex invalid entries for the build path and include path which tripped everything up. In the end, I noted that importing just as a simple PHP project was fine and all the errors disappeared. Whilst this may not integrate eclipse fully with the underlying Composer structure, as before, I was not interested in doing this. The project was just a simple interface calling Yoti’s php api, with no other composer dependencies of mine. I therefore stuck with a simple project import and ensured that, however I went about the import/create, I told eclipse effectively ‘stop trying to be clever, just treat it all as a simple php project’. This worked fine.

I did note that unlike intellij (and indeed eclipse for java), control/clicking on a method did not appear to go to the method, or offer the choice of visiting either the declaration or the implementation. After checking online, this appears to be the norm – I could not see any posts indicating that ctrl/click or some variant of this would work in this way. There were however keyboard shortcuts to do this kind of thing, but I did not investigate further.

3/ In the end, my solution to both these issues was to use the import menu in eclipse and import directly from bitbucket into eclipse, creating a new project in the process. The double advantage of this was that the integration with the remote bitbucket was immediate as a result of the import, and creating the project in the workspace during the import did not give the error above under 1/. 

To do this, I used the clone URI that bitbucket provided for cloning, but without the git command prefix. Whilst the initial import form has a ‘local directory’ next to the remote git uri field, this was not the target local folder – it would try to do a local import instead from this folder, and suppress the git uri. I therefore left this folder blank and proceeded with the next button. A subsequent screen had a local folder location field for where to place the imported/cloned project, and when placing this under the workspace, crucially, eclipse did not complain, and everything proceeded fine. An important point during this process was that I took great pains to ensure that any fields relating to the type of import were set to basic/simple eclipse project only, i.e. I told eclipse not to try to second guess the project type, and risk getting the errors I received above in 2/ again.

After doing this, the project looked fine in eclipse, with no compilation errors. I then updated the composer.json file as required, and manually ran ‘composer update –no-dev’ to update the vendor files, then did a refresh/revalidate in eclipse. This all worked fine.

4/ Another issue I hit was when accidentally missing out the pem file when deploying under zen hosting with the new version. When this happened, Yoti correctly returned an exception re the missing pem file, but the error code was set to 0, rather than to a specific http status as is done for the success case which gives a code of 200. Unfortunately, whilst this code of 0 was returned in the response body, the actual http status was set to 200 ok, as for success. This resulted in the age verification application assuming a successfully returned age of -1. In the java/Spring Boot version of the same api, I had elected to return all error conditions as a 404 for simplicity. This would be sensible i.e. if a broken or invalid token was sent to Yoti – Yoti would return an error stating that it could not decrypt the token, which should map to a 404. I did not want to get into mapping individual statuses to http responses as the mapping would not be easy/good anyway, and it did not feel right to map all errors to a 500 say, as in many typical cases this would not be appropriate, as in the incorrect or duplicate token usage as above.

I therefore did exactly the same for the PHP version as for the java one, for consistency. All 200 error codes were sent as an http response of 200 as expected, but anything else in the code field, which would not be a success, was sent as a 404. This solved the problem and all worked fine.

Comments Off on Issues when upgrading Yoti PHP Identity API to use v3 of the Yoti PHP api

February 18th, 2022
10:05 am
angular 11 node-sass deprecated warnings

Posted under Angular & Web
Tags

I received these warnings when building an angular 11 upgrade of microapps from angular 6. This post details the issue and remediation.

I checked and had already removed all the node-sass entries from package.json files and re-ran npm install and rebuilt, so have taken no further action at the moment. There may still be a few warnings lurking due to package-lock.json issues as discussed in the above post, in which case I will take a further look  in due course as required and update this post.

Comments Off on angular 11 node-sass deprecated warnings

February 2nd, 2022
6:30 pm
Issues when reinstalling NVM/NPM/Angular environment under new PC build

Posted under Angular & Web & Windows 10
Tags , ,

Update/Fix 24/2/2022

It appears that in the end much of this issue was down to a basic error on my part! I have previously documented here and here about the collision of object namespaces when loading multiple webpack bundles for separately deployed web components/angular elements. My solution is to perform a custom post build step to rename the root webpack objects to be unique for each webpack deployment.

This requires building to be done using npm via npm run build rather than the basic angular/cli ng build. Unfortunately I did the latter when initially rebuilding the microapps, hence the post build step did not run and I suffered the consequences I have seen previously due to namespace collisions. Once I rebuild everything correctly, all the microapps worked fine.

Original Post

I had reinstalled a PC from scratch with Windows 10, and this required rebuilding my whole dev environment from scratch. I hit some issues when I just simplistically tried the latest node via nvm install, and the latest angular (14) on projects previously run under angular 11 – builds failed and would not complete. Initially I had failed to install node-sass, so installing this helped, but I was still getting webpack errors on building.

I reverted to angular 11, but also reverted node as well. Finding a compatibility matrix for the versions was tricky but this one on stack overflow was a real help. I therefore reverted node to 12.11.1 using nvm install 12.11.1., and reverted node-sass to 5.0 due to some build errors that stated that 4.0 or 5.0 was needed.

Having done this, I was able to do a build using ng build, but this would not run using http-server, which gave the error “Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client”. My next action was to suspend/pause Kaspersky Antivirus, which helped, as it revealed a firewall port that I needed to enable. When I then immediately tried running directly using ng serve, this worked fine and I was finally able to successfully run my microapp fabric.

I then uploaded the built microapp as a test version under my zen hosting and tried running it from there. This ran fine with no errors, pointing to a local issue with my http-server. This likely needed an older version. I reverted to 0.12.2 to correspond with the current version when I last worked on the microapps, using the http-server version list here,  but this did not work.

I then checked exactly which versions of key components had been used successfully under Windows 7, and reverted to exactly those versions. These were v15.5.0 of node.js, and v0.12.3 of http-server. This worked successfully, and I was able to run compiled versions of both the fabric and the dataview microapp. Whilst I could have checked the versions used previously more carefully, this certainly highlights the potential brittleness of the environment as a whole to version changes.

I then upgraded http-server to the latest version and tried again, and everything still worked fine. Therefore, this definitely appears to point to an issue with the version of node.js alone. It also highlights issues with the version matrix I hunted down previously as above. I ended up using a later version of node which was technically incompatible in terms of the above version matrix, but which worked successfully, whereas a version mandated by the version matrix failed completely with the above error.

This whole area of versioning can certainly prove to be an unexpected and ill-documented minefield!

 

Comments Off on Issues when reinstalling NVM/NPM/Angular environment under new PC build

February 25th, 2021
12:23 pm
Angular 11 – remote loading of Angular Element from separately deployed webpack bundle

Posted under Angular & Uncategorized & Web & Webpack

This follows on from my original post here for Angular 6.

In Angular 11, the up-and-coming approach to this is to use Module Federation for remote loading of microapps/micro-frontends. Manfred Steyer has a new article series on this whole approach here, and the second article about using Angular for this may be found here.

My issue with module federation at present is that it is still appears too nascent to simply ‘just work as standard’ with angular – the above posts need a number of workarounds including the use of yarn, and I was unwilling to switch to this method just for my present requirement which is just the generation of simple proof of concept work.

At present, I am therefore continuing to use my original approach as above for my POC work, as it still works with Angular 11. I have tweaked the approach a little to allow performing production builds, by disabling the hashes added to the filenames (I already use my own alternative method for cache busting/cache avoidance using a query string parameter). Details are shown below.

package.json scripts section

{
"name": "microapp-fabric-prototype",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"prebuild": "npm run scss",
"build": "ng build",
"postbuild": "node post-build.js",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"scss": "npm run scss1",
"scss1": "cd src/assets/resources/themes/salient-v11-violet && sass theme.scss:theme.css --source-map .",
"prebuildProd": "npm run scss",
"buildProd": "ng build --prod --output-hashing none",
"postbuildProd": "node post-build-prod.js"
},

post-build.js

/* Do post build actions on the webpack bundle.
* Rename the webpack jsonp objects throughout, to prevent invalid multiple bootstraps due to name collisions
* This is due to an angular bug - see here: https://github.com/angular/angular/issues/23732
* This script requires the npm replace package: https://www.npmjs.com/package/replace
* To install use: "npm install replace -g" */

var replace = require("replace");

doWebpackReplace('MicroappFabric','microapp-fabric-prototype',
['main.js', 'polyfills.js', 'runtime.js', 'vendor.js']);

function doWebpackReplace(name, filename, paths) {
replace({
regex: '\\["webpackJsonp"\\]',
replacement: `["webpackJsonp${name}"]`,
paths: paths.map((p) => `dist\\${filename}\\${p}`),
recursive: false,
silent: false,
});
}

post-build-prod.js

/* Do post production build actions on the webpack bundle.
* Rename the webpack jsonp objects throughout, to prevent invalid multiple bootstraps due to name collisions
* This is due to an angular bug - see here: https://github.com/angular/angular/issues/23732
* This script requires the npm replace package: https://www.npmjs.com/package/replace
* To install use: "npm install replace -g" */

var replace = require("replace");

doWebpackReplace('MicroappFabric','microapp-fabric-prototype',
['main.js', 'polyfills.js', 'runtime.js']);

function doWebpackReplace(name, filename, paths) {
replace({
regex: 'window\\.webpackJsonp',
replacement: `window.webpackJsonp${name}`,
paths: paths.map((p) => `dist\\${filename}\\${p}`),
recursive: false,
silent: false,
});
}

At present, I will continue to monitor the situation with Module Federation, and will likely switch to using it when it really is working ‘out of the box’ with no tweaks or complications.

 

Comments Off on Angular 11 – remote loading of Angular Element from separately deployed webpack bundle

February 19th, 2021
6:05 pm
PrimeNG 11/Angular 11 build fails due to missing @angular/cdk dependency

Posted under Angular & PrimeNG & Uncategorized & Web
Tags , ,

… as above – I received the following error in relation to a PrimeNG p-dropdown used with a p-dataview:

Error: The target entry-point “primeng/dataview” has missing dependencies:
– @angular/cdk/scrolling

This issue is covered here.
I haven’t seen this before, but installing @angular/cdk resolved the build failure. This appears to be a transitive dependency issue which should have been resolved by my dependencies on PrimeNG.

 

Comments Off on PrimeNG 11/Angular 11 build fails due to missing @angular/cdk dependency

February 12th, 2021
5:33 pm
Dynamic Typing issues with Typescript/Angular 11

Posted under Angular & TypeScript & Web
Tags ,

I was using a JSON file to hold external configuration for an agular application, using the pattern detailed previously here, and the loading mechanism detailed here.

The configuration pattern used allowed parameters to be overridden dynamically from query string parameters, so that for example you could choose an application theme in your URL.

I wanted to further extend this to allow sticky configuration parameters using localStorage, in particular to support a sticky pinnable title banner as detailed previously here. The aim was that both the query string support and the sticky localStorage support would be encapsulated in the configuration pattern and all transparently handled by the existing configuration service. The service would be enhanced with a new method call to allow persisting of a sticky parameter to localStorage and to the loaded config, for example for my sticky pinnable banner, to allow calling to persist the new pin state when the pin state was changed via the pin button. The previous pin state would then be loaded when the site was subsequently visited. Sticky parameters would override settings in the JSON file, and query string parameters would further override both of the former, and a query string parameter would also be sticky and would persist to localStorage, so for example the previous theme selected in the URL would be remembered.

One challenge was that whilst the configuration structure conformed to a Typescript interface, I needed to dynamically update configuration parameters from query string parameters or localStorage. This meant using dynamic keys e.g. based on the querystring parameters. Whilst this was initially possible by casting the config structure and using a map style lookup with config[keyVariable], it was not possible to dynamically infer the type of a configuration parameter from the interface, noting that both query string and localStorage parameters are strings. Often this is not a problem, as the default javascript behaviour will quite often cope, but therein lies a danger. In one case with a boolean, my query string/localStorage parameter was of course a string, and when written to the configuration using a dynamic key name as above, it was written as a string rather than the boolean expected in the interface. This meant that the value ‘false’ was in fact interpreted as true, due to the standard javascript truthy behaviour whereby a non empty string counts as true.

In the end, my solution was to have a subsection in the configuration, called dynamicParams, which contained all these dynamic parameters. It was therefore a requirement that all the dynamic parameters were strings and that client code reading the configuration had to be aware of that and convert as required.

One useful feature was to use Typescript intersection types for the dynamic parameters section, as detailed here. This allowed me to specify the dynamic parameter names explicitly, to allow them to be read in code directly as for example using config.dynamicParams.theme. I could also use programmatic access as above using config[keyVariable].

The section of the interface definition to do this was as follows:-

export interface AppConfig {
   appTitle: string;
   description: string;

   /* These parameters can be overridden from URL query parameters
    * and/or sticky local storage parameters
    * They must all be strings as are accessed by key programmatically */
   dynamicParams: {[key: string]: string | undefined} &
      {
         theme: string;
         pinBanner?: string;
         profileId?: string;
      };
   propertyDetail: {
      defaults: {
      photoLinkHoverText: string;
   }
   …

A particular point of note was that the intersection type using “&” was needed for this to work, rather than the union type “|”.

This solved the problem satisfactorily and all worked fine.

Comments Off on Dynamic Typing issues with Typescript/Angular 11

February 10th, 2021
6:54 pm
Pinning a title bar on a page with Angular 11/PrimeNG 11

Posted under Angular & PrimeNG & Uncategorized & Web
Tags ,

My initial attempt on this was to use static positioning when the title bar was unpinned (e.g. scrollable), and fixed positioning when the bar was pinned.

When using fixed positioning as above, the title bar is no longer in the normal flow so the rest of the content (in my case, encapsulated in a main container div) will sit underneath the title bar. I therefore used a top margin when pinned to prevent the top of the content being hidden. Some issues arose with this as follows:

1/ It was necessary therefore to add an additional margin to the main container to avoid occluding the content under the title bar, which meant exactly knowing its height. In addition, to allow a gap between the title bar and the content when pinned, I added a border to the title bar of the same colour as the page background, in effect to act as a kind of margin. This worked fine.

1/ My title bar was floated, so it automatically resized to fit its content. this meant that the margin allowance on the main content div would have to vary dynamically on resize.

2/ One way around this was to set media query breakpoints to trigger on the resize, and to set a fixed height for the title bar rather than floating it, and setting the margin on the content to match in each media query. In addition to this, I implemented a flexbox solution where the container was sized and the content centered within it. I was not so keen on this as it lost the ability to dynamically resize the title bar container as needed by the content resizing, and might cause problems if the layout/text changed in the title bar for example.

3/ Another way was to use a resize event and change the size of the margin on the content programmatically, using an rxjs debounced resize event. This worked pretty well, but I needed to switch the content margin on and off when the title bar was pinned/unpinned. This should have worked ok, but I noticed some slight visual movements in some page elements on pinning change, even though I could not see any style or layout changes in the browser inspector. This was annoying.

4/ I then tried using absolute positioning of the title bar when unpinned, and fixed positioning when pinned. This relied on using the same programmatic margin on the content for both, and in fact simplified the code, as I did not have to switch off the programmatic margin change when unpinning the title bar – it was used all the time, as absolute positioning was also outside the normal flow. Also, the slight glitches I saw on the page were completely eliminated.

I therefore stuck with method 4/ as the final solution. Some sample code showing the programmatic resize is as follows:-

private readonly resizeDebounceTime = 100;
private resizeObservable!: Observable<Event>;
private resizeSubscription!: Subscription;
private readonly formatPixelSize = (pixels: number) => `${pixels}px`;

ngAfterViewInit(): void {
   this.initBannerSpacingAdjustment();
}

ngOnDestroy(): void {
   this.destroyBannerSpacingAdjustment();
}

private initBannerSpacingAdjustment(): void {
   this.adjustBannerSpacing();
   this.resizeObservable = fromEvent(window, 
      ‘resize’).pipe(debounceTime(this.resizeDebounceTime));
   this.resizeSubscription = this.resizeObservable.subscribe(event => 
      this.adjustBannerSpacing());
}

private destroyBannerSpacingAdjustment(): void {
   if (this.resizeSubscription) {
      this.resizeSubscription.unsubscribe();
}
}

private adjustBannerSpacing(): void {
   /* note that the offsetHeight is the total height of the banner,
    * including padding and border */
   this.mainContainer.nativeElement.style.marginTop =
      this.formatPixelSize(this.banner.nativeElement.offsetHeight);
}

 

Comments Off on Pinning a title bar on a page with Angular 11/PrimeNG 11

February 8th, 2021
6:04 pm
Using Font Awesome with Angular 11/PrimeNG 11

Posted under Angular & PrimeNG & Uncategorized & Web
Tags ,

Update 4/3/21

I had problems again when trying to display font-awesome icons in a microapp/web component. In this case, my parent fabric application which loaded the web component had font awesome loaded in package.json but not in angular.json. I removed font-awesome from the web component application in both package.json and angular.json as the parent had loaded it in both places. This then worked correctly. There may be a similar issue with e.g. the prime icons etc. but have not researched this. Clearly PrimeNG itself is needed in both applications as the child web component has development dependencies on it. My theme styling however is only loaded in the parent fabric, and it makes sense that font-awesome behaves the same way.

Original Post

My previous post about using font awesome with Angular  up to v6 and PrimeNG up to v6 is here

With PrimeNG 11, Prime have introduced their own icon set, PrimeIcons.

I wanted to use some font awesome icons as well as they have a larger set, but initially they would not display. When trying again later it all worked fine, and am unsure what I got wrong the first time around. To be clear, the following steps were needed:

1/ Install font awesome and add to package.json (–save adds to package.json)

npm install font-awesome –save

2/ Add a style reference to angular.json

“styles”: [
“node_modules/primeng/resources/primeng.min.css”,
“node_modules/font-awesome/css/font-awesome.min.css”,
“node_modules/primeicons/primeicons.css”,
“src/messages.scss”,
“src/styles.scss”
],

Double check that the referenced css file actually exists under node-modules for the version in use. in my case, this was 4.7.0.

I was looking for pin/unpin icons for a banner bar, and could only find a vertical pin, fa-thumb-tack – I also wanted a horizontal pin to designate the unpinned state. Fortunately, font awesome has the ability to transform icons e.g. to rotate them. This is more limited in v4, but rotation is allowed, so my reference was as follows:

<p-toggleButton [(ngModel)]="bannerPinned" onIcon="fa fa-thumb-tack" offIcon="fa fa-thumb-tack fa-rotate-90"
class="ss-pin-banner"></p-toggleButton>

This worked perfectly. v5, which was not available directly to install via npm at the time, allows more transformations. The transforms are detailed in this stack overflow post and this font awesome page.

 

 

Comments Off on Using Font Awesome with Angular 11/PrimeNG 11