Blog Archives

May 26th, 2017
12:55 pm
Dynamically updating css classes on child components from a parent property

Posted under Angular & CSS & PrimeNG
Tags , , ,

I was using a button component to encapsulate the primeNG one, to allow it to responsively change to an icon only button at smaller screen widths. Whilst in theory I could have dynamically modified the internal primeNG button CSS, this was complex and I did not want  to become tightly coupled to it. My button component therefore simply selected one of 2 buttons via a media query, setting the unwanted one to display:none.

I wanted any classes added to the top level ss-button to be set on the underlying primeNG buttons. One use of these buttons was in a home brewed tab component, and  I was dynamically changing the button colour via ui-button-primary, ui-button-secondary so that the active tab had a ‘primary’ coloured button and the inactive ones were ‘secondary’ which caused them to become uncoloured ghost buttons – ideal for my requirement.

During refactoring to replace the ‘full size only’ primeNG buttons with the resizing ss-buttons I introduced a bug and the colour change failed to work. The initial (incorrect) refactored code was as follows:-

ss-tab-toolbar.component.html

<ng-container *ngFor="let tab of tabs">
<app-ss-button [label]="tab.label" [icon]="tab.icon" (click)="setActiveTab(tab)"
[ngClass]="{'ui-button-primary': isActiveTab(tab), 'ui-button-secondary': ! isActiveTab(tab)}"></app-ss-button>
</ng-container>

ss-button.component.html

<button pButton type="button" [title]="label" [label]="label" [icon]="icon" class="ss-button icon-text"
[ngClass]="class" ></button>
<button pButton type="button" [title]="label" [icon]="icon" class="ss-button icon-only"
[ngClass]="class" ></button>

ss-button.component.ts

@Component({
selector: 'app-ss-button',
templateUrl: './ss-button.component.html',
styleUrls: ['./ss-button.component.scss']
})
export class SSTabButtonComponent {

@Input() label: string;
@Input() icon: string;
@Input() class: string;

constructor() { }
}

The issue was that I was using [ngClass] dynamically to update the classes on the <app-ss-button> in ss-tab-toolbar.component. html. This used to work for the PrimeNG buttons, but now would have no effect as the classes need to be changed on the child buttons not the encapsulating parent. A simple change of [ngClass] to [class] fixed the problem, as the parent style change then updated the property on the parent component which was then picked up by the children correctly.

modified ss-tab-toolbar.component.html

<ng-container *ngFor="let tab of tabs">
<app-ss-button [label]="tab.label" [icon]="tab.icon" (click)="setActiveTab(tab)"
[class]="{'ui-button-primary': isActiveTab(tab), 'ui-button-secondary': ! isActiveTab(tab)}"></app-ss-button>
</ng-container>

Happily the dynamic nature of angular meant that this worked perfectly for tab changes – the change on the parent class was propagated correctly to the child and the button colours changed correctly.

I was wondering initially whether I would need to involve observables to make this work but this was not the case – this kind of dynamic propagation pattern is worth remembering in future.

No Comments »

May 18th, 2017
6:30 pm
Tricks with the PrimeNG Grid CSS Component

Posted under Angular & CSS & HTML & PrimeNG
Tags ,

Update 19/5/2017

I noticed that my original attempt below, whilst causing the text div to flow under the image div at smaller screen sizes, did not cause the text div to be full width when it was sitting underneath. To do this properly I needed to use a combination of 2 specific non-default (i.e. not ui-g-*) responsive style classes on the text div, in this case ui-md-9 and ui-sm-12. This causes the following:-

  1. At the u-md-* screen size boundary, and higher, the ui-md-9 kicks in and the image and text are on the same line.
  2. Below the ui-md-9 boundary, the ui-sm-12 kicks in and allows the text div to be full width. Without this, it would sit underneath but the default ui-g-9 would still be in effect so it would not switch to full width.

The modified code fragment for the item-text div is as follows:-

<div class="ui-g-9 ui-sm-12 ui-md-9 item-text">

Original Post

I did this quite by accident, due to adding an unwanted “>” on the end of a ui-g-3 class for the div around the left image in a data list – it caused the class to be ignored.

The code (with the offending character and the ui-g-3 class removed) is as follows:-

<ng-template let-place pTemplate="item">
<div class="ui-g list-item item-image">
<div class="item-image">
<img src={{place.thumbUrl}}>
</div>
<div class="ui-g-9 item-text">
<h4>{{place.shortLocation}}</h4>
<h3>{{place.name}}</h3>
<p>{{place.strapline}}</p>
</div>
</div>
</ng-template>

The scss for the component is here (note this is from the component scss file so is encapsulated by Angular from bleeding out):-

h3 {
font-size:1.1em;
font-weight: normal;
margin:.2em 0;
}
h4 {
font-size:1em;
font-weight: normal;
margin: 0;
}
p {
font-size:1em;
margin:.2em 0;
}
.list-item {
padding:.5em;
border-bottom:1px solid #D5D5D5;
display:flex;
align-items: center;
}
.list-item .item-image {
padding-right:1em;
}
.list-item .item-text {
padding-left:0;
}

The happy effect of this was that the image div did not have a ui-g-* class to size it, so had a fixed size determined by the thumbnail, and was not a floating div. When I used a ui-g-3 class for it by removing the offending “>”, then the gap between the image and the text increased as the width changed, which is not something I wanted – the fixed padding there due to the bug was fine for all screen widths.

The ui-g-9 class happily floated next to it and flowed underneath as required. Different ui-g-* classes such as ui-g-6 and ui-g-8 just caused the flow to happen at a different width point.

I could probably have achieved a similar effect by using a ui-g-3 class for the image as I had intended, and then explicitly fixing the width for that div (or e.g. setting a min-width and a max-width).

I may need to do this or re-jig it if I have to cater for different thumbnail sizes, but my preferences is to scale all thumbnails to the same size as it gives a much better layout.

Whether this trick technically breaks or violates the ui-g-* grid css rules I am not sure, the documentation on them is not hugely comprehensive, but I will ponder this one in due course.

For now it works fine!

No Comments »

May 15th, 2017
4:07 pm
Angular–using parent component references

Posted under Angular & TypeScript
Tags ,

I had a need to do this initially when implementing my own tab container component.

I wanted each tab to hold a parent reference to the container so that it could get the container’s active tab, to see if ‘it’ was the active tab.

There is significant discussion about this online. The parent can be injected directly via its class name, but this introduces tight coupling which is undesirable.

Another option discussed was the use of @Host in conjunction with injection, as per the angular docs here. In this case, the traversal of the injector  tree stops at the parent otherwise another compatible component could conceivably be injected from elsewhere.

My solution initially was to define parent and child interfaces which defined the interaction between them, as one would in Java. This decoupled them from each other. However, in Angular you cannot inject interfaces directly as they are not available at runtime. As I was already iterating the content children (the tabs) in the parent container, in the ngAfterContentInit() lifecycle hook (as this is the earliest point at which the content children are available), it was straightforward to manually assign the parent reference to each child via a method in the child interface. In this way the parent and children were decoupled – any parent supporting the container interface (used by the child) could host any children which used the child interface (used by the parent).

In the end I dumped the idea as it ended up a tad unwieldy – I only needed the child to detect if it was the active one and it was having to call a parent method to compare itself with the currently active tab to see if it was the one. This child element property was then used to ensure that only the content of the active tab was actually rendered. I finally just added a boolean active property on the child interface, and in the parent, when switching tabs, I cleared the active flag on the old active tab (if there was one) and set the active flag on the new active tab, as well as assigning a parent property for the currently active tab. Whilst this meant I was having to track the active flags correctly, I no longer had to handle parent references and parent method calls. This seemed less messy but it was a close call and either pattern in reality would be ok.

One point of note is that in Typescript, an interface can contain properties (as in fields in Java) as well as methods, so for example my interface for the child could contain active and default properties directly rather than having to additionally define isActive() and isDefault() methods.

No Comments »

May 15th, 2017
1:46 pm
Angular–dynamic building of parent component markup based on content children

Posted under Angular
Tags ,

I had a use case where I was rolling my own simple tab container.

An interesting challenge of this use case was the fact that the tabs needed rendering in their own right, but also needed iterating separately in order to build the tab header bar.

This is an example use case where content markup might influence parent markup dynamically and in multiple areas, and that attributes of the content markup are used in parent markup.

To do this I used the @ContentChildren decorator to inject an array of the tabs into the parent tab container. I could then easily iterate the array in the parent markup to build the header bar with labels and icons declared in the content children. In addition, the content children were rendered in their own right with their own content in different ways using <ng-content select=”…”></ng-content>.

No Comments »

May 14th, 2017
10:57 am
List of Icons to use with PrimeNG

Posted under Angular & PrimeNG
Tags ,

Prime now use Font Awesome for icons. They do not appear to be listed in the PrimeNG documentation/showcase, but are listed in the PrimeFaces one and may therefore be found here.

No Comments »

May 14th, 2017
10:53 am
Web App container layout– how to fill space to right

Posted under Angular & CSS & PrimeNG
Tags , ,

I was trying to allow a left div for a menu to have a percentage width, possibly with a fixed min-width.

I then wanted to add a right div which filled all the remaining space to the right, to form a content pane.

My initial attempts which failed were:-

1/ Float both divs left – this partly works e.g. if I gave 25% width to the left and 75% width to the right, i.e. I had to assign width. If I then gave a min-width to the left, the right div drops underneath when the min-width kicks in.

2/ Per this post here, I took the float out of the right div. Whilst it extended to fill the right hand space, it also filled the left hand space, and placing e.g. a PrimeNG toolbar in the right hand pane resulted in a mess where the height of the toolbar filled the whole height of both divs. This was all due to the interaction of the floated and non floated div – the non floated one just flowed around the left hand floated div, and its content was in fact also hiding underneath the right one. In fact the comments mention that the proposed solution in the post does not work exactly as I found.

Finally an interesting solution which did work is this post here. The right float is not floated but is set to overflow:hidden. This triggers a Block Formatting Context, which interacts with the float to fill the remaining space. The right div becomes a BFC which prevents sibling floats from intruding on them, and also prevents descendant floats from escaping. The post explains the details on this well.

This worked correctly, even when the min-width was used in conjunction with a percentage width for the left div. A plunker showing a simple example of the BFC may be found here.

In the end I abandoned this approach of rolling my own layout. I was using PrimeNG components, and PrimeNG comes with a Grid CSS layout component which does full responsive 12 column based layout. It is nestable, and adaptable automatically for different screen widths via media queries. It is also used internally for the PrimeNG components, so will play nicely with them and will be less prone to side effects. I note from the comments that Bootstrap responsive column layout does not work well with PrimeNG, so I stuck with PrimeNG as it is flexible and easy to use.

Another alternative for grid layout which is big in this area is Foundation, which is also reviewed and compared with Bootstrap here. Bootstrap may be found here. Both Foundation and Bootstrap are frameworks offering components and css/theming as well as grid layout so would likely fight with Primefaces as this post indicates. It looks like you may be able to just get the grid with Foundation by now, not sure with Bootstrap.

No Comments »

May 11th, 2017
9:42 am
Upgrading angular-cli

Posted under Angular
Tags ,

Instructions as per here:-

Updating Angular CLI

If you’re using Angular CLI beta.28 or less, you need to uninstall angular-cli package. It should be done due to changing of package’s name and scope from angular-cli to @angular/cli:

npm uninstall -g angular-cli
npm uninstall --save-dev angular-cli

To update Angular CLI to a new version, you must update both the global package and your project’s local package.

Global package:

npm uninstall -g @angular/cli
npm cache clean
npm install -g @angular/cli@latest

Local project package:

rm -rf node_modules dist # use rmdir /S/Q node_modules dist in Windows Command Prompt; use rm -r -fo node_modules,dist in Windows PowerShell
npm install --save-dev @angular/cli@latest
npm install

Note that for a primeNg application I also had to reinstall the angular animations module:-

npm install @angular/animations

Failing to do this caused numerous errors on an ng serve due to the inability to reference the animations(!) :-

ERROR in E:/Dev/angular/places-admin/node_modules/@angular/platform-browser/animations/src/animation_renderer.d.ts (1,53):
Cannot find module '@angular/animations/browser'.

ERROR in E:/Dev/angular/places-admin/node_modules/@angular/platform-browser/animations/src/providers.d.ts (8,276):
Cannot find module '@angular/animations/browser'.

ERROR in Error encountered resolving symbol values statically.
Could not resolve @angular/animations/browser relative to
E:/Dev/angular/places-admin/node_modules/@angular/platform-browser/animations/index.d.ts.,
resolving symbol ?e in
E:/Dev/angular/places-admin/node_modules/@angular/platform-browser/animations/index.d.ts,
resolving symbol BrowserAnimationsModule in
E:/Dev/angular/places-admin/node_modules/@angular/platform-browser/animations/index.d.ts,
resolving symbol BrowserAnimationsModule in
E:/Dev/angular/places-admin/node_modules/@angular/platform-browser/animations/index.d.ts

ERROR in ./~/@angular/platform-browser/@angular/platform-browser/animations.es5.js

Module not found: Error:
Can't resolve '@angular/animations/browser' in
'E:\Dev\angular\places-admin\node_modules\@angular\platform-browser\@angular\platform-browser'
@ ./~/@angular/platform-browser/@angular/platform-browser/animations.es5.js 13:0-249
@ ./src/app/app.module.ts
@ ./src/main.ts
@ multi webpack-dev-server/client?
http://localhost:4200 ./src/main.ts

ERROR in ./~/primeng/components/accordion/accordion.js
Module not found: Error:
Can't resolve '@angular/animations' in
'E:\Dev\angular\places-admin\node_modules\primeng\components\accordion'
@ ./~/primeng/components/accordion/accordion.js 13:19-49
@ ./~/primeng/primeng.js
@ ./src/app/app.module.ts
@ ./src/main.ts
@ multi webpack-dev-server/client?
http://localhost:4200 ./src/main.ts

ERROR in ./~/primeng/components/calendar/calendar.js
Module not found: Error:
Can't resolve '@angular/animations' in
'E:\Dev\angular\places-admin\node_modules\primeng\components\calendar'
@ ./~/primeng/components/calendar/calendar.js 13:19-49
@ ./~/primeng/primeng.js
@ ./src/app/app.module.ts
@ ./src/main.ts
@ multi webpack-dev-server/client?
http://localhost:4200 ./src/main.ts

ERROR in ./~/primeng/components/confirmdialog/confirmdialog.js
Module not found: Error:
Can't resolve '@angular/animations' in
'E:\Dev\angular\places-admin\node_modules\primeng\components\confirmdialog'
@ ./~/primeng/components/confirmdialog/confirmdialog.js 13:19-49
@ ./~/primeng/primeng.js
@ ./src/app/app.module.ts
@ ./src/main.ts
@ multi webpack-dev-server/client?
http://localhost:4200 ./src/main.ts

 
It appeared that I did not need to reinstall primeng via npm install primeng –save. In fact although it initially ran without, I did reinstall this too as well as the animations.

No Comments »

May 10th, 2017
1:39 pm
Creating a skeleton Angular 4 / PrimeNG application

Posted under Angular & PrimeNG
Tags ,

Update 30/5/2017

Re the comment below on the stylesheet link tags not being honoured in index.html, it may still be ok to do this when the css is somewhere under the assets folder, as webpack loads these. I hit this on the Learning Tree angular course in an exercise, course 2324 ex 2.1, and moving a css folder from the src level to under the assets folder solved the problem – prior to this I was getting net errors on all the stylesheets (interestingly the exercise was originally set up wrong, which proved useful when diagnosing this issue) . This therefore may still be an alternative in some cases to using angular-cli.json.

Original Post

This is pretty much covered here, but salient points/commands as follows:-

ng new places-admin –style=scss
cd places-admin
npm install primeng –save
npm install @angular/animations
npm install font-awesome –save
ng serve

  • Note the use of –style=scss as the default is plain css.
  • angular animations are used for angular 4
  • font awesome is used and needs to be both installed as above and added as a dependency in package.json along with primeng (this was already done automatically when I looked).
  • Note that you need to import either BrowserAnimationsModule or NoopAnimationsModule in addition to BrowserModule – the post above mentions this but does not actually do it in the sample code:-
import { BrowserModule } from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
...

@NgModule({
declarations: [

],
imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
HttpModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Styles configuration issue

Per the setup instructions above I initially just configured the style sheets with link tags in index.html:-

<link rel="stylesheet" type="text/css" href="/node_modules/primeng/resources/themes/omega/theme.css" />
<link rel="stylesheet" type="text/css" href="/node_modules/primeng/resources/primeng.min.css" />
<link rel="stylesheet" type="text/css" href="YOUR_PATH/font-awesome.min.css" />

 

When I did this alone, the style sheets would not resolve at run time. Per some online post suggestions I tried various alternative path prefixes such as “/node_modules”, “./node_modules”, and “../node_modules” but none would resolve. When I looked in the chrome inspector I was getting 404s on all the style sheet loads. I checked the file system and all the referenced files were present under node_modules, but they were just not available to the web server/were not being served. It appears that this is a consequence of the way that angular-cli and webpack package up the application. I then tried adding the style references specifically to .angular-cli.json as per the instructions :-

"styles": [
  "../node_modules/primeng/resources/primeng.min.css",
  "../node_modules/primeng/resources/themes/omega/theme.css",
  "../node_modules/font-awesome/css/font-awesome.min.css",
  //...
],

This worked and the styles/theming did resolve correctly. In fact, the static link references were not used at all and could be removed.

When examining components which used the css with the Chrome inspector, the css rules were being taken from style blocks directly, so this was clearly a packaging issue.

For dynamic theme switching, it may therefore be necessary to move the themes under the app resources and use a dynamically changed <link> tag or similar to select the target theme – this is the way that the PrimeNG Showcase does its theme switching, and there is no evidence at present of any other theme switcher component.

No Comments »

May 10th, 2017
8:34 am
Angular 2 and Ionic – Builders/ Package Managers/ Bundlers/ Task Runners

Posted under Angular & Ionic
Tags ,

The landscape in this regard is pretty complex with a number of choices out there.

This StackOverflow post discusses the functionality and pros/cons of the alternatives and is helpful in gaining an idea of what they all actually do!

I was keen to pick tools that met my needs, especially re the ability to build apps from separate shared components, but did not want to over complicate things by using tools that I did not really need.

My conclusion from the above and all the comments is that for the moment all my need can be met by just sticking with Webpack (in conjunction with Angular CLI and Ionic CLI), and not venturing to use tools such as Gulp on top as I don’t really need to.

This is good as webpack is the standard for Angular and Ionic.

No Comments »

May 10th, 2017
8:15 am
PrimeNG Theming

Posted under PrimeNG
Tags , ,

Update 12/5/2017

Note that there are issues when trying to use the standard themes loaded by the PrimeNG installation, which reside under node_modules. Basically, the traditional use of the link tag did not work even though the style files were present.  This appears to be an issue relating to how the application is packaged and served.

See this post in the ‘Styles configuration issue’ near the end for details and resolution on this problem.

 

Original Post

This is handled in much the same way as it was in JSF – a directory for each theme holds its scss and css files.

Normally these are bundled in as part of an npm installation of primeng, so the themes end up under node_modules\primeng\resources\themes, but this may differ if you have your own custom themes.

The PrimeNG showcase for example does not use an npm install of primeng, but declares its own primeng package as it contains everything. It therefore puts the themes under resource\themes. See this post for issues with this re getting the showcase to work locally.

The showcase is instructive as a simple example of how to switch themes – at present there does not appear to be a theme switcher/manager component available.

The basic style link tag which picks up a theme is in index.html:-

<link rel="stylesheet" type="text/css" href="resources/themes/omega/theme.css">

The following javascript function modifies this dynamically as themes are selected:-

var DemoApp = {

changeTheme: function(event, element) {
var theme = $(element).data("theme"),
themeLink = $('link[href$="theme.css"]'),
newThemeURL = 'resources/themes/' + theme + '/theme.css';

themeLink.attr('href', newThemeURL);
event.preventDefault();
}
};

The following markup is used for theme selection, based on a hard coded list of the themes available:-

<span class="topbar-link" id="themeSwitcher"
(mouseenter)="themesVisible = true" (mouseleave)="themesVisible = false">
<img src="showcase/resources/images/themeswitcher.svg" />
<span>Themes</span>
<div id="GlobalThemeSwitcher" [style.display]="themesVisible ? 'block' : 'none'" style="margin-top:10px">
<span>Premium Templates</span>
<a href="http://www.primefaces.org/layouts/ultima-ng">
<img src="showcase/resources/images/themeswitcher-ultima.png" alt="Ultima Template">
<span class="ui-text">Ultima</span></a>
<a href="http://www.primefaces.org/layouts/barcelona-ng">
<img src="showcase/resources/images/themeswitcher-barcelona.png" alt="Barcelona Template">
<span class="ui-text">Barcelona</span></a>
<a href="http://www.primefaces.org/layouts/morpheus-ng">
<img src="showcase/resources/images/themeswitcher-morpheus.png" alt="Morpheus Template">
<span class="ui-text">Morpheus</span></a>
<a href="http://www.primefaces.org/layouts/atlantis-ng">
<img src="showcase/resources/images/themeswitcher-atlantis.png" alt="Atlantis Template">
<span class="ui-text">Atlantis</span></a>
<a href="http://www.primefaces.org/layouts/poseidon-ng">
<img src="showcase/resources/images/themeswitcher-poseidon.png" alt="Poseidon Template">
<span class="ui-text">Poseidon</span></a>
<a href="http://www.primefaces.org/layouts/omega-ng">
<img src="showcase/resources/images/themeswitcher-omega.png" alt="Omega Template">
<span class="ui-text">Omega</span></a>
<span>Free Themes</span>
<a href="#" data-theme="omega" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Omega</span></a>
<a href="#" data-theme="bootstrap" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Bootstrap</span></a>
<a href="#" data-theme="cupertino" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Cupertino</span></a>
<a href="#" data-theme="cruze" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Cruze</span></a>
<a href="#" data-theme="darkness" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Darkness</span></a>
<a href="#" data-theme="flick" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Flick</span></a>
<a href="#" data-theme="home" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Home</span></a>
<a href="#" data-theme="kasper" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Kasper</span></a>
<a href="#" data-theme="lightness" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Lightness</span></a>
<a href="#" data-theme="ludvig" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Ludvig</span></a>
<a href="#" data-theme="pepper-grinder" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Pepper-Grinder</span></a>
<a href="#" data-theme="redmond" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Redmond</span></a>
<a href="#" data-theme="rocket" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Rocket</span></a>
<a href="#" data-theme="south-street" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">South-Street</span></a>
<a href="#" data-theme="start" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Start</span></a>
<a href="#" data-theme="trontastic" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Trontastic</span></a>
<a href="#" data-theme="voclain" onclick="DemoApp.changeTheme(event, this)">
<span class="ui-text">Voclain</span></a>
</div>
</span>

No Comments »