Check out our Angular Book Series.

How do I uppercase the first letter of a word with CSS?

I was working on a project, and during a Pull Request review someone had written a TypeScript function to capitalize the first letter of each word. I said "It looks good to me" but one of my colleagues said "Hey, why don't we use CSS for this."

"CSS can do this?" Said Jeffry, blinking surprised.

It can, and it is super simple to do. CSS provides a text-transform property.

Try this text:


<div style="text-transform: capitalize;">the quick brown fox jumped over the lazy dogs</div>

Play with the Sample.

Sometimes I'm more surprised by the simple stuff I don't know than the complicated stuff.

How can you listen for a Browser Event in Angular?

This question recently came up in StackOverflow, and I thought I'd cross post my answer because I think I nailed this one.

The poster wanted to listen for an event in Angular. In the bulk of cases, I would do this in your HTML:


<button (click)="eventHandler($event)">

And this inside your component method:


eventHandler(event){
console.log(event);
}

It is simple, well documented, and Angular already 'wraps' the bulk of events dispatched up from your HTML page.

However, the poster really wanted to access the eventsin TypeScript. This is doable, but becomes a bit more complex.

First, add a #value to the HTML element in your HTML Template:


<button #myButton>

The #MyButton syntax allows you to reference the child in code using the @ViewChild metadata:


@ViewChild('myButton')
myButton: ElementRef;

Then you should be able to call the methods on the native element to access the event:


myButton.nativeElement.keydown();
myButton.nativeElement.keypress();
myButton.nativeElement.keyup();
myButton.nativeElement.blur();

If at all possible, I try to avoid drilling down into the ElementRef like this. I think I did it once when I created a reusable toast style component for a client, but for normal development I stick with the event directives.

Angular 7 is out, learn all about it here!

Angular 7 is out.. Along with it, I updated all the books in the Learn With series.

This is a major update to the book text, because I finally ditched the SystemJS infrastructure I created in the Angular 2 days, in favor of the more popular Angular CLI. The Angular CLI has become a standard Angular dev tool, and the formal Angular docs and samples do not use the SystemJS approach at all anymore.

Get your updated Books here, and use the discount code LaunchDayGiftFromJeffry to get 25% off when you buy straight from us:

I put together a brand new demo of the app that the book teaches you to build if you want a video reminder of what is going on.

Why aren't Styles working with my Angular 6 Build?

I was working on an Angular 6 project that recently ran into a problem. All our styles were messed up when we created a production build. There are a lot of complaints about it here.

There seem to be two solutions that work for us and I'll go over both of them.

Move the Styles

The first solution is to remove all your style imports from the Angular.json. Then add them back into the main styles.scss using @imports. So, my Angular CLI styles looks like this:


"styles": [
"src/styles.scss",
"node_modules/bootstrap/dist/css/bootstrap.css",
"node_modules/@swimlane/ngx-datatable/release/assets/icons.css",
"node_modules/@swimlane/ngx-datatable/release/themes/material.css"
],

Open up the styles.scss and add them as imports:


@import "../node_modules/bootstrap/dist/css/bootstrap.css";
@import "../node_modules/@swimlane/ngx-datatable/release/assets/icons.css";
@import "../node_modules/@swimlane/ngx-datatable/release/themes/material.css";

The styles would now change to this:


"styles": [
"src/styles.scss",
],

This worked. I actually think I like putting the styles in the main styles.scss instead of the Angular.json. I prefer to stay out of the Angular.json as much as possible.

Change Extract CSS Value

The second option, and the one in which we chose to do for this project, was to change the extractCss value from true to false. Inside your Angular.json find the value:


"extractCss":true

You'll find the value at projects.architect.build.configuration.product.extractCss

Change it to:


"extractCss":false

Now open up your package.json and find the build prod command:


"prod":"ng build"

Add the build-optimizer argument:


"prod":"ng build --build-optimizer"

This should address the issue.

When you create a normal build, the styles are minimized into a JavaScript file--styles.js--and then loaded on demand by Angular as needed. When you use extractCSS, the files are combined into a single CSS file instead of being created in a js file. Part of the minimization process seems to be screwing up the order that files are compressed, which of course affects the final CSS and why our styles were not showing up correctly.

This caused a few grumblings among my team about how borked Angular CLI is, but I still enjoy working with it.

How do I sort two ng-material table instances on the same component?

I have been doing some prototype work with the ng-material's table component. The table component is, basically, a DataGrid.

As part of this proof of concept work I put two separate tables inside the same ecomponent. The code worked well enough, but I had trouble getting both tables to sort.

To get a table to sort you need to add a ViewChild reference to the MatSort. In the HTML:


<table mat-table [dataSource]="rowData1" matSort >
</table>

Then you get a reference inside the component code:


@ViewChild(MatSort) sort: MatSort;

And attach the two together:


ngOnInit() {
this.rowData1.sort = this.sort;
}

The my missing magic from last week's post.

There is a problem once you add a second table. First create the two tables:


<table mat-table [dataSource]="rowData1" matSort >
</table>
<table mat-table [dataSource]="rowData2" matSort >
</table>

Then get the ViewChildren:


@ViewChild(MatSort) sort: MatSort;

@ViewChild(MatSort) sort2: MatSort;

This will cause issues, because both variables are pulling the same MatSort value and only the first grid will sort.

The way to solve this is how you mark the table to get the matSort value:


<table mat-table [dataSource]="rowData1" matSort #sort1="matSort">
</table>
<table mat-table [dataSource]="rowData2" matSort #sort2="matSort">
</table>

Now get the ViewChildren references like this:


@ViewChild('sort1') sort: MatSort;

@ViewChild('sort2') sort2: MatSort;

And associate the sort element with the data source:


ngOnInit() {
this.rowData1.sort = this.sort1;
this.rowData2.sort = this.sort2;
}

Now both grids should sort properly.

Why won't my Template Strings work?

As you probably know, I have been doing a lot of work with Angular, TypeScript, ES6, and the surrounding ecosystem. I've started using template strings a bunch.

This was the old way to create a string from many variables:


myNewValue = "http://" + myDomain + myPath + "?value=" + myValue;

It worked but got tedious. ES6 introduced something called template strings. Instead of using all those plus signs to concatenate variables, we can do use a friendly syntax:


myNewValue = `http://${myDomain}${myPath}"?value=${myValue}`;

I've read about this, done a few proof of principle samples, but for the first time I'm actually using this on a project and integrating it with code.

These are the two mistakes I make most common.

Use the Grave Accent

A template string must be enclosed in a grave accent, or backtick. This is the same key you use when formatting inline code in a StackOverflow comment or inside Slack. If you use double quotes or regular single quotes, your string will not be recognized as a template string and the variables will not turned into real actual values.

This works:


`http://${myDomain}${myPath}"?value=${myValue}`

But, this will not:


"http://${myDomain}${myPath}"?value=${myValue}"

Nor will this:


'http://${myDomain}${myPath}"?value=${myValue}'

I picked this one up the hard way after a particularly frustrating debug session wondering why all my unit tests suddenly broke.

Use Curly Brackets, not Parenthesis

The values that you inject in the string must be surrounded by curly brackets, like an object in JavaScript. For some reason my mind wants to use parenthesis, as if calling a function.

This works:


`http://${myDomain}${myPath}"?value=${myValue}`

But, this will fail miserably:


`http://$(myDomain)$(myPath)"?value=$(myValue)`

Despite these two minor roadblocks, I'm finding a lot of value in template strings because the new way of string concatenation is a lot easier to read than the old way.

Five Reasons My ngMaterial Table won't sort!

I've been doing some prototype work with the ngMaterial grid and had a problem where the grid would not sort. Here are a few things to check if this happens to you.

  1. Import the MatSortModule Module: Be sure that your @NgModule definition includes the MatSortModule:


    @NgModule({
    declarations: [
    AppComponent,
    ],
    imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatTableModule,
    MatSortModule,
    ],
    bootstrap: [AppComponent]
    })

    Without this, the sorting will not work.

  2. Specify the matSort header: Be sure to specify the matSort header on your table grid:


    <table mat-table [dataSource]="rowData" matSort class="mat-elevation-z8"
    >

    // rest of the table definition here
    </table>

    Without that you won't be able to click on the headers.

  3. Wrap Your Data Source in a MatTableDataSource: If you do not wrap your own datasource--probably an array--in the MatTableDataSource class you'll have to write your own sorting algorithm to affect your data because it won't work out of the box.


    this.rowData = new MatTableDataSource(myRowDataArray);

    Do this because it makes your life easier.

  4. Tell the data source about your sort: Your MatTableDataSource does not know about the sort by default. Get a ViewChild instance to the sort in your code:


    @ViewChild(MatSort) sort: MatSort;

    And apply that:


    ngOnInit() {
    this.rowData.sort = this.sort;
    }

    Hopefully you got this far and your table is sorting now.

  5. Write Your Own Sort: If you're avoiding using the MatTableDataSource for some reason, you'll have to write your own sort algorithm. In the HTML, listen for the matSortChange event:


    <table mat-table [dataSource]="rowData" matSort class="mat-elevation-z8" (matSortChange)="onMatSortChange()">
    // rest of the table definition here
    </table>

    And in your code:


    onMatSortChange(){
    // do something to modify your data source here.
    }

I've found the documentation lacking for ngMaterial, but so far we plan on plunging ahead with it. Hopefully this helped someone out.

How does the HTML5 Pattern Attribute work?

I came across a question on StackOverflow about how to use Angular to restrict input to capital letters. Back in my Flex days, I'd use the restrict attribute for that, but I've never had to do that for HTML5.

I did some digging and found that HTML5 introduced a pattern attribute. I thought this is probably exactly what is needed and Angular doesn't need to get involved at all.

I threw together a quick sample.


<input type="text" pattern="[A-Z]*" name="sampleinput" />

Unfortunately, that wasn't nearly as helpful as I thought it might be. It does not restrict input, only gives guidance. In Firefox, it will turn red if you enter invalid characters:

If we change to all caps, the Firefox red warning goes away. A nice visual queue, but it does not restrict the input like I wanted.

Chrome on the other hand provides no feedback:

I didn't continue testing in different browsers, but I imagine there is similar inconsistencies.

You can control the error message, but using the title attribute, and even write your own code against an invalid event.

As best I can tell, there is no HTML5 way to restrict the input into a text field. But, after some searching, I found a few ways to do this with Angular, most involve adding a validator on the input.

You can also use CSS to force the text to uppercase:


<input type="text" style="text-transform: uppercase;" name="sampleinput" />

However, that won't prevent the user from entering numbers.

Learning Redux - Using CombineReducers() - Part 6

This is the sixth and final part in a series on Redux, a state Management Framework used with single page application frameworks such as React and Angular. This series looks at using Redux without another framework. Please read part 1, Part 2. and Part 3, and part 4, and part 5 before reading this.

I write a lot more about Redux and Angular in the bonus book to the Angular 6 series.

In the previous sample we split up the reducer and manually called our sub reducer functions. Our reducer function was this:


function reducer(state = initialState, action) {
return {
helloUser: helloUser(state.helloUser, action),
goodbyeUser: goodbyeUser(state.goodbyeUser, action)
}
}

Redux provides a short hand to make that happen in the form of a combineReducers() function. Replace the reducer with this:


reducer = Redux.combineReducers({
helloUser,
goodbyeUser
})

Redux will automatically know how to combine these reducers. Try the app again, and you'll find that it works.

Try the app again.

I hope you enjoyed my series on Redux. Be sure to check out the full book series for an in depth explanation of how Redux and Angular can work together.

Learning Redux - Using Multiple Reducer Functions - Part 5

This is the fifth part in a series on Redux, a state Management Framework used with single page application frameworks such as React and Angular. This series looks at using Redux without another framework. Please read part 1, Part 2. and Part 3, and part 4 before reading this.

I write a lot more about Redux and Angular in the bonus book to the Angular 6 series.

Review the Reducer

This is the reducer we had in the previous samples:


function reducer(state = initialState, action) {
var newState = Object.assign({}, state)

switch (action.type) {
case 'NAME_MODIFIED':
newState.helloUser = action.value
break;
case 'NAME_LEFT':
newState.goodbyeUser = action.value;
newState.helloUser = '';
break;
default:
// do nothing
}
return newState;
}

It is functional, but over time as your application grows will become unwieldy. Each aspect of state is better handled separately with it's own actions and state modifications. To do that, we separate a single reducer into multiple reducers.

Split the Reducer

This example expands on the previous example, to show you how to split a single reducer into multiple reducers.

State objects and Reducers can get very complex in a real-world application. What do we do to make them simpler? What we're going to do is create a reducer for each section of the site and then combine them into our one big reducer function.

Let's start by creating a reducer for the hello portion of this app:


function helloUser(state = '', action){
var newState = state;
switch (action.type) {
case 'NAME_MODIFIED':
newState = action.value;
break;
case 'NAME_LEFT':
newState = '';
break;
default:
}
return newState
}

I created a new function named helloUser(). Notice that this function is named the same name as the state property. This is done on purpose, and you'll find out why in the next article. This function has a similar signature to the reducer. It accepts a state and an action. However, it does not accept the full state object. We'll send in the specific value for the helloUser state, which is just one branch of the main state object. This reducer function only focuses on handling its own state, not other states.

The helloUser() reducer only operates on the helloUser state variable. Notice it defaults the newState to an empty string in the command line signature. We might do something more complex if we were using an object or other data type. This reducer has to handle both major actions. If the name is modified, it sets to the new name. If we said goodbye to the user, then the helloUser resets to an empty string.

Create a goodbyeUser() reducer:


function goodbyeUser(state = '', action){
var newState = state;
switch (action.type) {
case 'NAME_LEFT':
newState = action.value;
break;
default:

}
return newState
}

This reducer only needs to operate on the goodbyUser state. As with the helloUser reducer, and as such only needs to respond to the NAME_LEFT action. In that case, it takes the value from the action and sets it to the new state. The NAME_MODIFIED state is ignored here.

Now, create the actual reducer:


function reducer(state = initialState, action) {
return {
helloUser: helloUser(state.helloUser, action),
goodbyeUser: goodbyeUser(state.goodbyeUser, action)
}
}

This automatically returns an object, representing the new state. The helloUser property is given the results of the helloUser() reducer. The goodbyeUser property is given the results of the goodbyeUser() reducer.

Run the app and you'll see it working.

More Entries

All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.