Check out our Angular Book Series.

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.

How do I send JSON to a Server in Angular 2+?

I have a lot more trouble answering Angular questions on StackOverflow than I did answering Flex questions. The bulk of Angular problems seem to come from integrating different systems and libraries together. But, every once in a while I see a question that I seem to be the perfect person to answer. This question is about Sending JSON from Angular to PHP. I wrote a book about that.

When sending JSON to PHP--or Java or ColdFusion or any server side tech--you need to be sure to set the headers to application/json.

If you are using Angular 2, this is how you do it:

let optionHeaders : Headers = new Headers();
optionHeaders.append('Content-Type', 'application/json');
let options: RequestOptions = new RequestOptions({headers:optionHeaders});
this.http.post(serverEndPoint, JSONPayload,options);

We create an instance of a RequestOptions object, and add the Headers onto it. The RequestOptions object is sent as part of your server request, in this case using a post() method. This is all part of the now deprecated Http library.

Angular 5 introduced the new HttpClient library, which does things a bit differently:

let options : Object;
let optionHeaders : HttpHeaders = new HttpHeaders().set('Content-Type', 'application/json');
options = {headers:optionHeaders};
this.http.post(serverEndPoint, JSONPayload,options);

You create a generic options object, and add an HttpHeaders() instance inside of it. Send that as the options argument to the http method, also a post().

Debug an Angular Application with a Chrome Plugin

I just discovered Augary, a Chrome Plugin for debugging angular applications. I can't believe I never came across this before.

Install Augary and then an Augary tab will appear as part of the Chrome Debugger tools. Here it is for the Learn With application:

Instead of trying to unravel the application through compiled source files and some guesses, Augaray models out the application for you and allows you drill into services, components, and routes to give you a deeper understanding of what is going on in your Angular application.

I've been playing around with it and it is pretty awesome.

How to specify the CSS extension when generating a Component with Angular CLI 6?

I created a brand new Angular CLI 6 project:


ng new foo --style=scss

I wrote about this in another blog post.

Now generate a component:


ng generate component myComp/display

As expected, the new component is generated using SCSS:

That's good. But, what if you want to use something other than the project settings, like creating a normal CSS file as part of your new component or using the styleext command line argument:


ng generate component myComp/otherdisplay --styleext=css

Now look at the generated files:

It changed the SCSS files from the first command to CSS Files in the second command. In case you are experimenting with different preprocessors for whatever reason, this has you covered.

How do I modify an existing Angular6 Project to use SASS?

If you haven't done so already, you may want to read last week's post about generating an Angular 6 project to use SASS instead of regular CSS files. There is a ton of documentation out there on how to do this for Angular 5 or before and they direct you to use ng set to modify the Angular config file. None of that works for Angular 6, because the

get/set have been deprecated in favor of the config command.

I had two problems. First, I found the documentation on how to use the config command a bit lacking. Second, you already have to know the properties you want to change before you can use the command.

Create a new project that is set to use SCSS and you'll find something like this:


"projects": {
"myAppSetToUseCSS ": {
"schematics": {
"@schematics/angular:component": {
"styleext": "scss"
}
},
....

This is what we want to create in our SASS-free project. Here is the command to add it to a new project:


ng config projects.myAppNotSetToUseCSS.schematics.@schematics/angular:component.styleext scss

You won't get a command line response, but your angular.json will not be updated.

If you want to CSS files that were already modified, you'll have to change them on your file system--and any code that references them such as a @component metadata. Be sure to open up the angular.json file and change the other defaults:


"projects": {
"myAppNotSetToUseCSS": {
"architect": {
"build": {
"styles": [
"src/styles.scss"
],
"test": {
"options": {
"styles": [
"src/styles.scss"
],
....

Those are the only two references to the default styles folder for the main project, but be sure to do a file search through your Angular.json file just to make sure.

How to set up an Angular 6 Project to use SASS?

I've been doing some architecture work on a new project, and setting up the project infrastructure using Angular 6 CLI. Without thinking I created a project normally.


ng new foo

You'll see something like this:

Notice that the CSS Files generated have the CSS extension. That's not what I wanted, SASS files have the scss extension. To tell Angular CLI how to create a project using SCSS files, you need to specify the style command like attribute:


ng new bar --style=scss

Now look:

The files are properly updated. Next week, I'll show you how to update a project that was already generated to make it use SCSS by default.

My Angular 6 Books are Out

Aside from being swamped with client work, I've just updated the Learn With series for Angular 6.

This is a relatively minor update as there were not a lot of changes between Angular 5 and 6, but if you want to find out the information on the latest version that is the best way to get it.

Right now I'm working on a series of longer articles about using Redux and Angular. They should be out soon.

What are Route Guards in Angular?

When you build an Angular application, you're probably going to use a router. The router is a library that allows you to change the URL of the application, and with that URL change to load new components. How do you protect parts of your application from being accessed by users who are not authorized? You use a Route Guard.

What is a Route Guard?

A Route Guard is code that Angular will execute when processing the route. I have been using one to determine whether a user should have access to the route or not. However, they can be used for any purpose. There are a handful of different hooks that can be used:

  • CanActivate to mediate navigation to a route. This is the one I'll demonstrate today.
  • CanActivateChild to mediate navigation to a child route.
  • CanDeactivate to mediate navigation away from the current route.
  • Resolve to perform route data retrieval before route activation.
  • CanLoad to mediate navigation to a feature module loaded asynchronously.

That list is copied from the documentation, because I don't think a lot of elaboration is needed.

Using CanActivate

I'm going to use modified code from my latest book on Angular 6, which you should get if you want a beginner's introduction to Angular.

The first step is to create a Service:


import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';

@Injectable()
export class AuthGuard implements CanActivate {
constructor() {}
canActivate() {
return userHasLoggedIn
}
}

The guard is marked as Injectable and implements the CanActivate method. I greatly simplified the algorithm for determining whether a user has logged in or not, but it can be as complex as you need it. I'm just returning a Boolean value. If the user has logged in--via the userHasLoggedIn value, then the user can activate this route and the canActviate() method returns true. If the user has not logged in, then canActivate() returns false and Angular will know now to load the route.

Since this is a service, load it in your module. In the LearnWith books, I set up a module strictly for routing purposes, so it looks something like this:


import {AuthGuard} from "./auth-guard.service";
@NgModule({
imports: [ RouterModule.forRoot(ROUTES) ],
exports: [ RouterModule ],
providers: [AuthGuard],
})

A constant named ROUTES defines the application's roots:


const ROUTES : Routes = [
{ path: 'login', component: LoginComponent },
{ path: 'GotIn', component: MainApplicationComponent, canActivate: [AuthGuard] },
];

The object which defines the router has a canActivate property and uses the AuthGuard class as it's value. So, when the user purposely tries to load the GotIn route, the canActivate() method inside the AuthGuard class will execute and determine whether the user can view this route based on their logged in status.

Route Guards a powerful and something to learn if you care about the security if your application.

Be sure to pick up my full book series on Angular 6.

Using Angular, RXJS, and SystemJS

just updated DotComIt's build scripts for building Angular 6 applications. I wrote these before the AngularCLI was king of the heap and keep these around because I haven't had time to update my LearnWith series, which contains an introduction to Angular.

Anyway, I copied my Angular5 scripts, updated the package.json to a bunch of new versions, build the sample app, and then started getting errors from the application:


Error: Unexpected token <
Evaluating http://local10.dciseed.dot-com-it.com/Angular6TypeScript/build/js/rxjs

My local dev server has directory browsing turned on, so instead of loading the actual files behind rxjs it was trying to load the directory listing. That won't work. I also saw this error in my experimentation, which said that '"rxjs/operators" not found'. Supposedly that issue was fixed long before RXJS 6.0.0, but alas I was still seeing it.

The solution was to list all the rxjs directories as a package inside of SystemJS Config:


packages: {
'rxjs/ajax': {main: 'index.js', defaultExtension: 'js' },
'rxjs/operators': {main: 'index.js', defaultExtension: 'js' },
'rxjs/testing': {main: 'index.js', defaultExtension: 'js' },
'rxjs/websocket': {main: 'index.js', defaultExtension: 'js' },
rxjs: { main: 'index.js', defaultExtension: 'js' }
}

It took me a while to find this solution, and even then I couldn't get it to work until I removed the quotes around the last package definition.

Weird stuff,

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.